手写bind

168 阅读1分钟

前置知识: this/原型/apply/call/bind

什么bind

bind是函数身上共有的方法,Fcuntion.prototype.bind,如果你了解原型应该就懂这句代码
bind不同与call与apply的是:返回一个新的函数并且指向该this,并不会直接调用

确定需求

为一个函数指定this并且返回一个新的函数,并且可以new

无废话版(es6无注释版)

function bind(newThis, ...args) {
    const fn = this
    function newFn(...args2) {

        return fn.call(this instanceof newFn ? this : newThis, ...args, ...args2)
    }
    newFn.prototype = fn.prototype
    return newFn
}

废话版(es5 有注释)

var slice = Array.prototype.slice
function bind(newThis) {
    var bindParams = slice.call(arguments, 1)//返回bind不包含newThis的其余参数,因为第一个参数是用来绑定新的this的嘛
    var fn = this //记录bind调用时的this,而this是什么取决于谁调用它,所以你能想到this就是你要修改this的那个函数吗 (这句是最难的,需要你对this了解的很清楚)
    function newFn() {
        var newFnParams = slice.call(arguments, 0)//这里拿到的是newFn的参数 因为参数是伪数组所以需要转成数组
        return fn.apply(newFn.prototype.isPrototypeOf(this)?this:newThis,bindParams.concat(newFnParams))//看不懂就把这句注释掉,把下面4句取消注释看看
        // var usedNew = newFn.prototype.isPrototypeOf(this)//如果是用了关键字这个方法会返回true
        // var endThis = usedNew ? this : newThis// 如果是用了new关键字那就应该返回new中的this,要没使用就应该返回bind传进来的this
        // var allParams = bindParams.concat(newFnParams) // 合并bind调用接受的参数,还有newFn调用时候的参数
        // return fn.apply(endThis, allParams) //这句就不解释了,加这么多中间变量,你要看不懂,我会哭的
        
    }
    newFn.prototype = fn.prototype //确保原型地址一致
    return newFn
}

github链接