在重学 JS 系列文章中,上一节学习了 JS 中的 this 指向问题。这节学习如何改变函数的上下文,实际上是改变函数体中 this 的指向。call()
函数和apply()
函数是为改变函数运行时上下文而存在的,但它们并不是从函数继承而来。bind()
函数也能达到这个目的。下面看看三者的用法:
1. call()函数的用法
call()
函数调用一个函数时,会将该函数的执行上下文改变为另一个对象。语法如下:
// Function : 调用的函数
// context : 新的对象上下文,函数中的this指向context,若context为null|undefined,则执行window
// arg1,arg2 : 参数列表
Function.call(context,arg1,arg2,...)
复制代码
看个简单例子:
function add(x,y){
return this.x+this.y
}
var obj = {
x:10,
y:20
}
add.call(obj) // 30
复制代码
例子里的add()
函数执行时,this
指向了 obj。可以粗俗的理解为add()
函数挂载到 obj 对象上,执行完函数后,obj 对象再删除了add()
函数属性。下面通过代码模拟下这个过程:
Function.prototype.customeCall = function(cxt){
// 不传context,或者null|undefined,默认指向window
let context = cxt || window
// 将调用函数挂载到当前context
context.fun = this
// 获取除了context外的参数
const args = Array.from(arguments).splice(1)
// 执行调用函数
const result = context.fun(...args)
// 执行完后删除属性
delete context.fun
return result
}
// 按照例子执行
add.customeCall(obj) // 30
复制代码
2. apply()函数的用法
apply()
作用与call()
函数是一致的,只是在传参形式上不同。
// [argArray] 这里传递的是数组
Function.apply(context,[argArray])
复制代码
简单例子:
function add(x,y){
return x + y
}
function mAdd(x,y){
// 注意apply的传参为数组,与call()函数不一致
return add.apply(this,[x,y])
}
mAdd(10,20) // 30
复制代码
模拟下实现:
Function.prototype.customeApply = function(ctx,argArray){
let context = ctx || window
context.fun = this
if(!Array.isArray(argArray)){
throw new Error('参数必须为数组')
}
if(!argArray){
return context.fun()
}
const result = context.fun(...argArray)
delete context.fun
return result
}
复制代码
3. bind()函数的使用
bind()
函数创建一个新函数,在调用时设置 this 关键字为提供的值,在执行新函数时,将给定的参数列表作为原函数的参数序列,从前往后匹配。语法如下:
Function.bind(context,arg1,arg2,...)
复制代码
简单例子:
function add(x,y){
return this.x+this.y
}
var obj = {
x:10,
y:20
}
// 函数上下文指向obj返回新函数
var newFun = add.bind(obj)
newFun() // 30
复制代码
模拟下实现:
Function.prototype.customeBind = function(context, ...rest) {
if (typeof this !== 'function')
throw new TypeError('invalid invoked!');
var self = this;
return function F(...args) {
if (this instanceof F) {
return new self(...rest, ...args)
}
return self.apply(context, rest.concat(args))
}
}
复制代码
4. 总结
call()
函数、apply()
函数、bind()
函数三者都会改变函数调用时的执行主体,修改this
的指向。
call()
函数、apply()
两个函数是立即执行返回,而bind()
函数是返回一个新函数,在任何使用可以调用。
apply()
函数第二个入参为数组,与其他 2 个函数不一致。
评论