JavaScript 中的硬绑定
JavaScript 中的硬绑定
[[工程师 JavaScript — 7]]
绑定函数的思想允许记住将 this 绑定固定到特定对象,除此之外,绑定函数还可以记住绑定函数闭包所需的部分参数
Function.prototype.bind 的简单 polyfill 如下所示。
if(!Function.prototype.bind) {
Function.prototype.bind = function (objToBind, ...initialArgs) {
常量 fnToBind = 这个;
// 调用 bind 的对象是 this
函数 boundFn(...remainingArgs) {
// 当 boundFn 用 new 操作符调用时
const allArgs = [...initialArgs, ...remainingArgs];
if(Object.getPrototypeOf(this) === boundFn.prototype) {
返回新的 fnToBind(...allArgs);
}
// 否则 // ... (2)
返回 fnToBind.apply(objToBind, allArgs);
// 显式绑定
}
返回boundFn;
}
} 函数 abc(x, y, z) {
控制台.log(this.a);
控制台.log(this.b);
控制台.log([x, y, z]);
console.log("abc end"); // .... (3)
} 常量 bFn = abc.bind({a: 10, b: 40}, 500); // ...(1)
bFn(670, 1000);
console.log("完成调用 bFn"); // ... (4)
在讨论绑定之前,我们先来看看函数 abc 的 [[Prototype]] 链,了解隐式绑定和 [[Get]] 是如何用于搜索绑定函数的,以及调用绑定函数的函数是如何隐式的将是这个上下文。
让我们看看 (1) 处的作用域链。调用 bind 时创建的作用域包含所有对 boundFn 可用的重要细节,因为它是在同一作用域中创建的。所以我们看到绑定函数已经准备好通过闭包访问很多细节,它知道它需要调用什么函数 f,它记住应该作为 this 传递的值,它还记住函数需要的一些参数F。
当调用绑定函数 bFn 时,让我们看看 (2) 处程序生命时的作用域链。创建的作用域对象将连接到绑定函数的 [[Environment]] 属性。因此 boundFn 将能够收集执行 abc 所需的所有必要细节,使用其包含剩余Args 的范围和包含通过范围链的所有细节的闭包。因此可以收集所有参数并将其传递给 abc。
在 (3) 处的作用域链,当使用显式 this 绑定从绑定函数调用 abc 函数时,我们看到为 abc 的函数调用创建的作用域连接到窗口作用域,因为 abc 是在该作用域中创建的。有趣的是,boundFn 确保当 abc 使用显式绑定执行时,它明确地告诉了这个绑定应该是什么。
(4) 的作用域链,当 abc 完成执行,以及绑定函数完成执行时,这些作用域可以被垃圾回收,因为它们不再需要。
当硬绑定函数再次被硬绑定时会发生什么,等等?
让硬绑定的顺序为
abc → boundA → boundB → boundC
调用boundC时,函数调用顺序为
boundC → boundB → boundA → abc
数据的传递方式很有趣,每个函数都使用自己的闭包,并将数据传递给其作用域内的下一个函数,该函数也使用自己的闭包,依此类推。请注意,执行 abc 时的此绑定将仅由 boundA 确定,因为 this 的其他值不会传递给常规函数 abc。
当使用 new 运算符调用硬绑定函数时,硬绑定 this 将被忽略,而是将新对象作为 this 传递。此规则与此绑定的权力有关。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明