手写原生call, apply,bind方法

1. call

call方法的作用

call方法使用一个指定的this值和单独给出的一个或多个参数来调用一个函数

call方法第一个参数为指定的this值,剩余的参数作为函数的参数传递给函数进行调用.call方法是为改变函数的执行上下文.

  1. 由于call方法可以被所有方法调用, 所以方法得定义在Function的原型上
  2. 绑定函数被调用时只传入第二个参数及以后的参数
  3. 将调用函数绑定到指定的上下文的方法上, 那么在该函数在调用时,内部的this指向该对象

明白了上面的思路我们就可以手写call了

下面是es5 实现方法

Function.prototype.Call = function (content) {
    content = content || window;// 给执行上下文 添加默认值 
    content.fn = this//给 content 添加一个方法指向this;
    var args = [];//保存参数集合
    for (let i = 1; i < arguments.length; i++) {
        args.push(arguments[i])
    }
    var res = args.length > 1 ? eval('content.fn(' + args + ')') : content.fn() ;//执行fn;
    delete content.fn;// 删除fn方法
    return res
}

下面是Es6的代码实现

Function.prototype.Call = function(content=window){// 给执行上下文 添加默认值
    content.fn = this//给 content 添加一个方法指向this;显示绑定this
    // 获取第一个参数以后的所有参数
    const args = Array.from(arguments).slice(1);
    // 调用上下文的fn属性, 此时函数的this指向上下文, 也就是我们传入的content
    const res = arguments.length > 1 ? content.fn(...args) : content.fn();
    // 删除上下文的content的fn方法, 避免污染上下文
    delete content.fn;
    return res
} 

2. apply

​ apply方法和call方法类似,都是Function原型上的方法, 每一个函数作为Function的实例都能调用这两个方法, 都是为了改变调用函数的执行上下文this指向.

​ 区别在于: call传参的时候接受的是一个参数列表,而apply方法的要传的参数接受的是一个参数列表数组, apply实现了思路和call基本相同, 我们只需要对参数进行不同的处理即可.

因为原生的apply第二个参数接受的是一个数组或者类数组对象, 所以我们得对第二个参数类型进行判断

下面是es6的实现代码

Function.prototype._Apply = function (content = window, args = []) {//给content和args添加默认值
    if (!(args instanceof Object)) {// 如果第二个参数不是对象的实例,就返回一个错误
        throw new TypeError('Create List From Array Like called on non-object');
    }
    // 显示绑定函数this
    content.fn = this;
    // 执行fn方法,并接受返回值
    const res = arguments[1] ? content.fn(...arguments[1]) : content.fn()
    delete content.fn;// 删除fn方法
    return res
}

3. bind

bind()方法创建一个新函数, 在bind()被调用时, 这个新函数的this被指定为 bind()的第一个参数, 而其余参数将作为新函数的参数,供调用时使用.

下面是bind的es6的简易实现

Function.prototype._bind = function(content=window){
    const slice = Array.prototype.slice;
    // 保存调用函数的this, 也就是原函数
    const thatFunc = this;
    // 获取第一个参数之后剩余的参数数组
    const args = [].slice.call(arguments,1);
    return function(){
        // 合并返回的新函数的参数
        const funcArgs = args.concat(slice.call(arguments))
        // 返回新函数调用的结果
        return thatFunc.call(content,...funcArgs)
    }
}

上面的代码只是对bind的一个简易实现, 没有考虑new运算符的实现,之后会更新对new运算符的实现.

你可能感兴趣的:(手写原生call, apply,bind方法)