3 深入解析.第三章.this

介绍
在这篇文章里,我们将讨论跟执行上下文直接相关的更多细节。讨论的主题就是this关键字。
实践证明,这个主题很难,在不同执行上下文中确定this的值经常会发生问题。
许多程序员习惯的认为,在程序语言中,this关键字与面向对象程序开发紧密相关,其完全指向由构造器新创建的对象。在ECMAScript规范中也是这样实现的,但正如我们将看到那样,在ECMAScript中,this并不限于只用来指向新创建的对象。
下面让我们更详细的了解一下,在ECMAScript中this的值到底是什么?
定义
this是执行上下文中的一个属性:

复制代码 代码如下:


activeExecutionContext = {
VO: {...},
this: thisValue
};


这里VO是我们前一章讨论的变量对象。
this与上下文中可执行代码(的类型)直接相关。this的值在进入上下文时确定,并且在上下文运行代码期间不会改变this的值。
下面让我们更详细研究这些场景。
this在全局代码中的值
在这里一切都很简单。在全局代码中,this始终是全局对象本身,这样就有可能间接的引用到它了。

复制代码 代码如下:


// explicit property definition of
// the global object
this.a = 10; // global.a = 10
alert(a); // 10
// implicit definition via assigning
// to unqualified identifier
b = 20;
alert(this.b); // 20
// also implicit via variable declaration
// because variable object of the global context
// is the global object itself
var c = 30;
alert(this.c); // 30


this在函数代码中的值
在函数代码中使用this时很有趣,这种应用场景很难且会导致很多问题。
在这种类型的代码中,this值的首要(也许是最主要的)特点是它没有静态绑定到一个函数。
正如我们上面曾提到的那样,this的值在进入上下文时确定,在函数代码中,this的值每一次(进入上下文时)可能完全不同。
不管怎样,在代码运行期间,this的值是不变的,也就是说,因为this不是一个变量,所以不可能为其分配一个新值。(相反,在Python编程语言中,它明确的定义为对象本身,在运行期间可以不断改变)。

复制代码 代码如下:


var foo = {x: 10};
var bar = {
x: 20,
test: function () {
alert(this === bar); // true
alert(this.x); // 20
this = foo; // error
alert(this.x); // if there wasn't an error then 20, not 10
}
};
// on entering the context this value is
// determined as "bar" object; why so - will
// be discussed below in detail
bar.test(); // true, 20
foo.test = bar.test;
// however here this value will now refer
// to "foo" – even though we're calling the same function
foo.test(); // false, 10


那么,在函数代码中,什么影响了this的值发生变化?有几个因素。
首先,在通常的函数调用中,this是由激活上下文代码的调用者来提供的,即调用函数的父上下文(parent context)。this取决于调用函数的方式。(译者注:参考这里)
为了在任何情况下准确无误的确定this值,有必要理解和记住这重要的一点:正是调用函数的方式影响了调用的上下文中this的值,没有别的什么(我们可以在一些文章,甚至是在关于javascript的书籍中看到,它们声称:“this的值取决于函数如何定义,如果它是全局函数,this设置为全局对象,如果函数是一个对象的方法,this将总是指向这个对象。–这绝对不正确”)。继续我们的话题,可以看到,即使是正常的全局函数也会因为不同调用方式而激活,这些不同调用方式产生了this不同的值。

复制代码 代码如下:


function foo() {
alert(this);
}
foo(); // global
alert(foo === foo.prototype.constructor); // true
// but with another form of the call expression
// of the same function, this value is different
foo.prototype.constructor(); // foo.prototype


有时可能将函数作为某些对象的一个方法来调用,此时this的值不会设置为这个对象。

复制代码 代码如下:


var foo = {
bar: function () {
alert(this);
alert(this === foo);
}
};
foo.bar(); // foo, true
var exampleFunc = foo.bar;
alert(exampleFunc === foo.bar); // true
// again with another form of the call expression
// of the same function, we have different this value
exampleFunc(); // global, false


那么,到底调用函数的方式如何影响this的值?为了充分理解this的值是如何确定的,我们需要详细分析一个内部类型(internal type)——引用类型(Reference type)。
引用类型
用伪代码可以把引用类型表示为拥有两个属性的对象——base(即拥有属性的那个对象),和base中的propertyName 。

复制代码 代码如下:

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

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