【发布时间】:2021-07-28 02:51:39
【问题描述】:
我完全错过了 ES6 革命,我在 7 年后回到 JavaScript,发现发生了许多非常奇怪的事情。
特别是Function.prototype.bind() 处理类构造函数的方式。
考虑一下:
// an ES6 class
class class1 {
constructor (p) {
this.property = p;
}
}
var class2 = class1.bind(passer_by);
var class3 = class2.bind(passer_by,3);
class2() // exception, calling a constructor like a function
class3() // idem
console.log (new class1(1)) // class1 {property: 1}
console.log (new class2(2)) // class1 {property: 2}
console.log (new class3() ) // class1 {property: 3}
// An ES5-style pseudo-class
function pseudoclass1 (p) {
this.property = p;
}
var property = 0;
var passer_by = { huh:"???" }
var pseudoclass2 = pseudoclass1.bind(passer_by);
var pseudoclass3 = pseudoclass1.bind(passer_by,3);
pseudoclass1(1); console.log (property) // 1 (this references window)
pseudoclass2(2); console.log (passer_by) // Object { huh: "???", property: 2 }
pseudoclass3() ; console.log (passer_by) // Object { huh: "???", property: 3 }
console.log (new pseudoclass1(1)) // pseudoclass1 {property: 1}
console.log (new pseudoclass2(2)) // pseudoclass1 {property: 2}
console.log (new pseudoclass3() ) // pseudoclass1 {property: 3}
显然class2和class3被标识为构造函数,而class3是class1的部分应用,可以生成第一个参数为固定值的实例。
另一方面,尽管它们仍然可以充当(穷人的)构造函数,但 ES5 风格的函数确实服务于 bind() 设置的 this 的值,当它们作用于倒霉的人时可以看出passer_by 而不是像未绑定的 pseudoclass1 那样破坏全局变量。
显然,所有这些构造函数都以某种方式访问this 的值,从而允许它们构造一个对象。然而他们的this 应该绑定到另一个对象。
所以我想一定有某种机制在起作用,将正确的this 提供给构造函数,而不是传递给bind() 的任何参数。
现在我的问题是,我可以在这里和那里找到一些关于它的知识,甚至一些代码显然来自 Chrome 的 V8 的某个版本(函数 bind() 本身似乎对构造函数做了一些特殊的事情),或者讨论关于原型链中插入的一个神秘的 FNop 函数,以及,如果我可以补充的话,偶尔的货物崇拜 bu[beep]it。
但是我找不到关于这里实际发生的事情的解释,关于为什么实施这种机制的理由(我的意思是,使用新的扩展运算符和解构等等,不是吗?可以产生相同的结果(向构造函数应用一些参数),而不必在bind()?除了传递给bind() 的值之外的其他东西?)
我尝试阅读 2015 年和 2022 年 ECMA 262 规范,但当我的大脑开始从耳朵里漏出来时,我不得不停下来。我将调用堆栈追溯为:
19.2.3.2
9.4.1.3
9.4.1.2
7.3.13
其中关于构造函数的说法是:“如果未传递 newTarget,则此操作等效于:new F(...argumentsList)”。啊哈。所以这个伪递归调用应该允许以某种方式模拟new... Erf...
如果某个善良和精明的灵魂能让我更好地了解正在发生的事情,告诉我 ECMA 规范的哪些部分处理这种机制,或者更笼统地指出我的正确方向,我将不胜感激方向。
说实话,我已经厌倦了用头撞墙。这个bit of Chrome code 似乎表明bind() 正在为构造函数做一些特别的事情,这对我来说是不可理解的。因此,如果其他一切都失败了,我至少想要一个解释。
【问题讨论】:
-
在
new class1(1)中,this对决定调用哪个构造函数没有影响,因为this是正在创建的东西。在决定构造实例时将运行什么时,是什么导致您期望new (class1.bind(null))(1)使用null而不是绑定函数本身(从.bind(null)返回的对象,而不是调用它时传递的参数)? -
我真的不期待什么,我只是想知道它是如何工作的。正常绑定函数的行为方式,使用
bind()设置的值。通过new调用时,情况有所不同。我看到关于“this”的 TB 级的光泽,而不是关于它在new调用上下文中的值的字眼。我什至没有看到任何关于它的规范或官方理由。而且我发现bind()的接口有点混乱(构造函数会忽略“this”值)。我已经修改了我的示例以使其更清晰。
标签: ecmascript-6 this