【学习笔记javascript设计模式与开发实践(this、call和apply)----2】

第2章this、call和apply

跟别的语言大相径庭的是,javascript的this总是指向一个对象,而具体指向哪个对象是运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

this的指向

除去不常用的with和eval的情况,具体到实际应用中,this的指向大致可以分为以下4种

o  作为对象的方法调用

o  作为普通函数调用

o  构造器调用

o  Function.prototype.call或Function.prototype.apply调用。

1.  作为对象方法的调用

当作为对象方法调用时,this指向该对象:

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. var obj = {  
  2. a:1,  
  3. getA:function(){  
  4.     alert(this==obj);  
  5.     alert(this.a);  
  6. }  
  7. }  
  8. obj.getA();  

2.  作为普通函数调用

当函数作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的this总是指向全局对象。在浏览器js里,这个全局对象是window对象

如:

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. window.name = ‘globalName’;  
  2. var getName = function(e){  
  3.   return  this.name;  
  4. }  
  5. console.log(getName()); //输出:globalName  

或者

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. window.name = ‘globalName’;  
  2. var myObject = {  
  3.  name:’sven’,  
  4.  getName:function(){  
  5.     return this.name;  
  6.  }  
  7. }  
  8. var getName = myObject.getName;  
  9. console.log(getName()); //输出globalName  

有时候我们会遇到一些困扰,比如在div节点的事件函数内部,有一个局部的callback方法,callback方法作为普通方法调用内部的this指向window,但我们往往是想让它指向div节点。

如下:

[html]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <html>  
  2.   <body>  
  3.       <div id=”div1”>我是一个div</div>  
  4.   </body>  
  5. <script>  
  6.     window.id = “window”;  
  7.        document.getElementById(“xxx”).onclick = function(){  
  8.           alert(this.id); //输出:div  
  9.           var callback = function(){  
  10.            alert(this.id); //输出:window  
  11.           };  
  12.           callback();  
  13.        }  
  14.    
  15. </script>  
  16. </html>  

此时有一种简单的解决方案,就是用一个变量保存div节点的引用

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. document.getElementById(“xxx”).onclick = function(){  
  2.        var that = this;  
  3.        alert(this.id); //输出:div1  
  4.        var callback = function(){  
  5.         alert(that.id); //输出:div1  
  6.        };  
  7.        callback();  
  8.  }  

在ECMAScript5的strict模式下,这种情况下的this已经被规定为不会指向全局对象,而是undefined。

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. function func(){  
  2.   “use strict”  
  3.   alert(this);//undefined  
  4. }  

3.  构造器调用

javascript中没有类,但是可以从构造器中创建对象,同是也提供了new运算符,使得构造器看起来更像一个类

除了宿主提供的一些内置函数,大部分javascript函数都可以当作构造器使用。构造器的外表跟普通函数一模一样,它们的区别在于被调用的方式。当用new运算符调用函数时该函数会返回一个对象。

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. var MyClass = function(){  
  2.    this.name = ‘sven’;  
  3. }  
  4. var obj = new MyClass();  
  5. alert(obj.name); //输出:sven  

注意:如果new 调用构造器时还要注意一个问题,如果构造器显式地返回一个object类型的对象,那么此次运算结果最终会返回这个对象(参见之前的总结) 

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. var MyClass = function(){  
  2. this.name = ‘sven’;  
  3. return {  
  4.    name:’anne’  
  5. }  
  6. }  
  7. var obj = new MyClass();  
  8. alert(obj.name); //输出:anne  

注意如果构造器不显式返回的不是一个对象类型的数据就不会造成上述问题。

如:

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. var MyClass = function(){  
  2.  this.name = ‘sven’;  
  3.  return “question”;  
  4. }  
  5. var obj = new MyClass();  
  6. alert(obj.name); //输出:sven  

4.  Functon.prototype.call或Function.prototype.apply调用

动态改变传入函数的this

2.1丢失this

如:

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. var obj = {  
  2.  myName:”sven”,  
  3.  getName:function(){  
  4.      return this.myName;  
  5.  }  
  6. }  
  7. console.log(obj.getName()); //sven  
  8. var getName2 = obj.getName;  
  9. console.log(getName2());//undefined 变成普通函数调用啦  
  10. //正如document.getElementById();我们来简化这个写法的时候是这样做的  
  11. var getId = function(id){  
  12.    return document.getElementById(id);  
  13. }  

而不是简单的这样

var getId = document.getElementById; //普通函数调用啦,上下文指向的不是document而是window对象啦

call和apply的区别就是前者的参数对应传递是单个的,后者以数组的形式传递函数的参数。

借用其他对象的方法

借用方法的第一种场景就是借用构造函数,通过这种技术,可以以实现类似继承的效果:

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. var A = function(name){  
  2.      this.name = name;  
  3. }  
  4.    
  5. var B = function(){  
  6.     A.apply(this,arguments);  
  7. }  
  8. B.prototype.getName = function(){  
  9.    return this.name;  
  10. }  
  11. var b = new B(‘sven’);  
  12. console.log(b.getName());<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>  

二种运用场景跟我们的关系更加密切:

函数的参数列表arguments是一个类数组对象,虽然它也有“下标”,但它并非真正的数组,所以也不能像数组一样,进行排序操作或者往集合里添加一个新的元素。这种情况下我们常常借用Array.prototype对象上的方法。

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. (function(){  
  2.   Array.prototype.push.call(arguments,3);  
  3.   console.log(arguments); //[1,2,3]  
  4. })(1,2)  
 

这种数组方法借用是可以在绝大多数浏览器中顺利执行,但由于引擎的内部实现存在差异,如果在低版本的IE中执行,必须显式地给对象a设置属性length。

所以这种数组方法的借用要满足:

o  对象本身要可以存取属性

o  对象的length属性可读写

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值