call()
、apply()
、bind()
办法的作用都是扭转函数运行时 this 的指向。 bind()
是返回对应的函数,便于稍后调用;call()
和 apply()
则是立刻调用。
相同点
- 都是用来扭转函数执行时 this 的指向,即函数运行时的上下文;
- 第一个参数都是 this 要指向的对象;
- 都能够利用后续参数传参。
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