学懂 JavaScript 言语,一个标志就是了解下面两种写法,或许有不一样的成果。
<blockquote "="">
var obj = { foo: function () {} }; var foo = obj.foo; // 写法一 obj.foo() // 写法二 foo()
上面代码中,尽管obj.foo和foo指向同一个函数,可是履行成果或许不一样。请看下面的比如。
<blockquote "="">
var obj = { foo: function () { console.log(this.bar) }, bar: 1 }; var foo = obj.foo; var bar = 2; obj.foo() // 1 foo() // 2
这种差异的原因,就在于函数体内部使用了this关键字。许多教科书会通知你,this指的是函数运转时地点的环境。关于obj.foo()来说,foo运转在obj环境,所以this指向obj;关于foo()来说,foo运转在大局环境,所以this指向大局环境。所以,两者的运转成果不一样。
这种解释没错,可是教科书往往不通知你,为什么会这样?也就是说,函数的运转环境到底是怎么决议的?举例来说,为什么obj.foo()就是在obj环境履行,而一旦var foo = obj.foo,foo()就变成在大局环境履行?
本文就来解释 JavaScript 这样处理的原理。了解了这一点,你就会完全了解this的效果。
二、内存的数据结构
JavaScript 言语之所以有this的规划,跟内存里边的数据结构有关系。
<blockquote "="">
var obj = { foo: 5 };
上面的代码将一个目标赋值给变量obj。JavaScript 引擎会先在内存里边,生成一个目标{ foo: 5 },然后把这个目标的内存地址赋值给变量obj。
也就是说,变量obj是一个地址(reference)。后面如果要读取obj.foo,引擎先从obj拿到内存地址,然后再从该地址读出原始的目标,返回它的foo特点。
原始的目标以字典结构保存,每一个特点名都对应一个特点描绘目标。举例来说,上面比如的foo特点,实际上是以下面的方式保存的。
<blockquote "="">
{ foo: { [[value]]: 5 [[writable]]: true [[enumerable]]: true [[configurable]]: true } }
留意,foo特点的值保存在特点描绘目标的value特点里边。
三、函数
这样的结构是很明晰的,问题在于特点的值或许是一个函数。
<blockquote "="">
var obj = { foo: function () {} };
这时,引擎会将函数独自保存在内存中,然后再将函数的地址赋值给foo特点的value特点。
<blockquote "="">
{ foo: { [[value]]: 函数的地址 ... } }
因为函数是一个独自的值,所以它可以在不同的环境(上下文)履行。
<blockquote "="">
var f = function () {}; var obj = { f: f }; // 独自履行 f() // obj 环境履行 obj.f()
四、环境变量
JavaScript 允许在函数体内部,引用当时环境的其他变量。
<blockquote "="">
var f = function () { console.log(x); };
上面代码中,函数体里边使用了变量x。该变量由运转环境提供。
现在问题就来了,因为函数可以在不同的运转环境履行,所以需要有一种机制,http://www.qijihu.com专卖网站可以在函数体内部获得当时的运转环境(context)。所以,this就呈现了,它的规划意图就是在函数体内部,指代函数当时的运转环境。
<blockquote "="">
var f = function () { console.log(this.x); }
上面代码中,函数体里边的this.x就是指当时运转环境的x。
<blockquote "="">
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()就变成在大局环境履行。
(完)