call(),apply()

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

call和apply只是接收参数上的不同

用法(MDN)

fun.call(thisArg, arg1, arg2, ...)

thisArg

在fun函数运行时指定的this值。需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于non-strict mode,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。

arg1, arg2, ...

指定的参数列表。

function greet() {
  var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
  console.log(reply);
}

var obj = {
  animal: 'cats', sleepDuration: '12 and 16 hours'
};

greet.call(obj);  // cats typically sleep between 12 and 16 hours

上面例子中当用call调用greet方法的时候,该方法的this值会绑定到obj对象。
我们来分析下call做了哪些事情:

  1. greet函数执行了;
  2. greet执行上下文中的this被改成了obj

下面我们来动手实现一下:

const obj = {
  name: '111',
  fn: function(){
    console.log(this.name);
  }
}
// 我们知道fn中的this 就是调用它的obj
obj.fn()


// 在Function原型上添加我们的方法
Function.prototype.myCall = function(ctx, ...args){
  //这里用Symbol以免覆盖了属性
  const key = Symbol('fn');
  /**
   * call的第一个参数如果为null和undefined时this值会自动指向全局对象(浏览器中就是window对象),
   * 同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象,原生的call会用Object包装一下。
   */
  ctx = ctx ? Object(ctx) : window;
  /**
   * 这里的this就指向调用的调用call的函数,上例中就是greet
   * 所以我们在实现的时候只要将call的第一个参数挂到greet中的某一个属性中去就可以了
   */
  ctx[key] = this;
  // 这里调用并将参数传给 this函数
  const result = ctx[key](...args);
  // 调用完成后将刚刚挂在的属性删除
  delete ctx[key];
  return result;
}
// 测试一下
greet.myCall(obj);  // cats typically sleep between 12 and 16 hours

bind()

bind和call的区别是call会被立即调用执行,而bind则返回的是一个改变了执行上下文的函数。

function greet() {
  var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
  console.log(reply);
}

var obj = {
  animal: 'cats', sleepDuration: '12 and 16 hours'
};

greet.call(obj);  // cats typically sleep between 12 and 16 hours
greet.bind(obj)(); // cats typically sleep between 12 and 16 hours

我们用call来实现

Function.prototype.myBind = function(ctx, ...args){
  const self = this;
  // 返回一个函数
  return function(){
   // 用call去调用并返回结果
    return self.call(ctx, ...args);
  }
}

标签: js

评论

我们在初始化一个构造函数实例时,需要用new操作符去初始化实例,那么我们在new 一个构造函数的时候new到底为我们做了什么呢?