2.new、apply、bind、call的模拟实现

2020-07-03  本文已影响0人  原来哥哥是万家灯火

1.new的模拟实现

function mockNew(constructor, argsArr) {
   var obj = {};
   obj.__proto__ = constructor.prototype;
   let result = constructor.apply(obj, argsArr);
   if (result instanceof Object) {
      return result;
   }
   return obj;
}

2.apply的模拟实现

原理很简单,将函数赋值成context的方法,调用函数,删除方法,返回值

Function.prototype.mockApply = function(context, argsArr) {
    var fn = this;
    var argReferenceArr = [];

    var globalContext = (typeof window === 'undefined')? global: window;
    context = (context instanceof Object)? context: globalContext;

    for (var i=0,len = argsArr.length; i<len; i++) {
        argReferenceArr.push('argsArr[' + i + ']')
    }

    context.f = fn;

    var result  = eval('context.f(' + argReferenceArr.toString() + ')');
    delete context.f;
    return result;
}

3.call的模拟实现

Function.prototype.mockCall = function(context) {
    var fn = this;
    var argReferenceArr = [];

    var globalContext = (typeof window === 'undefined')? global: window;
    context = (context instanceof Object)? context: globalContext;

    for (var i=1,len = arguments.length; i<len; i++) {
        argReferenceArr.push('arguments[' + i + ']')
    }

    context.f = fn;

    console.log(argReferenceArr)
    var result  = eval('context.f(' + argReferenceArr.toString() + ')');
    delete context.f;
    return result;
}

4.bind的模拟实现
bind相对复杂点,其参数可以分两次传递,如:f.bind(o, arg1)(arg2)
另还可以当做构造函数调用,生成的实例的构造函数是f,如:

function Human(name, age) { 
    this.name = name; 
    this.age = age; 
}

let f = Human.bind(null, '张三');
let man = new f(20);
console.log(man.contructor); 
打印结果:构造函数是Human  

模拟实现如下:

Function.prototype.mockBind = function (context) {
    var fn = this;

    var outerArgs = [];
    var outerArgsReference = [];

    var globalContext = (typeof window === 'undefined') ? global : window;
    context = (context instanceof Object) ? context : globalContext;

    for (var i = 1, len = arguments.length; i < len; i++) {
        outerArgs[i-1] = arguments[i];
        outerArgsReference[i-1] = 'outerArgs[' + (i-1) + ']';
    }


    function bound () {
        var innerArgsReference = [];

        for (var i = 0, len = arguments.length; i < len; i++) {
            innerArgsReference[i] = 'arguments[' + i + ']';
        }

        var args = outerArgsReference.concat(innerArgsReference).toString();
        context = this instanceof fn? this: context;
        context.fn = fn;
        var result =  eval('context.fn(' + args +')');
        delete context.fn;
        return result;
    }

    function F() {}
    F.prototype = fn.prototype;
    bound.prototype = new F();

    return bound;
}

调用apply简化版:

Function.prototype.mockBind = function (context) {
    var fn = this;
    var outerArgs = Array.prototype.slice.apply(arguments, [1]);

    function bound () {
        var innerArgs = [].slice.apply(arguments, [0]);
        return fn.apply(this instanceof fn? this: context, outerArgs.concat(innerArgs));
    }

    function F() {}
    F.prototype = fn.prototype;
    bound.prototype = new F();

    return bound;
}
上一篇下一篇

猜你喜欢

热点阅读