JS模拟实现call,apply,bind

论坛 期权论坛 脚本     
已经匿名di用户   2021-12-20 01:36   3404   0

前言

我相信对于call,applay,bind三者之前的用法与区别,小伙伴们肯定都很清楚了,毕竟这也是面试的高频试题,之前面试的时候,当面试官提到call的时候我可是心花怒放,正准备侃侃而谈的时候,面试官说请用js模拟call的用法,限时5分钟。当时就懵了,脑子里只有它的各种用法,但内部究竟如何实现的,还真没有研究过,当时就唱了一首凉凉给自己。失败不可怕,所以今天特写文一篇,纪念自己逝去的面试。

Call

改变函数的执行上下文,相当于将某个函数的指定于特定的对象下执行

Function.prototype.call = function (context) {
    let context = context || window;
    context.fn = this;
    let args = [];
    for(let i = 1, len = arguments.length; i < len; i++) {
        let temp = 'arguments['+ i +']';
        args.push(temp);
    }
    let result = eval('context.fn(' + args +')'); // 这里会主动调用Arrary.toString()方法
    delete context.fn;
    return result;
}

Apply

Function.prototype.apply = function (context, arr) {
    let context = Object(context) || window;
    context.fn = this;
    let result;
    if (!arr) {
        result = context.fn();
    } else {
        let args = [];
        for (let i = 0, len = arr.length; i < len; i++) {
            args.push('arr['+ i +']');
        }
        result = eval('context.fn(' + args + ')')
    }
    delete context.fn;
    return result;
}

bind

bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。即bind函数的特点是:返回一个函数,可以传入参数。而且一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

Function.prototype.bind2 = function (context) {

    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);

    var fNOP = function () {};
    fNOP.prototype = this.prototype;

    var fBound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
    }

    fBound.prototype = new fNOP();
    return fBound;
}

New——参考链接

function objectFactory() {
    var obj = new Object(),

    Constructor = [].shift.call(arguments); // 取出第一个参数,即是我们要传入的构造函数。此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数

    obj.__proto__ = Constructor.prototype;  // Object.setPrototypeOf(obj, Constructor.prototype)
    // 上述步骤是为了指向正确的原型,还可以使用空函数来中转实现
    // var Fn = new Function();
    // Fn.prototype = Constructor.prototype;
    // obj = new Fn();

    var ret = Constructor.apply(obj, arguments);

    return typeof ret === 'object' ? ret||obj : obj;  //确保构造器总是返回一个对象
};

【注意】参考文档:https://github.com/mqyqingfeng/Blog/issues/11

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP