深入理解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) { |
相关文章推荐
-------------------- 本文结束
感谢阅读 --------------------