博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【学习笔记javascript设计模式与开发实践(this、call和apply)----2】
阅读量:4157 次
发布时间:2019-05-26

本文共 3355 字,大约阅读时间需要 11 分钟。

第2章this、call和apply

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

this的指向

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

o  作为对象的方法调用

o  作为普通函数调用

o  构造器调用

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

1.  作为对象方法的调用

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

[javascript]   
 
  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]   
 
  1. window.name = ‘globalName’;  
  2. var getName = function(e){  
  3.   return  this.name;  
  4. }  
  5. console.log(getName()); //输出:globalName  

或者

[javascript]   
 
  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]   
 
  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]   
 
  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]   
 
  1. function func(){  
  2.   “use strict”  
  3.   alert(this);//undefined  
  4. }  

3.  构造器调用

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

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

[javascript]   
 
  1. var MyClass = function(){  
  2.    this.name = ‘sven’;  
  3. }  
  4. var obj = new MyClass();  
  5. alert(obj.name); //输出:sven  

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

[javascript]   
 
  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]   
 
  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]   
 
  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]   
 
  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]   
 
  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属性可读写

转载地址:http://pgzxi.baihongyu.com/

你可能感兴趣的文章
C中的static函数
查看>>
Ubuntu系统root用户密码找回方法
查看>>
Linux驱动程序中比较重要的宏
查看>>
芯片驱动问题定位思路总结之一单板重启的问题
查看>>
S3C2440看门狗定时器
查看>>
LDD3源码分析之llseek分析
查看>>
linux read 用法
查看>>
LDD3源码分析之llseek分析(二)
查看>>
printk及控制台的日志级别
查看>>
Linux驱动加载实例
查看>>
Percona对MySQL标准版本的改进
查看>>
Instagram 架构师分析笔记
查看>>
你应该知道的Unix和Linux命令 lsof
查看>>
Nginx模块开发入门
查看>>
安全的Web主机iptables防火墙脚本
查看>>
Nginx的平滑重启和平滑升级
查看>>
大型互联网站解决海量数据的常见策略
查看>>
好多东西还是看官网的比较好... MySQL 5.1 Server System Variables
查看>>
chattr
查看>>
/etc/sysctl.conf 调优 & 优化Linux内核参数
查看>>