深入理解JavaScript系列(9):bind
bind
函数与 call
,apply
的区别是什么呢?
bind
函数并不是直接调用的,且返回函数可以参数- 参数一 与
call、apply
同样,指定的对象(该函数的执行上下文 - 其他参数与
call
相同,都作为参数传入,但是apply
只传入一个数组参数
具体对照,可以看我上面的一篇文章,《深入理解 JavaScript 系列(8):call/apply》。
我们来看 bind
的特点
- 返回函数
- 返回函数可以传参数
第一版 - 返回函数
我们来看一下 bind
执行的返回效果吧:
1 | let obj = { |
由此,我们来写文吗的第一版代码。
1 | Function.prototype.myBind = function (context) { |
我们来看看结果,是不是一样了呢?
1 | let obj = { |
这时候,我们得到了一个返回值,并且绑定。
第二版 - 传入参数
我们来看看,不仅在 bind
函数中可以传入参数,其返回的函数也可以传入参数。
我们看下面的例子:
1 | let obj = { |
我们怎么加入参数呢?
- 我们要获取调用 bind 函数时除了第一个绑定对象以外的参数
- 我们要获取内部返回函数的参数
1 | Function.prototype.myBind = function (context) { |
第二版写完了。
第三版 - 作为构造函数使用的绑定函数
接下来就是构造函数啦,最难的部分了。
绑定函数自动适应于使用
new
操作符去构造一个由目标函数创建的新实例。当一个绑定函数是用来构建一个值的,原来提供的this
就会被忽略
我们来举个例子,看一下。
1 | var value = 2; |
从上面结果,我们可以看出,使用 new
进行创建新实例时,this
指向绑定的 obj
已经失效了,返回 undefined
。
但是为什么不会指向全局变量呢?其实就是 new
操作,让现在的 this
指向了 obj2
。
可以来看看 new
操作是怎么实现的,参考我的这篇文章 - 《深入理解 JavaScript 系列(10):new》。
1 | Function.prototype.myBind = function (context) { |
肯定有人会对这句代码有疑问 this instanceof resultFn ? this : context
,我们来解释一下。
这里我们根据 this
与 resultFn
进行 instanceof
来判断是构造函数还是普通函数调用。
- 构造函数,
this
指向实例,判断结果为true
,将绑定函数的this
指向该实例,可以让实例获得来自绑定函数的值。 - 普通函数,
this
指向window
,结果为false
,绑定函数的this
指向context
上面的代码真的实现了吗?
好像还不够,存在问题,那就是返回函数的值修改时,也会导致原函数值的修改。
1 | let bindObj = log.myBind(null); |
第四版 - 汇总
我们来汇总一下,我们实现 bind
函数的步骤。
我们还会对上面的问题进行优化 - 就是通过一个额外的函数进行中转。
- 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用
call
等方式调用的情况- 保存当前函数的引用,获取其余传入参数值
- 创建一个函数返回
- 函数内部使用
apply
来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的this
给apply
调用,其余情况都传入指定的上下文对象
1 | Function.prototype.myBind = function (context) { |
相关文章推荐
-------------------- 本文结束
感谢阅读 --------------------