Javascript this 的一些学习总结(2)


// Reference type.
var fooReference = {
base: global,
propertyName: 'foo'
};

var sayReference = {
base: global,
propertyName: 'say'
};


我们知道Javascript中属性访问有两种方式:点符号和中括号符号:

复制代码 代码如下:


// Invokes the say method.
foo.say();
foo['say']();


由于say()方法是标识符,所以它对应于foo对象引用类型如下:

复制代码 代码如下:


// Reference type.
var fooSayReference = {
base: foo,
propertyName: 'say'
};


我们发现say()方法的base属性值为foo对象,那么它对应的this属性也将指向foo对象。

假设,我们直接调用say()方法,它对应的引用类型如下:

复制代码 代码如下:


// Reference type.
var sayReference = {
base: global,
propertyName: 'say'
};


由于say()方法的base属性值为global(通常来说是window object),那么它对应的this属性也将指向global。

函数上下文中this的值是函数调用者提供并且由当前调用表达式的形式而定的。如果在调用括号()的左边有引用类型的值,那么this的值就会设置为该引用类型值的base对象。 所有其他情况下(非引用类型),this的值总是null。然而,由于null对于this来说没有任何意义,因此会隐式转换为全局对象。

函数调用以及非引用类型
前面我们提到,当调用括号左侧为非引用类型的时,this的值会设置为null,并最终隐式转换为全局对象。

现在我们定义了一个匿名自执行函数,具体实现如下:

复制代码 代码如下:


// Declares anonymous function
(function () {
alert(this); // null => global
})();


由于括号()左边的匿名函数是非引用类型对象(它既不是标识符也不属于属性访问),因此,this的值设置为全局对象。

复制代码 代码如下:


// Declares object.
var foo = {
bar: function () {
alert(this);
}
};

(foo.bar)(); // foo.
(foo.bar = foo.bar)(); // global?
(false || foo.bar)(); // global?
(foo.bar, foo.bar)(); // global


这里注意到四个表达式中,只有第一个表达式this是指向foo对象的,而其他三个表达式则执行global。

现在我们又有疑问了:为什么属性访问,但是最终this的值不是引用类型对象而是全局对象呢?

我们注意到表达式二是赋值(assignment operator),与表达式一组操作符不同的是,它会触发调用GetValue方法(参见11.13.1中的第三步)。 最后返回的时候就是一个函数对象了(而不是引用类型的值了),这就意味着this的值会设置为null,最终会变成全局对象。

第三和第四种情况也是类似的——逗号操作符和OR逻辑表达式都会触发调用GetValue方法,于是相应地就会丢失原先的引用类型值,变成了函数类型,this的值就变成了全局对象了。

引用类型以及this的null值
对于前面提及的情形,还有例外的情况,当调用表达式左侧是引用类型的值,但是this的值却是null,最终变为全局对象(global object)。 发生这种情况的条件是当引用类型值的base对象恰好为活跃对象(activation object)。

当内部子函数在父函数中被调用的时候就会发生这种情况,通过下面的示意代码介绍活跃对象:

复制代码 代码如下:


// Declares foo function.
function foo() {
function bar() {
alert(this); // global
}
// The same as AO.bar().
bar();
}


由于活跃对象(activation object)总是会返回this值为——null(用伪代码来表示AO.bar()就相当于null.bar()),然后,this的值最终会由null转变为全局对象。

当函数调用包含在with语句的代码块中,并且with对象包含一个函数属性的时候,就会出现例外的情况。with语句会将该对象添加到作用域链的最前面,在活跃对象的之前。 相应地,在引用类型的值(标识符或者属性访问)的情况下,base对象就不再是活跃对象了,而是with语句的对象。另外,值得一提的是,它不仅仅只针对内部函数,全局函数也是如此, 原因就是with对象掩盖了作用域链中更高层的对象(全局对象或者活跃对象):

函数作为构造器被调用时this的值
函数作为构造函数时,我们通过new操作符创建实例对象是,它会调用Foo()函数的内部[[Construct]]方法;在对象创建之后,会调用内部的[[Call]]方法,然后所有Foo()函数中this的值会设置为新创建的对象。

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wddpyd.html