日期:2014-05-16  浏览次数:20353 次

javascript难点之二:有奶就是娘的this
接下来谈谈js里的一个非常让人费解的关键字:this
之所以让人费解,可能是应为先入为主的关系。从面向过程的编程到面向对象的编程,class和object让无数习惯面向过程的人挣扎了许久,即使是从java,c++基于类的继承到js基于对象的继承,也让我们一头雾水。学会了严谨的高级语言,反而对js这个太随便的小流氓无从下手,它的种种行为看在眼里匪夷所思,长着和别人一样的嘴脸,但是却做着不一样的勾当。众所周知,this在JAVA里只是只带对象本身或者说是类本身,但是在js里,同样的this,你却闹不明白它到底在代表谁,而且同一个this,此时代表A,彼时可能就代表B了。这就是所谓的动态语言么?编程的随意性的增加看似可以变的功能强大,但是,越随意越是不好管理,就像C的指针,用的好可以提高性能,但是一点小错误也是致命的,代码可读性直线下降。这不应该是编程语言的趋势。
闲话不多说了,看看this到底怎么回事。
This在JS标准里的定义:对于每个执行上下文,都有一个 this 值与其相关联。在控制进入执行上下文时,根据调用者和被执行代码的类型决定这个值。与执行上下文相关联的 this 值是非可变的。
执行上下文:当控制器转换到 ECMAScript 可执行代码时,控制器就进入了执行上下文。活动的执行上下文组成一个逻辑上的栈。逻辑栈上的顶层执行上下文即正在运行的执行上下文。
进入执行上下文:每个函数和构造器调用都要进入一个新的执行上下文,即使是函数在递归地调用自身。每次返回都会退出执行上下文。未被 catch 的异常抛出有可能退出一个或多个执行上下文。当控制进入执行上下文时,创建并初始化作用域链,进行变量初始化,并决定 this 值。作用域链的初始化,变量的初始化和 this 值的决定取决于进入的代码类型。
通过以上的一系列名词定义知道,this到底代表什么,取决于此时此刻哪一个对象在用这个执行上下文。
function who(){
alert(this.name);
}
这个函数就是一个简单的执行上下文。直接输出who()的话,调用这个函数的对象是window,而window里没有name这个属性, 所以窗口弹出的是空白,继续写一个对象
var me = {name:"haha"};
me.who = who;//把who方法复制给me里的who属性
me.who();//调用这个me 的who方法
这时候,输出为haha。
其他情况也类似,如果学过call方法的话,下面的就比较容易理解了,如果还没学过,可以看我下一篇文章,<javascript难点之三:没有见过的怪物call>。
who.call(me)输出也为haha,这时候,调用这个方法的对象是me。
最后总结一下,在java等语言中,this指代的就是对象自己,this在那个类里声明的,就指代哪个类和他的对象。JS中的this虽然从本质上来说,也是指代对象,但是不同的是,这个this到底是指代哪个对象,这要更具实际情况来判断,简单的说,就是找到执行this所在的上下文的那个具体的对象,如果没有这样定义的对象,默认是浏览器window对象在执行上下文。记住this代表了一个对象就对了,然后就是撕下this这个面具,看看面具后面到底是哪个对象在操纵的过程,啊,有点福尔摩斯的感觉了。