从实现原理更深入了解call和apply

一、原理的粗糙实现

1. call
Function.prototype.call = function(x){
  x = x || '{}';
  x.fn = this;
  var i;
  var args = [];
  for(i = 1;  i < arguments.length; i++){
    args.push(arguments[i]);
  }
  var func = function(thisArg, args){
    var str = args.join(',');
    return thisArg.fn(str);
  }
  var result = func(x, args);
  delete x.fn;
  return result;
} 
2. apply
Function.prototype.apply = function(){
  x = x || '{}';
  x.fn = this;
  var i;
  var args = [];
  for(i = 0;  i < arguments[1].length; i++){
    args.push(arguments[1][i]);
  }      
  var func = function(thisArg, args){
    var str = args.join(',');
    return thisArg.fn(str);
  }
  var result = func(x, args);
  delete x.fn;
  return result;
}

二、以apply为例讲解实现的过程

假设现在有cat和dog两个对象:

var cat = {
    name: 'cat',
    printName: function(){
        console.log(this.name);
    }
}
var dog = {
    name: 'dog'
}

使用上面的apply:

cat.printName.apply(dog); // dog

现在分析代码的执行过程:

  1. 调用apply函数进入apply函数内部
  2. x.fn = this 就是 dog.fn = cat.printName
  3. 执行x.fn(); 输出this.name,而此时this为dog,所以代码输出dog

三、重新看之前的Function.prototype.call.apply(null, arguments)

那么它的执行过程就是:

  1. 调用apply函数进入apply函数内部
  2. x = null || {} 将 x变成{}
  3. x.fn = this 就是 {}.fn = Function.prototype.call
  4. 执行x.fn(arguments); 就是{}.call(arguments);
  5. 进入call内部
  6. x.fn = this 就是 arguments[0].fn = {}
  7. 执行x.fn(arguments[1-n]) 由于fn={}不是函数,所以报错

总结:call和apply需要由函数来调用,不能使用对象调用call和apply

参考文章:
https://blog.csdn.net/THEANARKH/article/details/54393176

原文地址:https://www.cnblogs.com/githubMYL/p/9580788.html