手动实现js中call、apply、bind方法

1,215 阅读1分钟

一:call方法

  1. es6实现
Function.prototype.myCall = function(content, ...args){
    content = content || window;
    content.fn = this;
    const res = content.fn(...args);
    delete content.fn;
    return res;
};
  1. es5实现
Function.prototype.myCall = function (context) {
    context = context || window;
    context.fn = this;
    var args = [];
    for(let i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }
    var result = eval('context.fn(' + args +')');
    delete context.fn;
    return result;
}

二:apply方法

  1. es6实现
Function.prototype.myApply = function (content, args) {
    content = content || window;
    content.fn = this;
    const res = content.fn(...args);
    delete content.fn;
    return res;
};
  1. es5实现
Function.prototype.myApply = function (content, arr=[]) {
    content = content || window;
    content.fn = this;
    var args = [];
    for(var i=0; i<arr.length; i++){
        args.push("arr["+i+"]")
    }
    var res = eval("content.fn("+args+")");
    delete content.fn;
    return res;
};

三:bind方法

注意点:bind返回的函数可通过new实例化(需要确保bind后的函数与原函数在同一原型链)

Function.prototype.myBind = function (content) {
    const args = Array.prototype.slice.call(arguments, 1);  // bind层参数
    const func = this;
    const bindFunc = function () {
        func.apply(content, args.concat([...arguments]))  
    };
    bindFunc.prototype = Object.create(func.prototype);
    return bindFunc
};

四:上面用到了Object.create方法

简单实现:

Object.create = function(proto){
    function F() {};
    F.prototype = proto;
    F.prototype.constructor = F;
    return new F();
}

五:实现call,apply存在小瑕疵

 content.fn = this;  // 原来对象中可能就存在 fn 属性,会存在覆盖
 
 /* ---> 替换  */
 const fn = Symbol("fn");
 content[fn] = this;