跳至主要內容

手写call、apply、bind

yyshino大约 2 分钟FrontEndJS手写系列

手写call、apply、bind

总结

  • 三者都可以改变函数的this对象指向
  • 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefinednull,则默认指向全局window
  • 三者都可以传参,但是apply是数组,而call是参数列表,且applycall是一次性传入参数,而bind可以分为多次传入
  • bind是返回绑定this之后的函数,applycall 则是立即执行

call

定义:call方法的第一个参数也是this的指向,后面传入的是一个参数列表

apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

Function.prototype.call1 = function(){
	// 初始化
    const [context,...args] = [...arguments]
    // 在传入的对象上设置属性为待执行函数
    context.fn = this
    // 执行函数
    const res= context.fn(args)
    // 删除属性
    delete context.fn
    // 返回执行结果
    return res
}

apply

定义: 调用一个具有给定 this 值的函数,及以一个数组的形式提供的参数。

改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

Function.prototype.apply1 = function (context, args) {
    // 给传入的对象添加属性,值为当前函数
    context.fn = this;
	
    // 判断第二个参数是否存在,不存在直接执行,否则拼接参数执行
    let res = !args ? context.fn() : context.fn(...args)
    
    // 删除新增属性
    delete context.fn
    
    return res
}

bind

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

Function.prototype.bind1 = function (context) {
	// 将当前函数的this存放起来
	var _self = this
    // 绑定bind传入的参数,从第二个开始
    var args = Array.prototype.slice.call(arguments,1);
    
    // 声明一个空的构造函数
    function fNOP(){}
    
    var fBound = function(){
        // 绑定bind返回新的函数,执行所带的参数
        const bindArgs = Array.prototype.slice.apply(arguments)
        // 合并数组
        args.push.apply(args.bindArgs)
        // 普通函数 this指向window
        // 作为构造函数,this指向实例
        return _self.apply(this instanceof fNOP ? this : context,args)
    }
    
    if(this.prototype){
        // 修改返回函数的prototype为绑定函数的prototype,实例就可以继承绑定函数的原型中的值
        fNOP.prototype = this.prototype
    }
    
    fBound.prototype = new fNOP();
    
    return fBound;
}