JavaScript设计模式之二:this、call和apply
2016-03-10 00:00
127 查看
摘要: 在Javascript的设计模式中,this很关键,Function.prototype.call和Function.prototype.apply应用很广泛
(本节内容摘自:Javascript设计模式与开发实践一书,作为自己的笔记保存,希望对有需要的朋友有用)
this、call和apply在Javascript编程中应用非常广泛,所以,我们必须先了解它们。
当函数作为对象的方法时,this指向该对象,看下面的代码:
当作为普通函数调用时,此时的this总是指向全局对象window
下面来一个实际的例子,我们在一个div节点内部,定义一个局部的callback方法,当这个方法被当做普通函数调用时,callback内部的this就指向了window,如下代码:
我们可以将callback函数分别写成alert(this === callback)和alert(this === window)来测试下。
那我们如何来解决这个问题呢,我们可以使用一个变量来保存div节点的引用
在ES5的strict模式,这种this不会再指向window,而是undefined
构造器的调用,当我们使用new运算符调用函数时,总会返回一个对象,那么构造器里的this就指向这个对象
Function.prototype.call或Function.prototype.apply调用,可以动态的改变传入函数的this
OK,我们再来看下下面的例子,丢失的this:
当obj调用其方法getName时,此时的this指向obj对象,所以打印出obj对象的myName属性值,然后当把对象obj的getName方法赋值给对象getName2时,此时是普通函数调用,this就指向了全局window对象,所以会打印出undefined。
apply接受两个参数,第一个指定函数体内this对象的指向,第二个是集合,可以是数组也可以是类数组,apply方法把集合中的元素作为参数传递给被调用的函数
call传入的参数不是固定的,第一个参数与apply相同,代表函数体内的this指向,从第二个参数开始,每个参数被依次传入函数
在Javascript内部,参数是用数组来表示的,所以,apply比call的使用率更高,如果我们明确参数的数量,想一目了然的表达形参与实参的对应关系,那么我们就使用call。
在使用apply或者call时,如果第一个参数使用null,那么函数体内的this会指向默认的宿主对象,在浏览器中就是window,但在严格模式下,仍然为null。
下面我们来看看apply和call的实际用途
1、改变this指向
当执行getName.call(obj1)的时候,getName()函数体内的this就指向了obj1对象
我们再来看一个在实际开发中可能会遇到的例子,如页面中有一个id为div1的区块
上面的代码中,事件函数有一个内部函数func,调用此函数时,this就指向了window,我们可以用call来修正它
2、Function.prototype.bind
大部分浏览器都实现了内置的Function.prototype.bind,用来指定函数内部的this指向。(这个内容不知道为什么要写,所以就略掉)
3、借用其他对象的方法
借用方法的第一种场景是“借用构造函数”,通过它可以实现一些类似继承的效果
第二种场景是对函数的参数列表arguments进行一些操作,arguments并非真正的数组,如果我们想往arguments中添加一些元素,就可以借用Array.prototype.push方法
(本节内容摘自:Javascript设计模式与开发实践一书,作为自己的笔记保存,希望对有需要的朋友有用)
this、call和apply在Javascript编程中应用非常广泛,所以,我们必须先了解它们。
一、this
Javascript中的this总是指向一个对象,而它又是基于执行环境动态绑定,以下有4中情况可以用来分析。当函数作为对象的方法时,this指向该对象,看下面的代码:
var obj = { a: 1, getA: function(){ alert(this === obj); //true alert(this.a); //1 } }; obj.getA();
当作为普通函数调用时,此时的this总是指向全局对象window
window.name = 'globalName'; var getName = function(){ return this.name; }; console.log(getName()); //globalName
下面来一个实际的例子,我们在一个div节点内部,定义一个局部的callback方法,当这个方法被当做普通函数调用时,callback内部的this就指向了window,如下代码:
<html> <body> <div id="div1">我是一个Div</div> </body> <script> window.id = 'window'; document.getElementById('div1').onclick = function(){ alert(this.id); //div1 var callback = function(){ alert(this.id); //window } callback(); }; </script> </html>
我们可以将callback函数分别写成alert(this === callback)和alert(this === window)来测试下。
那我们如何来解决这个问题呢,我们可以使用一个变量来保存div节点的引用
<html> <body> <div id="div1">我是一个Div</div> </body> <script> window.id = 'window'; document.getElementById('div1').onclick = function(){ var that = this; alert(that.id); //div1 var callback = function(){ alert(that.id); //div1 } callback(); }; </script> </html>
在ES5的strict模式,这种this不会再指向window,而是undefined
function func(){ "use strict"; alert(this); //undefined } func();
构造器的调用,当我们使用new运算符调用函数时,总会返回一个对象,那么构造器里的this就指向这个对象
var myClass = function(){ this.name = 'Kaindy'; }; var obj = new myClass(); alert(obj.name); //Kaindy
Function.prototype.call或Function.prototype.apply调用,可以动态的改变传入函数的this
var obj1 = { name: 'Kaindy', getName: function(){ return this.name; } }; var obj2 = { name: 'anne'; } console.log(obj1.getName()); //Kaindy console.log(obj1.getName.call(obj2)); //anne
OK,我们再来看下下面的例子,丢失的this:
var obj = { myName: 'Kaindy', getName: function(){ return this.myName; } }; console.log(obj.getName()); //Kaindy var getName2 = obj.getName; console.log(getName2()); //undefined
当obj调用其方法getName时,此时的this指向obj对象,所以打印出obj对象的myName属性值,然后当把对象obj的getName方法赋值给对象getName2时,此时是普通函数调用,this就指向了全局window对象,所以会打印出undefined。
二、call和apply
下面我们来分析下call和apply,它们是ES3为Function的原型定义的两个方法,它们的作用一样,区别只是在传入的参数的不同。apply接受两个参数,第一个指定函数体内this对象的指向,第二个是集合,可以是数组也可以是类数组,apply方法把集合中的元素作为参数传递给被调用的函数
var func = function(a, b, c){ alert([a, b, c]); //[1, 2, 3] }; func.apply(null, [1, 2, 3]);
call传入的参数不是固定的,第一个参数与apply相同,代表函数体内的this指向,从第二个参数开始,每个参数被依次传入函数
var func = function(a, b, c){ alert([a, b, c]); //[1, 2, 3] }; func.call(null, 1, 2, 3);
在Javascript内部,参数是用数组来表示的,所以,apply比call的使用率更高,如果我们明确参数的数量,想一目了然的表达形参与实参的对应关系,那么我们就使用call。
在使用apply或者call时,如果第一个参数使用null,那么函数体内的this会指向默认的宿主对象,在浏览器中就是window,但在严格模式下,仍然为null。
下面我们来看看apply和call的实际用途
1、改变this指向
var obj1 = { name: 'sven'; }; var obj2 = { name: 'anne'; }; window.name = 'window'; var getName = function(){ alert(this.name); }; getName(); //window getName.call(obj1); //sven getName.call(obj2); //anne
当执行getName.call(obj1)的时候,getName()函数体内的this就指向了obj1对象
我们再来看一个在实际开发中可能会遇到的例子,如页面中有一个id为div1的区块
document.getElementById('div1').onclick = function(){ alert(this.id); //此处的this指向document.getElementById('div1')产生对象,输出div1 var func = function(){ alert(this.id); //此处的this就指向全局对象window了,故输出undefined }; func(); }
上面的代码中,事件函数有一个内部函数func,调用此函数时,this就指向了window,我们可以用call来修正它
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指向。(这个内容不知道为什么要写,所以就略掉)
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
第二种场景是对函数的参数列表arguments进行一些操作,arguments并非真正的数组,如果我们想往arguments中添加一些元素,就可以借用Array.prototype.push方法
(function(){ Array.prototpye.push.call(argumets, 3); console.log(arguments); [1,2,3] })(1, 2);
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- 最后一次说说闭包
- Ajax
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- 异步流程控制:7 行代码学会 co 模块
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因
- Canvas 在高清屏下绘制图片变模糊的解决方法
- Redux系列02:一个炒鸡简单的react+redux例子
- JavaScript 各种遍历方式详解
- call/apply/bind 的理解与实例分享