在重学 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 个函数不一致。
评论