这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
下文有大概 70% 的内容出自 http://www.quirksmode.org/js/this.html,另外 30% 是我自己对它的理解和感想。希望能对有需要的人一点帮助。。。 首先,先看一个很典型的关于 this 关键字题目:
在传统面向对象语言中,this 关键字是个很乖的小孩,从不乱跑,该是谁的就是谁的。可是在 JavaScript 中,我们发现它不那么乖,有时甚至把我们搞的晕头转向的。所以有必要对它稍微做个总结。
- var name = 'hong'
- var obj = {
- name: 'ru',
- getName: function(){
- return function(){
- return this.name;
- };
- }
- }
- alert(obj.getName()());
这里也不卖关子了,执行结果为:hong 稍微改下代码:
- var name = 'hong'
- var obj = {
- name: 'ru',
- getName: function(){
- var that = this;
- return function(){
- return that.name;
- };
- }
- }
- alert(obj.getName()());
执行结果为:ru 执行结果为:ru 关于出现这种结果的原因,下面会细细讨论。 【函数的拥有者】 要解释 this,要先说这个概念。在 JavaScript 里,this 始终指向我们当前正在执行的函数的 "拥有者"。更为确切的说:是指向把这个函数作为方法的对象。 这句话怎么理解,我们可以看看下面的例子:
- /* -- test1 -- */
- function test1 () {
- this.title = 'me';
- alert(window['title']);
- alert(this === window); //true
- }
- test1();
执行结果为:me, true 在上例中,this 是指向 window 对象的。并把 window 这个对象的 title 属性写为'me',因为 test1 是个顶级函数,所以它的拥有者是 window 对象,或者说它是 window 对象的一个方法。这个应该不难理解。比如上面调用 test1()时,也可以写成 window.test1(); 这样的明了了。 接下来,我们建一个 div,并把 test1 作为方法赋给 div 的 onclick 属性:
- <div id="o" style="width:50px;height:50px;border:4px solid #333">
- me!
- </div>
- <script type="text/javascript">
- /* -- test1 -- */
- function test1() {
- this.title = 'me';
- alert(window['title']);
- alert(this === window);
- }
- var o = document.getElementById('o');
- o.onclick = test1;
- </script>
点击 div 结果为:undefined, false; 同时我们用 firebug 可以看到'me'这个属性值其实是被赋给了 id 为'o'的这个 HtmlObject
显而易见,此时 this 指向了这个 div,也就是说,test1() 的拥有者变成了 div 这个 HtmlObject,或者说它变成了 div 的 onclick 方法来调用。这种情况应该还是容易理解的。 下面我们接着改代码,就改一个地方:
- o.onclick = test1(); // 注意:这里加了个括号
把上面代码的最后一句改成这样后,点击 div 运行的结果为:me, true 变成了和第一种情况一样了,this 指向了 window。有人会纳闷,觉得没什么区别,其实是有区别的。这里涉及到函数的 copy 和 refer 的问题。 【函数的 Copy】 如果通过
- o.onclick = test1;
这样的方式的话,其实是把 test1() 这个函数 Copy 给了对象 o 的 onclick 属性。因此 test1 的拥有者变成了 o 这个对象。 如果通过
- o.onclick = test1();
这样的方式的话,本质上是指当获取到点击事件的 handle 时,指引它去执行 test1() 函数。注意是指引去执行而不是赋给它去执行。test1() 的拥有者没变,还是 window. 【函数的 Refer】 同上,我们通过 inline 的方式把调用写到 html 里来调用的话,还是 refer 的方式
- <div id="o" style="width:50px;height:50px;border:4px solid #333" onclick="test1()">
- me!
- </div>
点击 div 执行结果还是表示 this 指向 window。 【函数 copy 的例子】
- element.onclick = doSomething
- element.addEventListener('click',doSomething,false)
- element.onclick = function () {this.style.color = '#cc0000';}
- <element onclick="this.style.color = '#cc0000';">
这几种方式都会使 this 的指向变为当前调用的 object。 【函数 refer 的例子】
- element.onclick = function () {doSomething()}
- element.attachEvent('onclick',doSomething)
- <element onclick="doSomething()">
这几种方式都不会改变函数的拥有者,其中要注意的是 addEventListener 和 attachEvent 是不一致的,因为 attachEvent 其实是建立了一个 reference 到了 doSomething,而不是 copy 了这个函数。 【用 call 的方式】 刚才我们说了,写成
这样显式的调用是可以的。或者,用 call 或 apply 这种对象冒充的继承方式也可以
- <element onclick="test(this)">
- function (o) {
- o.title = 'me';
- }
这也是对象冒充最典型的方式。 【自由变量问题】 写了这么长,我们还是回到最开始的那个问题:
- <element onclick="test.call(this)">
- function test () {
- this.title = 'me';
- }
为什么这种方式得到的结果会是:hong 呢?重点在
- var name = 'hong'
- var obj = {
- name: 'ru',
- getName: function(){
- return function(){
- return this.name;
- };
- }
- }
- alert(obj.getName()());
对比一下上面写的函数 refer 的例子,不难发现,返回的这个匿名函数的调用方式和 onclick = function () {doSomething()} 如出一辙。所以这种方式并不会改变这个 function 的拥有者,它虽然是个嵌套函数,但是它的声明却是顶级的。其中的 this 指向的是 window。 而第二种方式是强制在 getName()中把 this 赋给了 that,也就是说,that.name 其实和 getName() 中的 this.name 是一样的。而在 getName 的上下文中,它的拥有者是 obj 这个对象,所以 this 会指向 obj,故 this.name === obj.name; 绕了这么一大圈不知道有没有把各位绕明白。 其实可以这样总结:在 this 所在的函数上下文中,如果这个函数不是以" 方法 " 的形式被调用的话,那么这个 this 会指向 window 对象,否则会指向这个函数的拥有者。
- return function(){
- return this.name;
- };
来源: http://www.phperz.com/article/17/0427/284099.html