模拟实现 JavaScript 的 apply call 及 bind 函数
在 JavaScript 中,apply
、call
和 bind
方法都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this
的指向。
改变 this 指向
我们看下面一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var name = 'GlobalName' var obj = { name: 'ObjName' }
function getName(arg1, arg2) { console.log(this.name, arg1, arg2) }
getName(1, 2)
getName.apply(obj, [1, 2]) getName.call(obj, 1, 2) getName.bind(obj, 1, 2)()
|
通过上面一段代码可以看出,我们可以通过 apply
、call
和 bind
方法,改变调用 getName()
函数的 运行时上下文,从而改变运行时函数内部的 this
指向。
三个方法的功能区别
Function.prototype.apply()
apply()
方法调用一个具有给定this
值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
Function.prototype.call()
call()
方法使用一个指定的 this
值和单独给出的一个或多个参数来调用一个函数。
注意:call() 方法的作用和 apply() 方法类似,区别就是 call()
方法接受的是 参数列表,而 apply()
方法接受的是 一个参数数组。
Function.prototype.bind()
bind()
方法创建一个新的函数,在 bind()
被调用时,这个新函数的 this
被指定为 bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
注意:bind()
是返回对应函数,便于稍后调用,apply()
、call()
则是立即调用。
模拟实现 apply、call 及 bind
实现 myApply()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Function.prototype.myApply = function (context) { if (typeof this !== 'function') { throw new Error('type error') }
let args = arguments[1]
context.fn = this
let result = context.fn(...args)
delete context.fn
return result } getName.myApply(obj, [1, 2])
|
实现 myCall()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Function.prototype.myCall = function (context) { if (typeof this !== 'function') { throw new Error('type error') }
let args = [...arguments].slice(1)
context.fn = this
let result = context.fn(...args)
delete context.fn
return result } getName.myCall(obj, 1, 2)
|
实现 myBind()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Function.prototype.myBind = function (context) { if (typeof this !== 'function') { throw new Error('type error') }
let args = [...arguments].slice(1)
let fn = this
return function () { return fn.myApply(context, args) } } getName.myBind(obj, 1, 2)()
|