发表于: 2019-10-13 22:29:48

1 690


今天完成的事情:

巩固下昨天的增加功能帮助师弟搭建好懒加载
明天计划的事情:

修改和删除功能
遇到的问题:


收获:

了解下课堂THIS指向是什么

在javaScript中,this是动态绑定的,它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。 这就导致了this具备了多重含义,可以使得this可以更灵活地使用。 但是,带来了灵活性的同时也会给我们初学者带来不少困惑。 简而言之, this 是一个特殊的标识符关键字 —— 在每个 function 中自动根据作用域(scope) 确定, 指向的是此次调用的 “所有者,owner”。

this指向在函数定义的时候是确定不了的,只有函数被调用的时候才能够确定,实际上this的最终指向的是那个调用它的对象。

ECMASCRIPT 的类型分为语言类型和规范类型。
  • ECMAScript 语言类型是开发者直接使用 ECMAScript 可以操作的。其实就是我们常说的Undefined, Null, Boolean, String, Number, 和 Object。
  • ECMAScript 规范中还有一种只存在于规范中的类型,它们的作用是用来描述语言底层行为逻辑。
其中重点是便是规范类型中的 Reference 类型。它与 this 的指向有着密切的关联。

这里的 Reference 是一个 Specification Type,也就是 “只存在于规范里的抽象类型”。它们是为了更好地描述语言的底层行为逻辑才存在的,但并不存在于实际的 js 代码中。
REFERENCE 的构成,由三个组成部分,分别是:

  • base value
  • referenced name
  • strict reference

base value 就是属性所在的对象或者就是 EnvironmentRecord,它的值只可能是 undefined, an Object, a Boolean, a String, a Number, or an environment record 其中的一种。

referenced name 就是属性的名称。
举个例子:

  var foo = 1;// 对应的Reference是:
  var fooReference = {
         base: EnvironmentRecord,
         name: 'foo',
         strict: false
    };

而且规范中还提供了获取 REFERENCE 组成部分的方法,比如 GETBASE 和 ISPROPERTYREFERENCE。

  • GetBase(reference),返回的是reference的值
  • IsPropertyReference(reference),如果 base value 是一个对象,就返回true。
  • GetValue,GetValue 返回对象属性真正的值,但是要注意:调用 GetValue,返回的将是具体的值,而不再是一个 Reference

当函数调用时,如何确定THIS的值?

1.计算MemberExpression的结果赋给ref
2.判断ref是不是一个Reference类型
a.如果ref是Reference,并且ref的base value是一个对象,那么 this 的值为 base value
如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)即为undefind
b.如果 ref 不是 Reference,那么 this 的值为 undefined
举个例子:

                    function foo() {
                       console.log(this)
                    }
                    foo(); // MemberExpression 是 foo
                    function foo() {
                       return function() {
                       console.log(this)
                      }
                    }
                    foo()(); // MemberExpression 是 foo()
                    var foo = {
                       bar: function () {
                       return this;
                       }
                    }
                    foo.bar(); // MemberExpression 是 foo.bar

所以简单理解 MemberExpression 其实就是()左边的部分。

2.判断 ref 是不是一个 Reference 类型。 关键就在于看规范是如何处理各种 MemberExpression,返回的结果是不是一个Reference类型。 举最后一个例子:

                    var value = 1;
                    var foo = {
                      value: 2,
                      bar: function () {
                        return this.value;
                      }
                    }
                    //示例1
                    console.log(foo.bar());
                    //示例2
                    console.log((foo.bar)());
                    //示例3
                    console.log((foo.bar = foo.bar)());
                    //示例4
                    console.log((false || foo.bar)());
                    //示例5
                    console.log((foo.bar, foo.bar)());

foo.bar()在示例 1 中,MemberExpression 计算的结果是 foo.bar,那么 foo.bar 是不是一个 Reference 呢? 查看规范 11.2.1 Property Accessors,这里展示了一个计算的过程,什么都不管了,就看最后一步:

Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

我们得知该表达式返回了一个 Reference 类型!根据之前的内容,我们知道该值为:

                    var Reference = {
                      base: foo,
                      name: 'bar',
                      strict: false
                    };

接下来按照 2.1 的判断流程走:该值是 Reference 类型,然后执行IsPropertyReference(ref),如果ref的base value是一个对象则返回true,那么 this 的值为 base value 即这个foo

实例3,4,5中,MemberExpression计算结果分别为(foo.bar=foo.bar),(false||foo.var),(f00,bar,foo,bar)

根据规范,逗号操作符,逻辑或操作符和赋值操作符都会执行:

3.Let rval be GetValue(ref).

因为使用了 GetValue,所以返回的不是 Reference 类型,this 为 undefined

this 为 undefined,非严格模式下,this 的值为 undefined 的时候,其值会被隐式转换为全局对象。
结果:

                    var value = 1;

                    var foo = {
                      value: 2,
                      bar: function () {
                        return this.value;
                      }
                    }

                    //示例1
                    console.log(foo.bar()); // 2
                    //示例2
                    console.log((foo.bar)()); // 2
                    //示例3
                    console.log((foo.bar = foo.bar)()); // 1
                    //示例4
                    console.log((false || foo.bar)()); // 1
                    //示例5
                    console.log((foo.bar, foo.bar)()); // 1

因此这些this都指向了全局对象




返回列表 返回列表
评论

    分享到