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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。