javascript中call和apply的区别与联系
apply接收两个参数:
- 指定了函数体内this对象的指向;
- 一个带下标的集合(可以是数组或类数组)
var func = function(a, b, c){
console.log([a, b, c]); // 输出[1, 2, 3]
}
func.apply(null, [1, 2, 3]);
call接收一个或多个参数:
- 指定了函数体内this对象的指向;
- 从第二个参数往后,每个参数被依次传入函数;
var func = function(a, b, c){
console.log([a, b, c]); // 输出[1, 2, 3]
}
func.call(null, 1, 2, 3);
从上面的两个例子我们可以看出apply和call的唯一的区别就是:传入参数的数量是否固定。通常call在以下情况使用:
- 函数传入的参数数量确定;
- 需要清晰地表达形参和实参之间的对应关系
apply和call使用注意点:
- 如果传入的第一个参数是null,this就会指向全局对象,在浏览器上面是window,在nodejs上是global;
- 在1的条件下,如果使用严格模式,函数体内的this还是为null;
var func = function(a, b, c){
"use strict";
console.log(this === null); // 输出true
}
func.apply(null, [1, 2, 3]);
apply和call的用途:
- 借用其他对象的方法:
// 例一
Math.max.apply(null, [1, 2, 5, 3, 4]); // 输出5
// 例二
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'
- 改变this的指向:
var obj1 = {
name: 'sven',
};
var obj2 = {
name: 'anne',
};
global.name = 'global';
var getName = function(){
console.log(this.name);
}
getName(); // 输出:global
getName.call(obj1); // 输出:sven
getName.call(obj2); // 输出: anne
- Function.prototype.bind的模拟实现:
// 简单实现
Function.prototype.bind = function(context){
var self = this;
return function(){
return self.apply(context, arguments);
}
}
var obj = {
name: 'sven',
}
var func = function(){
console.log(this.name); // 输出:sevn
}.bind(obj);
func();
// 复杂实现
Function.prototype.bind = function(){
var self = this,
context = [].shift.call(arguments),
args = [].slice.call(arguments);
return function(){
return self.apply(context, [].concat.call(args, [].slice.call(arguments)));
}
}
var obj = {
name: 'sven',
};
var func = function(a, b, c, d){
console.log(this.name); // 输出:sven
console.log([a, b, c, d]); // 输出:[1, 2, 3, 4]
}.bind(obj, 1, 2);
func(3, 4);
本篇博客参考自JavaScript设计模式与开发实践,[p29-p33]