蛀牙--《设计模式---通往未来的很高的台阶之(五)》
来源:互联网 发布:外卖货到付款的软件 编辑:程序博客网 时间:2024/04/28 23:26
今天谈谈this call apply
为什么要特意说一说这几个关键字呢。就学就行了,他们应用还是蛮广泛的
1、this
和其他语言不一样,js中的this总是指向一个对象,而具体指向那个对象是在运行时基于运行时函数的执行环境动态绑定的。
那么this指向分几种方式呢
(1)、作为对象的方法调用
当函数作为对象的方法被调用时,this指向该对象
var obj = { a:1, getA:function(){ alert( this === obj ); //输出 true alert( this.a ); //输出 1 }};obj.getA();
(2)、作为普通函数调用
当函数不作为对象的属性被调用时,此时this总是指向window对象
window.name = "globalName";var getName = function(){ return this.name;};console.log(getName());//输出 globalName
这里还分几种不同的情况 比如说我们在 button节点的时间函数内,有一个局部的回调方法,回调方法会被作为普通的函数调用。那么this就指向了全局对象 也就是window 。该怎么办呢???
这就需要我们保存div节点的引用。 方法就不详细介绍了 ,相信大家在平时的开发中都用到了。
在ES5的严格模式下,以上情况this被规定为undefined
(3)、构造器调用
js中没有类,但是可以从构造器中创建对象,同时也提供了new运算符,使得构造器很想一个类。
构造器的外观和普通函数提莫一样,区别就是调用的方式不同。当用new调用函数时,该函数总会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象。
var MyClass = fucntion(){ this.name = 'zhuya';};var obj = new MyClass();alert( obj.name ); //输出 zhuya
但是用new调用构造器时,要注意的问题就是,如果构造器显示的返回了一个object类型的对象。就会变成这种情况
var MyClass = function(){ this.name = 'zhuya'; return{ name:'anne'; }}var obj = new MyClass();alert( obj.name ); //输出 anne
(4)、Function.prototype.call 或 Function.prototype.apply调用
与普通函数调用相比,用Function.prototype.call或Function.prototype.apply可以动态的改变传入函数的this
var obj1 = { name:'zhuya', getName:function(){ return this.name; }};var obj2 = { name:'anne'};console.log( obj1.getName() ); //输出zhuyaconsole.log( obj1.getName.call( obj2 ) ); //输出 anne
2、call和apply
能熟练的运用这两个方法是我门成为js程序员的重要一步
apply接受两个参数,第一个参数制定了函数体内this对象的指向,第二个参数作为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply方法吧这个集合中的元素作为参数传递给被调用的函数
var func = function( a,b,c ){ alert( [a,b,c] ); //输出[ 1 ,2 ,3 ]}func.apply( null,[1,2,3] );
这段代码中,参数 1、2、3被放在数组中一起传入func函数,他们分别对应func参数列表中的a、b、c
call传入的参数数量不固定,和apply一样,第一个参数都是代表函数体内部this的指向,第二个参数往后,每个参数被依次传入函数
var func = function(a,b,c){ alert([a,b,c]); //输出[1,2,3]};func.call( null,1,2,3 );
当调用一个函数时,js解释器不会计较形参和实参在数量,类型以及顺序上的区别。js的参数在内部就是用一个数组表示的。从这个意义上来说,apply比call的使用率更高。
当使用call或者apply的时候,如果传入的第一个参数为null,函数体内的this会指向默认的宿主对象。在浏览器中则是window:
var func = function( a,b,c ){ alert ( this === window ); //输出true};func.apply( null,[1,2,3] );
call和apply的用途
(1)改变this的指向
var obj1 ={ name:'sven'};var obj2 = { name : "anne"};window.name = 'window';var getName = function(){ alert ( this.name );};getName(); //输出windowgetName.call(obj1); //输出 svengetName.call(obj2); //输出 anne
但是在实际开发中。经常会遇到的this指向不经意改变的场景。比如有一个div节点,div节点的onclick事件中的this本来是指向这个div的:
document.getElementById(' div1 ').onclick = function(){ alert( this.id ); //输出 div1}
假如该事件中有一个内部的函数func,在事件内部中调用func函数时,func函数体的this就指定了window,而不是我们预期的div ,见如下代码:
document.getElementById('div1').onclick = function(){ alert( this.id ); //输出 div1 var func = function(){ alert(this.id); //输出undefined } func();};
我们可以用call来修正func函数内部的this,其依然指向div
document.getElementById('div1').onclick = function(){ alert( this.id ); //输出 div1 var func = function(){ alert(this.id); //输出div1 } func.call(this);};
(2)Function.prototype.bind
大部分高级浏览器都实现了内置的Function.prototype.bind来制定函数内部的this指向,即使没有原生的Function.prototype.bind实现,模拟一个也不难
Function.prototype.bind = function(context){ var self = this; //保存原函数 return function(){ //返回一个新的函数 return self.apply( context ,arguments );// 执行新的函数的时候,会把之前传入的context //当成新函数体内的this } };var obj = { name:'sven'};var func = function(){ alert(this.name); //输出 sven}.bind(obj);func();
我们通过Function.prototype.bind来包装 func函数,并且传入一个对象 context 当作参数,这个context对象就是我们想修正的this对象
(3)借用其他对象的方法
借用构造函数 通过这种技术 可以实现一些类似继承的效果
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() ); //输出:'sven'
人之所以弱小是因为还有缺陷——《蛀牙》
- 蛀牙--《设计模式---通往未来的很高的台阶之(五)》
- 蛀牙--《设计模式---通往未来的很高的台阶之(一)》
- 蛀牙--《设计模式---通往未来的很高的台阶之(二)》
- 蛀牙--《设计模式---通往未来的很高的台阶之(三)》
- 蛀牙--《设计模式---通往未来的很高的台阶之(四)》
- 蛀牙--《设计模式---通往未来的很高的台阶之(六)》
- 通往幸福的九级台阶
- [软件人生]苦难与蜕变——心性修炼是通往高手之路的第一个台阶[ZT]
- 转载:苦难与蜕变——心性修炼是通往高手之路的第一个台阶
- 代码脏乱的“蛀牙”效应
- 设计模式之五:原型模式—对象的克隆
- 转:IT恐怖战国:通往终极垄断的最后几级台阶
- 《nslookup通往DNS的桥梁》-linux命令五分钟系列之三十三
- 读前辈的大话设计模式(五)之代理模式,抒自己的读后感
- 高品质的网页设计与技巧之五(自我克制与精妙细节)
- 我们的目标是:没有蛀牙!
- 拔掉那颗蛀牙的红警
- 重读《设计模式》之学习笔记(五)--我对COMPOSITE模式的理解
- git学习五:eclipse使用git下载项目
- Qt基础 08_数据传送_顺传
- 友盟错误分析解析
- 【图】图的遍历及实现
- wpf中:xaml中的命名空间的引入方法
- 蛀牙--《设计模式---通往未来的很高的台阶之(五)》
- Akka(7): FSM:通过状态变化来转换运算行为
- centos7 同时安装python2、python3和pip3以及各种包遇到的坑
- iOS 手机号和固话验证方法
- 25. OP-TEE驱动篇----驱动编译,加载和初始化(二)
- DRUID: 任务分配策略配置
- hibernate配置文件详解
- PAT.1036. 跟奥巴马一起编程
- XGBoost学习资料及Anacoda安装