this值&&this上下文&&此法作用域

this值

在ECMAScript的规范中对this的定义为:this是一个特殊的对象,与执行期上下文相关,因此可以称之为上下文对象。this是执行期上下文对象的一个属性。
由于this是执行期上下文对象的属性,因此在代码中使用this,其值直接从上下文对戏那个中获得,而无需查找作用域链,其值在进入上下文的那个时刻被确定

在全局上下文中,this是全局对象本身:

1
2
3
4
var attribute = "attribute";  

console.log(attribute);
console.log(this.attribute);

最后结果:attribute attribute
而在函数上下文中,不同的调用方式可以有不同的值。

this上下文

this值是执行期上下文对象的一个属性(执行期上下文对象包括变量对象,作用域链以及this)。执行期上下文对象有三类,当进入不同的上下文时,this的值会确定下来,并且this的值不能更改。结合前面小节讨论的内容,在执行全局代码时,控制流会进入全局执行期上下文,而在执行函数时,又会有函数执行期上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var global = this;  
var tom = {
name : "Tom",
home : "desine",
getInfo : function(){
print(this.name + ", from "+this.home);
}
};

tom.getInfo();

var jerry = {
name : "Jerry",
getInfo : tom.getInfo
}

jerry.getInfo();

global.getInfo = tom.getInfo;
global.getInfo();

最后结果为:
Tom, from desine
Jerry, from undefined
undefined, from undefined

tom对象本身具有name和home属性,因此在执行tom.getInfo时,会打印tom对象上的这两个属性值。当将global.getInfo属性设置为tom.getInfo时,getInfo中的this值,在运行时,事实上是global对象(还记得在全局执行期上下文对象中,global的变量对象的this值吗?)的变量对象中的this就是自身。而global.name和global.home都没有定义,因此会得到上边的结果。

从上例中还可以看到,在函数getInfo调用时,在getInfo之前的对象(tom,jerry,global)会被作为this来执行。当然global可以省略,这时仍然是全局对象作为this。应该记住的是,this的值取决于调用函数的方式(当然这里的this指函数上下文中的this,全局上下文的我们已经讨论过了)。

词法作用域

在JavaScript中,函数对象的创建和函数本身的执行是完全不同的两个过程:
函数创建过程:

1
2
3
4
function func(){  
var x = 0;
print("function func");
}

函数执行过程:func()
所谓词法作用域(静态作用域)是指,在函数对象的创建时,作用域”[[scope]]”就已经建立,而并非到执行时,因为函数创建后可能永远不会被执行,但是作用域是始终存在的。

比如在上例中,如果在程序中使用没有调用func(),那么,func对象仍旧是存在的,在内存的结构可能是这样的:

1
func.["[[scope]]"] = global.["variable object"];

而当函数执行时,进入函数执行期上下文,函数的活动对象被创建,此时的作用域链是活动对象和”[[scope]]”属性的合成。