bind、call、apply 的用法
注:因为作用域的问题,不能用 let 声明 year
var year = 2021function getDate(month,day){return this.year + '-' + month + '-' + day} //如果单独执行这个函数,this的指向是windowlet nextYear = {year: 2022}getDate.call(null,6,2) //"2021-6-2",this === null非严格模式下对应着 windowgetDate.call(this,6,2) //"2021-6-2"getDate.call(nextYear,6,2) //"2022-6-2",this === nextYeargetDate.apply(nextYear,[6,2]) //"2022-6-2"getDate.bind(nextYear)(6,2) //"2022-6-2"
bind、call、apply 都是用来指定一个函数内部的 this 的值,三者的区别主要在于用法上,apply的第二个参数是一个数组,等价于call里面的第二个之后(包括第二个)的参数直接展开。
bind 的用法是当我们调用 getDate.bind() 的时候,它会去返回一个函数,这个函数的功能和 getDate 的功能是类似的,如果这个函数里面用到了this,那这个 this 就是我们绑定的 this。
代码
代码思路
- 将函数设为对象的属性
- 执行该函数
- 删除该函数
call
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
当执行Function.prototype.call2 =function(context, ...args){context = (context === undefined ||context === null) ? window : contextcontext.__fn = thislet result = context.__fn(...args)delete context.__fnreturn result}
getDate.call2(nextYear,6,2)的时候context = nextYearnextYear.__fn = this = getDatenextYear.__fn(...args) = nextYear.__fn(3,8)
apply
apply 和call 非常的类似,唯一的区别是 apply 的第二个参数是一个数组Function.prototype.apply2 =function(context, args){context = (context === undefined ||context === null) ? window : contextcontext.__fn = thislet result = context.__fn(...args)delete context.__fnreturn result}
bind
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。Function.prototype.bind2 =function(context, ...args1){context = (context === undefined ||context === null) ? window : contextlet _this = thisreturn function(...args2){context.__fn = _thislet result = context.__fn(...[...args1,...args2])delete context.__fnreturn result}}
context.__fn =_this等同于给原来的对象新增了一个临时的属性。如果我们的对象做了一些配置使对象不能新增属性,那我们的bind2就有问题了。其实,我们不只可以在 context 上去增加属性,我们可以把目光看向更底层,比如说在Object.prototype上面去舔加属性。
比如说如果我们的obj上面不允许有fn,那我们也可以在 Object.prototype 上面添加一个 fn2
let obj = {a:1,fn:function(){console.log(this.a)}}obj.fn() // 1Object.prototype.fn2 = function(){console.log(this.a)}obj.fn2() //1
