【学习笔记javascript设计模式与开发实践(this、call和apply)----2】
2015-09-29 14:43
1041 查看
第2章this、call和apply
跟别的语言大相径庭的是,javascript的this总是指向一个对象,而具体指向哪个对象是运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。this的指向
除去不常用的with和eval的情况,具体到实际应用中,this的指向大致可以分为以下4种o 作为对象的方法调用
o 作为普通函数调用
o 构造器调用
o Function.prototype.call或Function.prototype.apply调用。
1. 作为对象方法的调用
当作为对象方法调用时,this指向该对象:var obj = { a:1, getA:function(){ alert(this==obj); alert(this.a); } } obj.getA();
2. 作为普通函数调用
当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的this总是指向全局对象。在浏览器js里,这个全局对象是window对象如:
window.name = ‘globalName’; var getName = function(e){ return this.name; } console.log(getName()); //输出:globalName
或者
window.name = ‘globalName’; var myObject = { name:’sven’, getName:function(){ return this.name; } } var getName = myObject.getName; console.log(getName()); //输出globalName
有时候我们会遇到一些困扰,比如在div节点的事件函数内部,有一个局部的callback方法,callback方法作为普通方法调用内部的this指向window,但我们往往是想让它指向div节点。
如下:
<html> <body> <div id=”div1”>我是一个div</div> </body> <script> window.id = “window”; document.getElementById(“xxx”).onclick = function(){ alert(this.id); //输出:div var callback = function(){ alert(this.id); //输出:window }; callback(); } </script> </html>
此时有一种简单的解决方案,就是用一个变量保存div节点的引用
document.getElementById(“xxx”).onclick = function(){ var that = this; alert(this.id); //输出:div1 var callback = function(){ alert(that.id); //输出:div1 }; callback(); }
在ECMAScript5的strict模式下,这种情况下的this已经被规定为不会指向全局对象,而是undefined。
function func(){ “use strict” alert(this);//undefined }
3. 构造器调用
javascript中没有类,但是可以从构造器中创建对象,同是也提供了new运算符,使得构造器看起来更像一个类除了宿主提供的一些内置函数,大部分javascript函数都可以当作构造器使用。构造器的外表跟普通函数一模一样,它们的区别在于被调用的方式。当用new运算符调用函数时该函数会返回一个对象。
var MyClass = function(){ this.name = ‘sven’; } var obj = new MyClass(); alert(obj.name); //输出:sven
注意:如果new 调用构造器时还要注意一个问题,如果构造器显式地返回一个object类型的对象,那么此次运算结果最终会返回这个对象(参见之前的总结)
var MyClass = function(){ this.name = ‘sven’; return { name:’anne’ } } var obj = new MyClass(); alert(obj.name); //输出:anne
注意如果构造器不显式返回的不是一个对象类型的数据就不会造成上述问题。
如:
var MyClass = function(){ this.name = ‘sven’; return “question”; } var obj = new MyClass(); alert(obj.name); //输出:sven
4. Functon.prototype.call或Function.prototype.apply调用
动态改变传入函数的this2.1丢失this
如:var obj = { myName:”sven”, getName:function(){ return this.myName; } } console.log(obj.getName()); //sven var getName2 = obj.getName; console.log(getName2());//undefined 变成普通函数调用啦 //正如document.getElementById();我们来简化这个写法的时候是这样做的 var getId = function(id){ return document.getElementById(id); }
而不是简单的这样
var getId = document.getElementById; //普通函数调用啦,上下文指向的不是document而是window对象啦
call和apply的区别就是前者的参数对应传递是单个的,后者以数组的形式传递函数的参数。
借用其他对象的方法
借用方法的第一种场景就是借用构造函数,通过这种技术,可以以实现类似继承的效果:
var A = function(name){ this.name = name; } var B = function(){ A.apply(this,arguments); } B.prototype.getName = function(){ return this.name; } var b = new B(‘sven’); console.log(b.getName());<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
第二种运用场景跟我们的关系更加密切:
函数的参数列表arguments是一个类数组对象,虽然它也有“下标”,但它并非真正的数组,所以也不能像数组一样,进行排序操作或者往集合里添加一个新的元素。这种情况下我们常常借用Array.prototype对象上的方法。
如
(function(){ Array.prototype.push.call(arguments,3); console.log(arguments); //[1,2,3] })(1,2)
这种数组方法借用是可以在绝大多数浏览器中顺利执行,但由于引擎的内部实现存在差异,如果在低版本的IE中执行,必须显式地给对象a设置属性length。
所以这种数组方法的借用要满足:
o 对象本身要可以存取属性
o 对象的length属性可读写
相关文章推荐
- [IOS 开发] iOS 如何将日期字符串转成NSDate
- Android清除本地数据缓存代码
- [置顶] 我的Android进阶之旅------>Android解决异常: startRecording() called on an uninitialized AudioRecord.
- CooradicatoarLayout 介绍
- Objective-C---5---字典,集合
- Tools ------ Installing the Android SDK ------ Installing Android Studio
- Android 常见分辨率
- ios 创建和绘画pdf文件 -转
- 从零开始学习iOS开发-股票记帐本1.0(4)
- IOS TableView实现省市联动
- 总结:iOS打包发布在不同的机器上面
- IOS Masonry自动布局
- Android之解析XML总结(SAX、Pull、Dom三种方式)
- android L新控件RecyclerView具体解释DeMo
- APP推广之有关ASO痛点的10个Q&A
- Android动画之属性动画Animator详解(卫星菜单)
- 如果没有 Android,世界会怎样?-IT蓝豹
- 版本检测更新 调用AppStore 显示自己的app
- 斯坦福iOS7 2013-2014秋Assignment 6的一种答案 #3
- iOS中需要注意的小细节