call、apply:
在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
call可以传递一个thisArgs参数和一个参数列表,thisArgs 指定了函数在运行期的调用者,也就是函数中的 this 对象,而参数列表会被传入调用函数中。thisArgs 的取值有以下4种情况:
- 不传,或者传null,undefined, 函数中的 this 指向 window 对象
- 传递另一个函数的函数名,函数中的 this 指向这个函数的引用
- 传递字符串、数值或布尔类型等基础类型,函数中的 this 指向其对应的包装对象,如 String、Number、Boolean
- 传递一个对象,函数中的 this 指向这个对象
function a() {
console.log(this); //输出函数a中的this对象
}
function b() {} //定义函数b
var obj = {
name: 'hehe'
}; //定义对象obj
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 的核心功能,它允许你在一个对象上调用该对象没有定义的方法,并且这个方法可以访问该对象中的属性。
function animals() {}
animals.prototype = {
type: "dog",
say: function() {
console.log("I am a " + this.type);
}
}
var dog = new animals();
dog.say(); //I am a dog
var cat = {type:'cat'};
dog.say.call(cat); //I am a cat
因此,可以看出 call 和 apply 是为了动态改变 this 而出现的,当一个 object 没有某个方法(本栗子中cat没有say方法),但是其他的有(本栗子中dog有say方法),我们可以借助call或apply用其它对象的方法来操作。
apply、call 的区别
对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。
对象.函数名.call(thisArgs, arg1, arg2);
对象.函数名.apply(thisArgs, [arg1, arg2])
其中 this 是你想指定的上下文,他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
* bind*
bind是ES5 新增的一个方法,它的传参和call类似,但又和 call/apply 有着显著的不同,即调用 call 或 apply 都会自动执行对应的函数,而 bind 不会执行对应的函数,只是返回了对函数的引用。
MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
var obj = {
id : 1,
eventBind: function(){
var _this = this;
$('.btn').on('click',function(event) {
alert(this.id); //undefined
alert(_this.id); //1
});
}
}
obj.eventBind();//没有这句话,click事件不执行
由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到 $(‘.btn’).on(‘click’,function(event) { }) 发生了改变,上述使用变量保存 this 这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:
var obj = {
id : 1,
eventBind: function(){
$('.btn').on('click',function(event) {
alert(this.id); //1
}.bind(this));
}
}
obj.eventBind();//没有这句话,click事件不执行
call、apply和bind的区别
var obj = {
x: 77,
};
var foo = {
getX: function() {
return this.x;
}
}
console.log(foo.getX.bind(obj)()); //77
console.log(foo.getX.call(obj)); //77
console.log(foo.getX.apply(obj)); //77
三个输出的都是77,但是注意使用 bind() 方法后面多了对括号。
也就是说,区别就是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法;而 apply/call 则会立即执行函数。