[ apply-bind-call 思考 下 | 青训营笔记]

67 阅读3分钟

JavaScript中的apply,bind和call是三个非常重要的函数,它们允许您在调用函数时指定this关键字的值,并以一种非常方便的方式将参数传递给函数。虽然这些函数可以很容易地通过库或框架来使用,但了解如何手动实现它们有助于您更深入地了解JavaScript函数的内部工作原理。

call函数是最简单的函数之一,它允许您以指定的this值调用函数,并传递任意数量的参数。例如,以下是调用函数并将this设置为obj的示例:

function myFunction(arg1, arg2) {
  console.log(this.name + " " + arg1 + " " + arg2);
}

var obj = { name: "John" };
myFunction.call(obj, "hello", "world");

在上面的示例中,call函数使我们能够将myFunction函数的this值设置为obj,并将“hello”和“world”作为参数传递给该函数。

接下来是apply函数,它与call函数非常相似,但是它要求您将参数作为数组传递,而不是作为单独的参数。以下是使用apply函数调用上述示例函数的示例:

myFunction.apply(obj, ["hello", "world"]);

在这个例子中,我们将["hello", "world"]作为数组传递给apply函数,它会将数组中的每个元素作为myFunction函数的参数。

最后是bind函数,它是在ES5中引入的,它允许您创建一个新函数,该函数的this值永久地绑定到指定值。以下是创建新函数并将其this值绑定到obj的示例:

var boundFunction = myFunction.bind(obj);
boundFunction("hello", "world");

在上面的示例中,我们使用bind函数创建了一个新函数boundFunction,该函数的this值绑定到obj。然后,我们调用boundFunction并传递“hello”和“world”作为参数。

虽然以上这些函数看起来很简单,但它们的实现可能会有点复杂。以下是apply和call函数的手写实现:

Function.prototype.myApply = function(thisArg, argsArray) {
  if (typeof this !== "function") {
    throw new TypeError("Function.prototype.myApply - 调用对象不是函数");
  }
  var result;
  if (!thisArg) {
    result = this();
  } else {
    result = thisArg.myTempFn(argsArray);
  }
  delete thisArg.myTempFn;
  return result;
};

Function.prototype.myCall = function(thisArg) {
  var argsArray = [];
  for (var i = 1; i < arguments.length; i++) {
    argsArray.push(arguments[i]);
  }
  return this.myApply(thisArg, argsArray);
};

在上面的示例中,我们将myApply函数添加到Function.prototype对象中,并使用它来实现myCall函数。myApply函数首先检查调用对象是否为函数,然后根据是否传递了this值来确定要调用哪个函数。如果没有传递this值,则直接调用该函数;否则,将该函数作为this值的属性存储在一个临时对象中,然后再调用该函数并将参数数组传递给它。最后,删除临时对象并返回函数的结果。

下面是bind函数的手写实现:

Function.prototype.myBind = function(thisArg) {
  var func = this;
  var argsArray = Array.prototype.slice.call(arguments, 1);
  return function() {
    var boundArgsArray = Array.prototype.slice.call(arguments);
    return func.apply(thisArg, argsArray.concat(boundArgsArray));
  };
};

在上面的示例中,我们将myBind函数添加到Function.prototype对象中,并使用它来创建一个新函数。myBind函数首先将当前函数存储在func变量中,然后将要绑定的this值存储在thisArg变量中。接下来,将第二个参数开始的所有参数作为参数数组存储在argsArray变量中。最后,创建一个新函数并返回它,该函数将绑定的参数和调用时传递的参数组合起来,并调用原始函数。

综上所述,JavaScript中的apply,bind和call函数非常有用,可以帮助您以不同的方式调用函数,并使您能够更好地控制函数的this值。尽管这些函数已经包含在JavaScript库和框架中,但了解它们的工作原理和手动实现它们有助于您更好地理解JavaScript函数的内部工作原理。