在JavaScript 中,call、apply 和 bind 是 Function 对象自带的三个方法,这三个方法的主要作用是改变函数调用过程中的 this 指向
apply(thisArgs[,args[]])
- 第一个参数指定函数体内this对象的指向
thisArgs 的取值有以下4种情况:- 不传,或者传
null
,undefined
, 非严格模式下 函数中的this
指向window
对象。 严格模式下不传
、undefined
函数中this
指向undefined
。传入null
函数中this
指向null
- 传递另一个函数的函数名,函数中的
this
指向这个函数的引用 - 传递字符串、数值或布尔类型等基础类型,非严格模式函数中的
this
指向其对应的包装对象,如String
、Number
、Boolean
。严格模式,指向传入的值 - 传递一个对象,函数中的
this
指向这个对象
- 不传,或者传
- 第二个参数为一个带下标的集合,可以是数组或类数组,apply方法把这个集合中的元素作为参数传递给被调用的函数
var func = function(a, b, c) {
console.log([a, b, c]); // [1,2,3]
}
func.apply(null, [1,2,3])
apply 和 call 的唯一区别是第二个参数的传递方式不同,apply 的第二个参数必须是一个数组,而 call 允许传递一个参数列表。值得你注意的是,虽然 apply 接收的是一个参数数组,但在传递给调用函数时,却是以参数列表的形式传递,我们看个简单的例子:
function b(x,y,z){
console.log(x,y,z);
}
b.apply(null,[1,2,3]); // 1 2 3
call(thisArgs [,args...])
该方法可以传递一个thisArgs参数和一个参数列表,thisArgs 指定了函数在运行期的调用者,也就是函数中的 this 对象,而参数列表会被传入调用函数中。
thisArgs 的取值有以下4种情况:
- 不传,或者传
null
,undefined
, 非严格模式下 函数中的this
指向window
对象。 严格模式下不传
、undefined
函数中this
指向undefined
。传入null
函数中this
指向null
- 传递另一个函数的函数名,函数中的
this
指向这个函数的引用 - 传递字符串、数值或布尔类型等基础类型,非严格模式函数中的
this
指向其对应的包装对象,如String
、Number
、Boolean
。严格模式,指向传入的值 - 传递一个对象,函数中的
this
指向这个对象
function a(){
console.log(this); //输出函数a中的this对象
}
function b(){} //定义函数b
var obj = {name:'onepixel'}; //定义对象obj
// 严格模式
a.call(); //undefined
a.call(null); //null
a.call(undefined);//undefined
a.call(1); //1
a.call(''); // ''
a.call(true); //true
a.call(b);// function b(){}
a.call(obj); //Object
// 非严格模式
a.call(); //window
a.call(null); //window
a.call(undefined);//window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b);// function b(){}
a.call(obj); //Object
当使用call或则apply的时候,如果我们传入的第一个参数是null.函数体内的this会指向默认的宿主对象,在游览器中则是window
var func = function( a, b, c ){
alert ( this === window ); // 输出true
};
func.apply( null, [ 1, 2, 3 ] );
但如果是在严格模式下,函数体内的this还是为null:
var func = function( a, b, c ){
"use strict";
alert ( this === null ); // 输出true
}
func.apply( null, [ 1, 2, 3 ] );
有时候我们使用call或者apply的目的不在于指定this指向,而是另有用途,比如借用其他对象的方法。
那么我们可以传入null来代替某个具体的对象:
Math.max.apply( null, [ 1, 2, 5, 3, 4 ] ) // 输出:5
call和apply的用途
确定函数内部this指向
var obj1={
name: '李小龙'
}
var obj2={
name: '萧薰'
}
window.name = 'window'
var getName = function(){
console.log(this.name)
};
getName(); //输出:window
getName.call(obj1); //输出:李小龙
getName.call(obj2); //输出:萧薰
当执行getName.call( obj1 )这句代码时,getName函数体内的this就指向obj1对象
- this 错误的情况
document.getElementById( 'div1' ).onclick = function(){
alert( this.id ); // 输出:div1
var func = function(){
alert ( this.id ); // 输出:undefined
}
func();
};
- 修正this
document.getElementById( 'div1' ).onclick = function(){
var func = function(){
alert ( this.id ); // 输出:div1
}
func.call( this );
};
bind(thisArgs [,args...])
bind是ES5 新增的一个方法,它的传参和call类似,但又和 call/apply 有着显著的不同,即调用 call 或 apply 都会自动执行对应的函数,而 bind 不会执行对应的函数,只是返回了对函数的引用。粗略一看,bind 似乎比call/apply 要落后一些,那ES5为什么还要引入bind 呢?
其实,ES5引入 bind 的真正目的是为了弥补 call/apply 的不足,由于 call/apply 会对目标函数自动执行,从而导致它无法在事件绑定函数中使用,因为事件绑定函数不需要我们手动执行,它是在事件被触发时由JS 内部自动执行的。而 bind 在实现改变函数 this 的同时又不会自动执行目标函数,因此可以完美的解决上述问题,看一个例子就能明白:
var obj = {name:'onepixel'};
/**
* 给document添加click事件监听,并绑定onClick函数
* 通过bind方法设置onClick的this为obj,并传递参数p1,p2
*/
document.addEventListener('click',onClick.bind(obj,'p1','p2'),false);
//当点击网页时触发并执行
function onClick(a,b){
console.log(
this.name, //onepixel
a, //p1
b //p2
)
}
参考JavaScript设计模式与开发实践 、 一像素 博客园
网友评论
function fruits() {}
fruits.prototype = {
color: "red",
say: function() {
console.log("My color is " + this.color);
}
}
var apple = new fruits;
apple.say(); //My color is red
banana = {
color: "yellow"
}
apple.say.call(banana); //My color is yellow
apple.say.apply(banana); //My color is yellow