# bind、call、apply 实现

# call

// 会出现number => string的情况
Function.prototype.myCall = function (context) {
    // content 表示绑定的对象,为null的时候指向window
    var context = context || window
    // this指向函数
    context.fn = this
    // 参数
    var args = []
    // 第一个参数是context
    for(var i = 1;i<arguments.length; i++){
        args.push(`arguments[${i}]`)
    }
    // 执行完之后,args = [arguments[1],arguments[2]...]

    // 执行
    // `context.fn(${args})` 中的args会调用 toString方法
    var value = eval(`context.fn(${args})`)
    delete context.fn
    return value
}

# apply

Function.prototype.myApply = function (context,arr) {
    // arr 表示参数为数组,可为空,也可采用arguments[1]获取

    // content 表示绑定的对象,为null的时候指向window
    var context = context || window
    // this指向函数
    context.fn = this
    // value 为返回值
    var value
    if(!arr || !arr.length){
        value = context.fn()
    } else {
         // 参数
        var args = []
        // 第一个参数是context
        for(var i = 0;i<arr.length; i++){
            args.push(`arr[${i}]`)
        }
        // 执行
        value = eval(`context.fn(${args})`)
    }
    delete context.fn
    return value
}

# bind

 // 创建新函数,调用新函数的时候,bind的第一个参数作为运行时的this。
Function.prototype.myBind = function(context){
    // this指向当前函数
    var self = this
    // 绑定时传参
    var args = Array.prototype.slice.call(arguments,1)
    var F = function F(){}
    // 闭包,哈哈
    function myBind(){
        var myArgs  = Array.prototype.slice.call(arguments)
        // 使用apply的原因是myArgs 和args 会以数组的形式传递给this函数
        // 你不知道的js中有讲到 new 和bind的优先级,new虽然会改变新对象的this,但是原函数不会受到影响
        // 构造函数的时候,this指向的是新创建的对象,执行self时,会在新对象上添加属性或方法
        return self.apply(this instanceof F ? this : context,args.concat(myArgs))
    }
    // 空函数做原型的中转,避免操作myBind的prototype,影响到原有函数的prototype
    F.prototype = self.prototype
    myBind.prototype = new F()
    return myBind
}