手撕代码系列(一):举一反三实现apply&call&bind

398 阅读2分钟

前言

applycallbind是显式绑定this的三种常用函数,也是面试最热门的考点。下面我们将从apply出发,带大家举一反三实现三种函数的简易版本

本文默认你已经了解以上三种函数的行为,若不了解可以请先上MDN查看详细函数说明。

apply的实现

/*
* thisArg为函数运行时要使用的this值
* args 为一个数组或者类数组对象,是调用函数时的参数列表
*/
Function.prototype.apply = function(thisArg,args){
    /*
    * 当thisArg为undefined或null时
    * 默认将thisArg指向window
    * 注意仅在非严格模式下会有这种行为
    */
    if (typeof thisArg === 'undefined' || thisArg === null){
        thisArg = window;
    }
    // 为了防止原来的属性被覆盖,用Symbol去创建一个独一无二的值
    const fnSymbol = Symbol();
    // 这里this指向调用apply的函数
    thisArg[fnSymbol] = this;
    // 调用函数并接收返回值
    const res = thisArg[fnSymbol](...args);
    // 最后删除这个临时属性
    delete thisArg[fnSymbol];
    // 返回值
    return res;
}

call的实现

实现call时只需要修改函数声明,注意这里使用了ES6的剩余参数,也可借助arguments去实现

- Function.prototype.apply = function(thisArg,args)
+ Function.prototype.call = function(thisArg,...args)

bind的实现

bind是一个高阶函数,它的实现可以借助之前的apply,下面给出最简的实现方式。

Function.prototype.bind = function(thisArg) {
    // 法一:保存一下this指向,这里的this指向调用bind的函数
    const self = this;
    return function(...args){
        return self.apply(thisArg,args);
    }
    // 法二:直接用箭头函数
    return (...args)=>this.apply(thisArg,args);		
}

后记

为了方便大家学习和记忆,上述源码都尽量以最简的形式进行呈现,在真正遇到面试的时候,大家只需牢记apply的实现便可以快速举一反三。同时,掌握它们的实现原理也是掌握this指向的关键。

关于我

喜欢聊天、喜欢分享、喜欢前沿的22届小菜鸡,初来乍到希望得到各位大佬的关注。能有实习/校招机会就更好啦!
个人公众号:鼠子的前端CodeLife