call()、apply()、bind()都是函数对象的一个方法,目的是改变函数中this的指向。
一. 作用
通常的函数有两种,一种是独立的函数,另一种是作为对象的一个方法。
作为对象方法的时候,函数中的this指的是调用它的对象。如果是独立函数,通常不用使用this。
call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他对象有,我们可以借助call或apply用其它对象的方法来操作。
例如
var cat={
food:"fish",
eat: function(){
alert("I eat "+this.food);
}
}
var dog = {food:"bone"};
cat.eat.call(dog);
翻译成通俗的方式来理解就是:猫可以吃鱼,现在有一只狗也想吃,那么猫.吃鱼.call(狗),这样狗就可以吃到了。
二. 参数说明
第一个参数:指定将要调用此函数的对象,即this的指向,如果没有,则默认为全局对象window
第二个参数:被调用函数的传参
三. 区别
- call传参需要一个个传,apply直接传一个数组
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2]);
当你的参数是明确知道数量时,用 call,而不确定的时候,用 apply,然后把参数 push 进数组传递进去。
当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。
- call和apply直接执行函数,bind需要再调用一次
bind是用来绑定this指向,返回一个原函数被绑定this后的新函数
例如:
var obj = {
x: 81,
}
var foo = {
getX: function(){
return this.x;
}
}
console.log(foo.getX.bind(obj)());//81
console.log(foo.getX.call(obj)); //81
console.log(foo.getX.apply(obj)); //81
- bind的第二个参数不传时,可以调用的时候传。如果传了,调用时就不用传,如果调用时也传了,则不生效。
例如:
var person = {
name:"tt",
age:24,
sayHello:function(age){
console.log(this.name);
console.log(age);
}
};
var son = {
name:"cc"
};
var boundFunc = person.sayHello.bind(son);
boundFunc(25); // cc 25
var boundFunc = person.sayHello.bind(son,25);
boundFunc(); // cc 25
var boundFunc = person.sayHello.bind(son,25);
boundFunc(30); // cc 25
四. 应用
1. 实现继承
function Animal(type) {
this.type = type;
}
function Bird(type, color) {
Animal.call(this, type);
this.color = color;
}
var bird = new Bird('bird', 'green');
console.log(bird); // Bird { type: 'bird', color: 'green' }
2. 合并数组
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
Array.prototype.push.apply(arr1, arr2);
console.log(arr1); // [1, 2, 3, 4, 5, 6]
3. 获取数组的最大值,最小值
var num = [1,3,5,7,2,-10,11];
var maxNum = Math.max.apply(null, num);
var minNum = Math.min.apply(null, num);
console.log(maxNum); //11
console.log(minNum); //-10
4. 将伪数组转换为数组
var Arr = {0:'a',1:'b',length:2};
var arr1 = Array.prototype.slice.call(Arr);
console.log(arr1[0]); //a
var arr2 = [].slice.call(Arr);
console.log(arr2[0]); //a
arr1.push("c");
console.log(arr1); //["a", "b", "c"]
Array.prototype.slice.call() 是什么?
Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组,就是arguments.toArray().slice();
slice有两个用法,一个是String.slice,返回字符串,一个是Array.slice,返回数组。
推测一下slice的实现:
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length; //this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
}
5. 保存this 变量
// 正常情况下使用变量保存 this 值
var foo = {
bar : 1,
eventBind: function(){
var _this = this ;
$('.someClass').on('click',function(event) {
console.log(_this.bar); //1
});
}
}
// 使用 bind 进行函数绑定
var foo = {
bar : 1,
eventBind: function(){
$('.someClass').on('click',function(event) {
console.log(this.bar); //1
}.bind(this));
}
}