手写JS面试题 --- call apply bind 实现

Posted lvhanghmm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写JS面试题 --- call apply bind 实现相关的知识,希望对你有一定的参考价值。

手写JS面试题 --- call apply bind 实现

题目描述:手写 call apply bind 实现

实现代码如下:

    Function.prototype.myCall = function (context, ...args) {
        if (!context || context === null) {
            context = window;
        }

        // 创建唯一的 key 值 作为我们构造的 context 内部方法名
        let fn = Symbol();
        context[fn] = this; // this 指向调用 call 的函数
        // 执行函数并返回结果 相当于把自身作为传入的 context 的方法进行调用了!
        return context[fn](...args);
    };

    // apply 原理一致 只是第二个传入的参数是一个数组!
    Function.prototype.myApply = function (context, args) {
        if (!context || context === null) {
            context = window;
        }

        // 创建唯一的 key 值 作为我们构造的 context 内部方法名
        let fn = Symbol();
        context[fn] = this;
        // 执行函数并返回结果!
        return context[fn](...args);
    };

    // bind 实现要复杂一点 因为他考虑的情景比较多 还要涉及到参数合并(类似函数柯里化)

    Function.prototype.myBind = function (context, ...args) {
        if (!context || context === null) {
            context = window;
        }

        // 创建唯一的 key 值 作为我们构造的 context 内部方法名!
        let fn = Symbol();
        context[fn] = this;
        let _this = this;
        // bind 情况要复杂一点
        const result = function (...innerArgs) {
            // 第一种情况 :若是将 bind 绑定之后的函数当作构造函数,通过 new 操作符使用,则不绑定传入的 this,而是将 this 指向实例化出来的对象
            // 此时由于new操作符作用  this指向result实例对象  而result又继承自传入的_this 根据原型链知识可得出以下结论
            // this.__proto__ === result.prototype // this instanceof result => true
            // this.__proto__.__proto__ = result.prototype.__proto__ === _this.prototype; // this instanceof _this => true
            if (this instanceof _this === true) {
                // 此时 this 指向 result 的实例 这时候不需要改变 this 指向
                this[fn] = _this;
                this[fn](...[...args, ...innerArgs]); // 这里使用 es6 的方法让 bind 支持参数合并
                delete this[fn];
            } else {
                // 如果只是作为普通的函数使用 那就很简单了 直接改变 this 指向为传入的 context
                context[fn](...[...args, ...innerArgs]);
                delete context[fn];
            }
        };
        // 如果绑定的是构造函数 那么需要继承构造函数原型的属性和方法
        // 实现继承的方式:使用 Object.create
        result.prototype = Object.create(this.prototype);
        return result;
    }

    // 用法如下:
    function Person(name, age) {
        console.log(name); //\'我是参数传进来的name\'
        console.log(age); //\'我是参数传进来的age\'
        console.log(this); //构造函数this指向实例对象
    }

    // 构造函数原型的方法
    Person.prototype.say = function() {
        console.log(123);
    }

    let obj = {
        objName: \'我是 obj 传进来的 name\',
        objAge: \'我是 objAge 传进来的 age\'
    }

    // 普通函数
    function normalFun(name, age) {
        console.log(name);   //\'我是参数传进来的name\'
        console.log(age);   //\'我是参数传进来的age\'
        console.log(this); //普通函数this指向绑定bind的第一个参数 也就是例子中的obj
        console.log(this.objName); //\'我是obj传进来的name\'
        console.log(this.objAge); //\'我是obj传进来的age\'

    }

    // 先测试作为构造函数的调用
    // let bindFun = Person.myBind(obj, \'我是参数传进来的name\')
    // let a = new bindFun(\'我是参数传进来的 age\')
    // a.say(); // 123

    console.log(\'------------------------\')

    // 在测试作为普通函数的调用!
    let bindFun = normalFun.myBind(obj, \'我是参数传进来的name\')
    bindFun(\'我是参数传进来的 age\')

以上是关于手写JS面试题 --- call apply bind 实现的主要内容,如果未能解决你的问题,请参考以下文章

前端JS面试题汇总 Part 3 (宿主对象与原生对象/函数调用方式/call与apply/bind/document.write)

js常见的面试题

JS手写面试题 --- 寄生组合继承

反复刷这些javascript面试手写题,我感觉我真的变强了

JavaScript手撕前端面试题:手写Object.create | 手写Function.call | 手写Function.bind

JS 手写之 Function.prototype.apply