Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 52 期(W3C 标准-ECMAScript-上下文环境):模拟call方法 #55

Open
wingmeng opened this issue Jul 6, 2019 · 0 comments
Open

Comments

@wingmeng
Copy link
Collaborator

wingmeng commented Jul 6, 2019

ECMAScript 中的 call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
下面我们编写一个函数 myCall 来模拟 call 方法,以此加深对 call 的理解。

使用 ES6 实现,非常简单:

// 将 myCall 定义在 Function 原型链上,这样所有的函数都可以共享这个方法
// context 为当前上下文环境
Function.prototype.myCall = function(context, ...args) {
  // 当传入 null 或 undefined 时,指向 window
  context = context || window;

  // 【重点】
  // 在当前上下文环境下创建一个临时函数,赋值为 this(当前调用 myCall 的函数)
  // 用以将当前调用 myCall 的函数“借用”到当前上下文环境中
  context._fn = this;

  // 将形参传入临时函数,获得执行结果
  let result = context._fn(...args);

  // 过河拆桥,删除临时函数
  delete context._fn;
  return result;
}

call 方法是 ES1.3 就有了的,用 ES6 模拟未免有点……所以:

使用 ES3 实现:

Function.prototype.myCall = function(context) {
  // 创建一个数组来保存参数,即考虑 bar.call(obj, a, b, c) 这样存在多参数的场景  
  var args = [];

  context = context || window;
  context._fn = this;

  // 接着要处理传参的问题,例如有多个参数的情况
  // arguments 是函数中的隐式参数,保存着传递递给函数的实参,是一个伪数组(像数组却没有数组方法)
  // 注意这里的 i 是从 1 开始的,因为 arguments[0] 是 context,排除在外
  for (var i = 1; i < arguments.length; i++) {
    // 以形参的形式将参数保存到 args 数组中,供下一步使用
    args.push('arguments[' + i + ']');
  }

  // 【重点】
  // 现在我们需要把临时函数和参数以字符串的形式拼接起来,然后用 eval 执行
  // 为啥要用拼接的方式?因为 ES3 中无法给函数传递不定参数
  var result = eval('context._fn(' + args + ')');

  delete context._fn;
  return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant