JavaScript 系列 - Function.prototype.call

91 阅读1分钟

概念

function.call(thisArg, arg1, arg2, ...)  方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

  • thisArg

    • 在 func 函数运行时使用的 this 值。
    • 请注意,this 可能不是该方法看到的实际值:如果这个函数处于非严格模式下,null 或 undefined 自动替换为指向全局对象,原始值会被包装
  • argsArray 可选

    指定的参数列表

使用示例

使用 call 方法调用父构造函数

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = "food";
}

function Toy(name, price) {
  Product.call(this, name, price);
  this.category = "toy";
}

var cheese = new Food("feta", 5);
var fun = new Toy("robot", 40);

使用 call 方法调用匿名函数

var animals = [
  { species: "Lion", name: "King" },
  { species: "Whale", name: "Fail" },
];

for (var i = 0; i < animals.length; i++) {
  (function (i) {
    this.print = function () {
      console.log("#" + i + " " + this.species + ": " + this.name);
    };
    this.print();
  }).call(animals[i], i);
}

使用 call 方法调用函数并且指定上下文的 this

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

模拟

Function.prototype.myCall = function (context) {
  // 判断调用对象
  if (typeof this !== "function") {
    console.error("type error");
  }
  if (typeof context === "object") {
    context = context || window;
  } else {
    context = Object.create(null);
  }
  // 判断 context 是否传入,如果未传入则设置为 window
  //   context = context || window;
  // 将调用函数设为对象的方法
  context.fn = this;
  // 获取参数
  var args = [],
    result = null;
  for (var i = 1, len = arguments.length; i < len; i++) {
    args.push("arguments[" + i + "]");
  }
  // 调用函数
  result = eval("context.fn(" + args + ")");
  // 将属性删除
  delete context.fn;
  return result;
};

Function.prototype.myCall = function (context) {
  if (typeof this !== "function") {
    console.error("type error");
  }
  if (typeof context === "object") {
    context = context || window;
  } else {
    context = Object.create(null);
  }
  // 获取参数
  let args = [...arguments].slice(1),
    result = null;
  // 重新设定this
  let fn = Symbol();
  context[fn] = this;
  // 调用函数
  result = context[fn](...args);
  // 将属性删除
  delete context[fn];
  return result;
};