call&apply&bind小结

719 阅读3分钟

一、方法定义

call方法

语法: call([thisObj[,arg1[, arg2[, [,.argN]]]]])

定义: 调用一个对象的一个方法,以另一个对象替换当前对象。

说明: call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。 arg1 … argN为被调用方法的传参。

function numAdd( a, b ) {
    console.log(this);
    console.log(a + b, "123456");
}

function numPow( a, b ) {
    console.log(this);
    console.log(Math.pow(a, b), "xxxxxx")
}

//把numAdd方法放在numPow上执行
//this指向numPow
numAdd.call(numPow, 3, 4);          // 7
//把numPow方法放在numAdd上执行
//this指向numAdd
numPow.call(numAdd, 3, 4);          // 81

Object.prototype.toString.call(numAdd)


apply方法

语法: apply([thisObj[,argArray]])

定义: 应用某一对象的一个方法,用另一个对象替换当前对象。

说明: apply的第一个参数thisObj和call方法的一样,第二个参数argArray为一个传参数组。thisObj如果未传,那么 Global 对象被用作 thisObj。

function add( a, b ) {
    console.log(this);
    console.log(a + b, "123456");
}

function pow( a, b ) {
    console.log(this);
    console.log(Math.pow(a, b), "xxxxxx")
}

//把numAdd方法放在numPow上执行
//this指向pow
add.apply(pow, [ 3, 4 ]);;          // 7
//把numPow方法放在numAdd上执行
//this指向add
pow.apply(add, [ 3, 4 ]);          // 81

bind方法 ECMAScript5中扩展了叫bind的方法(IE6,7,8不支持)

语法: bind([thisObj[,arg1[, arg2[, [,.argN]]]]])

定义: 应用某一对象的一个方法,用另一个对象替换当前对象。

说明: bind的thisObj参数也和call方法一样,thisObj如果未传,那么 Global 对象被用作 thisObj。arg1 … argN可传可不传。如果不传,可以在调用的时候再传。如果传了,调用的时候则可以不传,调用的时候如果你还是传了,则不生效。

function add( a, b ) {
    console.log(this);
    console.log(a + b, "123456");
}

function pow( a, b ) {
    console.log(this);
    console.log(Math.pow(a, b), "xxxxxx")
}

//把add方法放在pow上执行
//this指向pow
aadd.bind(pow)( 3, 4);          // 7
//把pow方法放在add上执行
//this指向add
pow.bind(add)( 3, 4);          // 81

二、call,apply,bind的相似

  1. 都是用来改变函数this指向的

  2. 第一个参数都是this要指向的对象

  3. 都可以传参

三、call,apply,bind的区别

  1. callapply都是对函数的直接调用

  2. bind返回的是一个函数,需要配合()进行调用

  3. callbind的传参使用,分隔的 例如(item1,item2,item3...)

  4. apply的传参使用数组[...arguments]

四、简单实现call

Function.prototype.selfCallWithEs5 = function (context) {
  var context = context || window;
  context.fn = this;
  var args = [];
  for (var i = 1; i < arguments.length; i++) {
    args.push("arguments[" + i + "]");
  }
  args = args.join(",");

  var result = eval("context.fn(" + args + ")");

  delete context.fn;
  return result; //因为有可能this函数会有返回值return
}

Function.prototype.selfCallWithEs6 = function (context, ...args) {
  context = context || window;
  context.fn = this;
  const result = context.fn(...args);
  delete context.fn;
  return result;
};

五、简单实现apply

Function.prototype.selfApplyWithEs5 = function (context, arr) {
  var context = context || window;
  context.fn = this;
  var args = [];
  var params = arr || [];
  for (var i = 0; i < params.length; i++) {
    args.push("params[" + i + "]");
  }
  args = args.join(",");
  var result = eval("context.fn(" + args + ")");

  delete context.fn;
  return result; //因为有可能this函数会有返回值return
}

Function.prototype.selfApplyWithEs6 = function(context, arr) {
  context = context || window;
  context.fn = this;
  arr = arr || [];
  const result = context.fn(...arr);
  delete context.fn;
  return result;
}

六、简单实现bind

Function.prototype.selfBindWithEs5 = function (context) {
  var _this = this;
  var argsParent = Array.prototype.slice.call(arguments, 1);
  return function () {
    var args = argsParent.concat(Array.prototype.slice.call(arguments)); //转化成数组
    _this.apply(context, args);
  };
}

Function.prototype.selfBindWithEs6 = function (context) {
  var fn = this;
  var argsParent = [...arguments];
  return function () {
    fn.call(...argsParent, ...arguments);
  };
}