javascript中call和apply的区别与联系

apply接收两个参数:

  1. 指定了函数体内this对象的指向;
  2. 一个带下标的集合(可以是数组或类数组)
var func = function(a, b, c){
    console.log([a, b, c]);  // 输出[1, 2, 3]
}

func.apply(null, [1, 2, 3]);

call接收一个或多个参数:

  1. 指定了函数体内this对象的指向;
  2. 从第二个参数往后,每个参数被依次传入函数;
var func = function(a, b, c){
    console.log([a, b, c]);  // 输出[1, 2, 3]
}

func.call(null, 1, 2, 3);

从上面的两个例子我们可以看出apply和call的唯一的区别就是:传入参数的数量是否固定。通常call在以下情况使用:

  1. 函数传入的参数数量确定;
  2. 需要清晰地表达形参和实参之间的对应关系

apply和call使用注意点:

  1. 如果传入的第一个参数是null,this就会指向全局对象,在浏览器上面是window,在nodejs上是global;
  2. 在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]