前面两篇文章介绍了JavaScript执行上下文中两个重要属性:VO/AO和scope chain。本文就来看看执行上下文中的this。
首先看看下面两个对this的概括:
- this是执行上下文(Execution Context)的一个重要属性,是一个与执行上下文相关的特殊对象。因此,它可以叫作上下文对象(也就是用来指明执行上下文是在哪个上下文中被触发的对象)。
- this不是变量对象(Variable Object)的一个属性,所以跟变量不同,this从不会参与到标识符解析过程。也就是说,在代码中当访问this的时候,它的值是直接从执行上下文中获取的,并不需要任何作用域链查找。this的值只在进入上下文的时候进行一次确定。
关于this最困惑的应该是,同一个函数,当在不同的上下文进行调用的时候,this的值就可能会不同。也就是说,this的值是通过函数调用表达式(也就是函数被调用的方式)的caller所提供的。
下面就看看在不同场景中,this的值。
全局上下文
在全局上下文(Global Context)中,this总是global object,在浏览器中就是window对象。
1 2 3 4 5 6 7 8 9 10 |
console.log(this === window); this.name = "Will"; this.age = 28; this.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); }; window.getInfo(); // true // Will is 28 years old |
函数上下文
在一个函数中,this的情况就比较多了,this的值直接受函数调用方式的影响。
Invoke function as Function
当通过正常的方式调用一个函数的时候,this的值就会被设置为global object(浏览器中的window对象)。
但是,当使用”strict mode”执行下面代码的时候,this就会被设置为”undefined”。
1 2 3 4 5 6 7 8 |
function gFunc(){ return this; } console.log(gFunc()); console.log(this === window.gFunc()); // window // true |
Invoke function as Method
当函数作为一个对象方法来执行的时候,this的值就是该方法所属的对象。
在下面的例子中,创建了一个obj对象,并设置name属性的值为”obj”。所以但调用该对象的func方法的时候,方法中的this就表示obj这个对象。
1 2 3 4 5 6 7 8 9 |
var obj = { name: "obj", func: function () { console.log(this + ":" + this.name); } }; obj.func(); // [object Object]:obj |
为了验证”方法中的this代表方法所属的对象”这句话,再看下面一个例子。
在对象obj中,创建了一个内嵌对象nestedObj,当调用内嵌对象的方法的时候,方法中的this就代表nestedObj。
1 2 3 4 5 6 7 8 9 10 11 12 |
var obj = { name: "obj", nestedObj: { name:"nestedObj", func: function () { console.log(this + ":" + this.name); } } } obj.nestedObj.func(); // [object Object]:nestedObj |
对于上面例子中的方法,通常称为绑定方法,也就是说这些方法都是个特定的对象关联的。
但是,当我们进行下面操作的时候,temp将是一个全局作用里面的函数,并没有绑定到obj对象上。所以,temp中的this表示的是window对象。
1 2 3 4 5 6 7 8 9 10 11 |
var name = "Will"; var obj = { name: "obj", func: function () { console.log(this + ":" + this.name); } }; temp = obj.func; temp(); // [object Window]:Will |
Invoke function as Constructor
在JavaScript中,函数可以作为构造器来直接创建对象,在这种情况下,this就代表了新建的对象。