关于javascript:callapplybind的区别

6次阅读

共计 2041 个字符,预计需要花费 6 分钟才能阅读完成。

call()apply()bind()办法的作用都是扭转函数运行时 this 的指向。 bind() 是返回对应的函数,便于稍后调用;call()apply() 则是立刻调用。

相同点

  1. 都是用来扭转函数执行时 this 的指向,即函数运行时的上下文;
  2. 第一个参数都是 this 要指向的对象;
  3. 都能够利用后续参数传参。

1、apply、call

二者作用完全相同,只是接管参数上的不同。如果不传入第一个参数,则默认上下文是 window

1)call
语法
  • fun.call(context, arg1,arg2…)
  • context: 在 fun 函数中运行时指定的 this 值
  • arg1,arg2:指定的参数列表
实现原理
Function.prototype.myCall = function(context, ...args) {if( typeof this !== 'function') {throw new TypeError('Error') // 判断是否是函数调用
    }
    context = context ? Object(context) : window // 原始值的 this 会指向该原始值的实例对象 因而须要 Object 转换成对象类型
    context.fn = this // 函数的 this 指向隐式绑定到 context 上
    const result = context.fn(...args) // 通过隐式绑定函数并传递参数
    delete context.fn // 删除上下文对象的属性
    return result // 返回函数执行后果
}

示例

let test = {name: "test"}
let  fun = {fn: function () {console.log(this.name)
    }
}
fun.fn.myCall(test) // test
2)apply
语法
  • fun.apply(context, [argsArr])
  • context:在 fun 函数运行时指定的 this 值
  • argsArr:一个数组或者是类数组对象,其中数组中元素会作为独自参数传给 fun。当参数值为 null 或者 undefined 时,示意不须要传入任何参数。

留神: 上述指定的 this 值(thisArg)并不一定是该函数执行时真正的 this 值,如果该函数处于 非严格模式 下,则指定为 null 或者 undefined 时会主动指向全局对象(浏览中就是 window 对象),同时值为原始值(number、string、boolean)的 this 会指向该原始值的主动包装对象。

实现原理
Function.prototype.myApply = function(context) {if( typeof this !== 'function') {throw new TypeError('Error')
    }
    context = context ? Object(context) : window
    context.fn = this
    let result
    if(arguments[1]) { // 解决参数上和 call 有区别
        result = context.fn(...arguments[1])
    } else {result = context.fn()
    }
    
    delete context.fn
    return result
}

示例

function fn() {console.log(this.age)
}

let person = {age: 12}
fn.myApply(person) // 12

2、bind

bind办法会创立一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创立它时传入 bind() 的第一个参数作为 this,传入bind 办法的 其余参数以及和绑定函数运行时自身的参数,将依照程序作为原函数的参数来调用原函数。

语法
  • fun.bind(context, arg1, arg2, …)
  • context:当绑定函数被调用时,该参数会作为原函数运行时的 this 指向;当应用 new 操作符调用绑定函数时,该参数有效。
  • arg1,arg2…:绑定函数被调用时,这些参数将位于实参之前传递给绑定的办法。
实现原理
Function.prototype.myBind = function(context) {if( typeof this  !== 'function') {throw new TypeError('Error')
    }
    
    let args = [...arguments].slice(1) // bind 函数中的参数
    let self = this // 保留原函数
    return function() {return self.apply(context, args.concat(...arguments)) // arguments 是内部函数传入的
    }
}

示例

let obj = {a: 'a'};

function f(b, c, d) {console.log(this.a, b, c, d)
}

f.myBind(obj, 'b')('e') // a b e undefined
f.myBind(obj, 'b', 'c')('e') // a b c e
f.myBind(obj, 'b', 'c', 'd')('e') //a b c d
正文完
 0