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

第 6 题:手写代码,简单实现call #6

Open
airuikun opened this issue Apr 8, 2019 · 8 comments
Open

第 6 题:手写代码,简单实现call #6

airuikun opened this issue Apr 8, 2019 · 8 comments

Comments

@airuikun
Copy link
Owner

airuikun commented Apr 8, 2019

Function.prototype.call2 = function(context) {
    var context = context || window; //因为传进来的context有可能是null
    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 + ")"); //相当于执行了context.fn(arguments[1], arguments[2]);

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

samonxian commented Apr 9, 2019

为什么用 eval 执行?下面的方式,不是更方便?

Function.prototype.call2 = function(context, ...args) {
  // 因为传进来的 context 有可能是 null
  context = context || window;
  // Function.prototype this 为当前运行的函数
  // 让 fn 的上下文为 context
  context.fn = this;

  const result = context.fn(...args);

  delete context.fn;

  return result;
};

function test(a, b, c) {
  console.log(this, a, b, c);
  return this;
}
test.call2({ test: 22 }, 1, 2, 3);

@jinggk
Copy link

jinggk commented Apr 15, 2019

同问,想请教下为什么在这里要采用eval的形式来执行函数?

@samonxian
Copy link

samonxian commented Apr 15, 2019

@jinggk 他这个是 es5 时代的写法,不支持 es6 之前没有 ... 这个语法,通过 eval 可以达到这种效果,如果通过 call,那就不算模拟 call 了。
即使现在通过 babel 转换,转换后的 es5 代码,说到底还是要用 call 或者 apply 实现的。
这道题的考点在于 this 上下文怎么绑定到目标函数,其他个人认为都是其次。

@airuikun
Copy link
Owner Author

@xianshannan @jinggk 是的 这题的最重要考点是this的指向性问题 使用eval固然性能不好 但是兼容性好 并且能达到实现本题的效果 但是用es6也是一个不错的方法 但是真正的call和apply可比这复杂得多 欢迎各种答案和想法交流

@jinggk
Copy link

jinggk commented Apr 16, 2019

嗯 试了一下 如果不用这种形式好像避不开 Array.prototype.slice.call(arguments) 这个问题

@NikFranki
Copy link

Function.prototype.call2 = function() {
var args = arguments;
var context = args[0] || window;
context.fn = this;
var newArr = [];
for(var i=0; i<args.length; i++) {
newArr.push(args[i]);
}
context.fn(newArr.slice(1).join(','));
delete context.fn;
}

var test = function(a, b) {console.log(a, b);}

test.call2({}, 1, 2);
// 1, 2
跟题主类似的
只是没有用eval去执行

@wjx25zj
Copy link

wjx25zj commented Feb 1, 2020

严格模式下 怎么处理 this 为null的情况?

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

6 participants
@samonxian @airuikun @NikFranki @jinggk @wjx25zj and others