call() 实现原理
call() 方法是Function的原型对象的方法(Function.prototype.call)
call() 允许为不同的对象分配和调用属于一个对象的函数/方法
call() 可以改变this的指向(但是这种说法其实并不准确,这是根据作用阐述的通俗易懂的说法,因为this是在执行上下文创建时确定的一个在执行过程中不可更改的变量)
那么 call() 方法做了什么呢?
以此调用为例:
1 |
|
主要做了以下处理:
obj.toString = Object.prototype.toString 将调用的函数设为被指向对象的属性
obj.toString() 执行该函数
delete obj.toString 删除该函数
如此一来,就实现了目标对象没有此函数,却可以通过call方法进行调用
模拟实现call
1 |
|
在知道了实现原理的情况下,可以联想到
- call 会出现闭包的情况
因为 call 会直接将调用call方法的函数的引用赋给目标对象的一个属性
而函数在定义时,其定义域就已经确定了,若该函数是内部函数,则有可能会出现闭包的情况
(当然,这种情况出现的机率非常小,但是从原理上来讲,是会发生的,取决于如何使用)
apply() 实现原理
apply() 的实现原理与 call() 一样,区别只是参数的传递方式不一样,apply()要求传递数组,而call()则是一个个传递
模拟实现apply
1 |
|
bind() 实现原理
bind() 会返回一个新的函数,此函数会绑定创建它时传入 bind()方法的目标对象(第一个参数)
若使用 new 关键字调用返回的新函数,则绑定的对象会失效,转为绑定new出来的实例
模拟实现bind
1 |
|
bind传入目标对象后,会return一个函数
返回的函数,无法再用call() 或 apply()重新绑定新的目标对象
- 连续bind()也是无效的
如:foo.bind(obj1).bind(obj2).bind(obj3) 等同于 foo.bind(obj1)
后面的两个bind都是不生效的
原因嘛,不好表达,大致描述一下下:
第一层bind,foo函数绑定了obj1,而bind的内部调用了call/apply,call/apply都会立即执行调用它的函数
第一层bind返回的函数 f1 中,内部是调用apply绑定 foo 与 obj1(foo.apply(obj1)),若执行 f1,会立即执行 foo
第二层bind,f1函数绑定了obj2,返回的函数 f2 ,f2中调用apply绑定 f1 与 obj2(f1.apply(obj2)),若执行 f2,会立即执行 f1
从这里,我们已经可以看出结果了(第三层就不列举了,同样的原理):
我们的目标是将 foo函数 与目标对象绑定,然后执行foo函数
而第二层虽然绑定了 obj2,却是 f1 与 obj2 绑定,无法影响到 foo
所以有如下的执行链:
f2 => f1(绑定obj2) => foo(绑定obj1)
最终还是会执行 foo,并且,foo函数绑定的还是 obj1
无论多少层都是一样的结果
参考文章:
call()、apply() 参考:
https://blog.csdn.net/liubangbo/article/details/84098212
https://blog.csdn.net/Liu_yunzhao/article/details/90216066