前言:高程这本书真是神奇,每复习一遍,都会有新的收获。话说我看书有个习惯,要是看得似懂非懂的地方就喜欢打个“?”。这次看到高程第七章“函数表达式”关于闭包与this对象的部分,发现已经积攒了2个问号了。之前过了两遍都没有完全弄明白!
好在如今对this的指向、函数的理解已经今非昔比,这一次终于让我打通这条堵塞的经脉,让他融入我的知识体系了!!想想真是有些小激动呢~~
目的:一句话,本文就是解释为什么如下两篇代码中this.name的指向不同。
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); //The Window
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()()); //My Object
正文:首先,我们得知道当函数调用过程中发生了什么。
当函数被调用时,会自动创建两个变量:this和arguments。这两个变量有个特点,他们的搜索范围仅限被调用函数的活动对象。什么意思呢?arguments对象大家一定很清楚,保存函数的传参的副本。看如下代码:
function father (a) { var result=a; var result2=null; function son (a) { result2=a; } return result+" and "+result2; } father(123); //"123 and null"
这里创建了两个函数,father和son,其中son作为father函数内部的函数。 他们都接受传参a。在这里我们传入传参123,返回father与son获得的传参结果。
结果显示father的传参为123,而son的传参为null,这个结果是显而易见的。在这里贴这么弱智的代码的用意是想说明son在搜索a这个变量时只搜索自己的活动变量而不会通过作用域链向上到father中去搜索。同样的道理使用于this。
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); //The Window
这里最内层匿名函数this为什么指向的是window而不是他的上层函数getNameFunc。之前已经说明了this作为特殊的变量他的搜索范围同arguments一样仅限于自身的活动对象。也就是说内层匿名函数的this就算在自己这儿搜不到结果也不会再去他的上层函数getNameFunc中搜索。这个问题可以等同于——最内层匿名函数的this为什么指向的是window?
如果我们将最后的结果赋给一个变量来说明会简单汗多。
var result=object.getNameFunc()();
result变量是一个全局变量,他保存的指针指向getNameFunc最内层匿名函数的结果。访问这个变量其实调用的不是getNameFunc函数,而是getNameFunc内部的匿名函数。也就是说这个匿名函数是在全局作用域中调用的,那么匿名函数的this理所当然的指向window。
有了前面的解释,第二段代码就很好解释了。
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()()); //My Object
getNameFunc函数用that变量保存了他的this的指向,并在匿名函数中调用that变量。匿名函数在自己的活动对象中搜索到了that,并向上通过作用域链找到了that的出处。结果就显而易见了。