JS中的call、apply、bind

在JavaScript中,call、apply和bind 是Function对象自带的三个方法,这三个方法的共同点:

  1. 都是用来改变函数的this对象的指向的。
  2. 第一个参数都是this要指向的对象。
  3. 都可以利用后续参数传参。

定义

call

语法 :fun.call(thisArg, arg1, arg2, ...)

call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表) 。

可以让call()中的对象调用当前对象所拥有的function。可以使用call()来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)。

apply

语法:fun.apply(thisArg, [argsArray])

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数。

在调用一个存在的函数时,你可以为其指定一个 this 对象。 this 指当前对象,也就是正在调用这个函数的对象。 使用 apply, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。

bind

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

语法:fun.bind(thisArg[, arg1[, arg2[, ...]]])

bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call。当新函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

区别

call和apply的区别

他们俩之间的差别在于参数的区别,call和aplly的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。

1
2
3
4
5
6
function hello(name,age){
console.log(name);
console.log(age);
}
hello.call(this,"tsrot",24);
hello.apply(this,["tsrot",24]);
call, apply与bind的差别

call 和 apply 改变了函数的 this 上下文后便执行该函数, 而 bind 则是返回改变了上下文的一个函数

1
2
3
4
5
6
7
8
9
10
11
var obj = {
x: 81,
};
var foo = {
getX: function() {
return this.x;
}
}
console.log(foo.getX.bind(obj)());
console.log(foo.getX.call(obj));
console.log(foo.getX.apply(obj));

运用场景

实现继承

1
2
3
4
5
6
7
8
9
10
11
function Animal(name) {
this.name = name;
this.showName = function () {
console.log(this.name);
}
}
function Cat(name) {
Animal.call(this, name);
}
var cat = new Cat('Black Cat');
cat.showName();

数组追加

1
2
3
4
5
6
7
8
9
10
var arr1 = [1,2,3]
var arr2 = [4,5,6]

[].push.apply(arr1, arr2)
// 使用一个辅助的空数组(为了访问非静态方法),就是把arr2利用apply的数组参数特性push到arr1中.
// 这样通过解构可以写成 arr1.push(...arr2), 如果需要返回一个全新的对象,还可以使用 [...arr1, ...arr2]。
// 还可以写成var newArr = arr1.concat(arr2)

// arr1 [1, 2, 3, 4, 5, 6]
// arr2 [4,5,6]

将伪数组转化为数组

js中的伪数组具有length属性,并且可以通过0、1、2…下标来访问其中的元素,但是没有Array中的push、pop等方法。我们可以利用call、apply来将其转化为真正的数组这样便可以方便地使用数组方法了。

1
2
3
4
5
6
7
8
9
10
var arrayLike = {
0: 'shifeng',
1: 'xingyun',
2: 'ruxue',
length: 3
}

var arr = Array.prototype.slice.call(arrayLike)
// 上面arr便是一个包含arrayLike元素的真正的数组啦.
// 注意数据结构必须是以数字为下标而且一定要有length属性!