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

Build your own call & apply #3

Open
xchunzhao opened this issue Mar 25, 2019 · 0 comments
Open

Build your own call & apply #3

xchunzhao opened this issue Mar 25, 2019 · 0 comments

Comments

@xchunzhao
Copy link
Owner

自己动手实现call

根据MDN上的定义

call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。

例如:

var foo = {
    value: 1
};

function bar() {
    console.log(this.value);
}

bar.call(foo); // 1

那要明确的是call做了哪几件事:

  • 改变了this指向
  • 函数执行了

如何改变this指向?

试想执行call的时候,将foo改造成这样:

var foo = {
    value: 1,
    bar: function(){
        console.log(this.value)
    }
}

这样就改变了this的指向。但存在的问题是foo会多出一个属性。那使用delete即可。

所以call的过程可以分为以下三个阶段:

  • 将函数设为对象的属性
  • 执行函数
  • 删除该函数属性
Function.prototype.call = function(context) {
    context.fn = this;
    var args = [];
    // index=0的是context
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }
    var result = eval('context.fn(' + args +')');
    delete context.fn;
    return result;
}

同理apply类似。只是apply接受的是参数数组。

Function.prototype.apply = function(context, arr) {
    context.fn = this;
    var result;
    if(!arr) {
        result = context.fn(); 
    }else {
        var args = [];
        for(var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        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
Projects
None yet
Development

No branches or pull requests

1 participant