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

模拟实现call和apply #20

Open
chenqf opened this issue May 12, 2020 · 0 comments
Open

模拟实现call和apply #20

chenqf opened this issue May 12, 2020 · 0 comments

Comments

@chenqf
Copy link
Owner

chenqf commented May 12, 2020

模拟实现call和apply

简单介绍一下 call 和 apply

call、apply、bind三者均来自Function.prototype,被设计用来用于改变函数体内this的指向。

举个 call 的例子:

let foo = {
    value: 1
};

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

bar.call(foo);
// print: 1

在这个例子中,我们注意到 call 改变了 this 的指向,指向 foo ,并且 bar 函数执行了

call

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

func.apply(thisArg, [argsArray])
  • thisArg
    • 可选的参数,在 func 函数运行时使用的 this 值。
    • 注意,不一定是该函数执行时真正的 this 值,非严格模式下会出现一下情况
      • 指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),
      • 指定为原始值,会指向原始值对应的包装对象
  • argsArray
    • 可选的参数。一个数组或者类数组对象
    • 其中的数组元素的每一项将作为单独的参数传给 func 函数
    • 如果该参数的值为 null 或 undefined,则表示不需要传入任何参数
    • 从ECMAScript 5 开始可以使用类数组对象。

apply

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

  • thisArg
    • 可选的参数,在 func 函数运行时使用的 this 值。
    • 注意,不一定是该函数执行时真正的 this 值,非严格模式下会出现一下情况
      • 指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),
      • 指定为原始值,会指向原始值对应的包装对象
  • arg1,arg2,arg3,...
    • 可选的参数
    • 指定参数列表

简单模拟实现

在这里只考虑非严格模式下对call和apply的模拟实现,又由于Symbol没有对应的包装对象,在此不考虑Symbol类型作为this的情况

call 和 apply 都是改变了this的指向,让新的对象可以执行该函数。

那么我们的思路就变成给新的对象添加一个函数,然后在执行完以后删除。

实现如下:

Function.prototype.myCall = function(thisArg,...args) {
    // undefined null 时 thisArg 重置为window
    // 基本类型时 thisArg 重置为对应的包装对象
    if(thisArg === undefined || thisArg === null){
        thisArg = window;
    }else if(typeof thisArg === 'number'){
        thisArg = new Number(thisArg);
    }else if(typeof thisArg === 'string'){
        thisArg = new String(thisArg);
    }else if(typeof thisArg === 'boolean'){
        thisArg = new Boolean(thisArg);
    }
    //为thisArg设置fn属性,绑定当前函数
    thisArg.fn = this;
    //获取函数调用结果
    let result = thisArg.fn(...args);
    //删除临时增加的属性fn
    delete thisArg.fn;
    //返回最终结果
    return result;

};

Function.prototype.myApply = function(thisArg,args) {
    return this.myCall(thisArg,...args)
};
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