下面的两种写法,结果有何不同?
虽然obj.foo和foo指向同一个函数,但是执行结果可能不同。例如
产生这种差异的原因,在于函数内部使用了this关键字。根据书面解释这种情况:this指的是函数运行时的环境。也就是对于obj.foo()来说,foo运行在obj环境;foo运行在全局环境,所以两者运行结果不一样。
思考
- 函数的运行环境到底怎么决定?
- var foo = obj.foo 为什么赋值后foo就成了全局执行环境?
内存的数据结构
var obj = { foo : 5 };
上面的代码将一个对象赋值给变量obj。JavaScript会先内存里面生成一个对象{foo:5},然后再把内存地址赋值给变量obj。也就是obj是一个地址。
对象的的每一个属性,实际是以字典结构的形式保存的,类似下图,
对象的每个属性都包含描述属性。其中value属性保存对应的值。
思考
如果属性的值是函数或者其他引用类型。描述属性中的value应该是什么,例如
var obj = { foo : function(){} }
这时,JavaScript引擎会把函数单独保存在内存中,然后把地址赋值给value属性
由于函数是一个单独的值,所以可以在不同的环境(上下文)中执行。
环境变量
JavaScript允许在函数体内部引用当前环境的其他变量,如
var f = function () {
console.log(x);
};
上面代码中,函数体里面使用了变量x。该变量由运行环境提供。
现在问题就来了,由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。
var f = function () {
console.log(this.x);
}
上面代码中,函数体里面的this.x就是指当前运行环境的x。
var f = function () {
console.log(this.x);
}
var x = 1;
var obj = {
f: f,
x: 2,
};
// 单独执行
f() // 1
// obj 环境执行
obj.f() // 2
上面代码中,函数f在全局环境执行,this.x指向全局环境的x。
在
obj环境执行,this.x指向obj.x。
回到本文开头提出的问题,
obj.foo()是通过obj找到foo,所以就是在obj环境执行。一旦var foo = obj.foo,变量foo就直接指向函数本身,所以foo()就变成在全局环境执行。