我完全错过了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()设置的bind()值,就像它们在不幸的passer_by上运行而不是像无界pseudoclass1那样破坏全局变量时所看到的那样。
显然,所有这些构造函数都以某种方式访问了允许它们构造对象的this值。然而他们的this被认为是绑定到另一个物体上的。
因此,我想一定有某种机制可以将适当的this提供给构造函数,而不是传递给bind()的任何参数。
现在我的问题是,我可以到处找到一些关于它的知识,甚至一些代码显然是来自Chrome的V8版本(函数bind()本身似乎对构造函数做了一些特殊的事情),或者讨论了在原型链中插入的一个神秘的FNop函数,还有,如果我可以说的话,偶尔会有一段货物崇拜的蜂鸣声。
但我找不到的是对这里实际发生的事情的解释,这是为什么实现这样一种机制的理由(我的意思是,使用新的扩展操作符和析构等等,难道不可能产生相同的结果(向构造函数应用一些参数),而不需要对bind()进行适当的文档攻击吗?)及其范围(它对构造函数有效,但是否还有其他类型的函数被传递给bind()?)?
我试着阅读2015年和2022年ECMA 262的规范,但当我的大脑开始从我的耳朵里漏出来时,我不得不停止阅读。我将调用堆栈追溯到:
19.2.3.2
9.4.1.3
9.4.1.2
7.3.13关于构造函数的一些内容是:“如果newTarget未被传递,则此操作等效于: new (...argumentsList)”。啊哈。所以这个伪递归调用应该允许在某种程度上模拟new .Erf..。
如果某个善良而精明的灵魂能让我更好地了解正在发生的事情,向我展示ECMA规范的哪一部分来处理这一机制,或者更普遍地指出我的正确方向,我将不胜感激。
我受够了把头撞在墙上,说实话。这个一点Chrome代码似乎表明bind()正在为构造函数做一些特殊的事情,这对我来说是难以理解的。所以,如果其他一切都失败了,我至少想要一个解释。
发布于 2021-07-28 08:47:36
具体而言,这与类无关,而是与.bind的工作方式有关。
你一直走在正确的轨道上。这里最相关的部分是9.4.1.2。
作为一个概述: ECMAScript区分了两种类型的函数:可调用函数和可构造函数。函数表达式/声明都是,而例如,class构造函数只能是可构造的,而箭头函数只能被调用。
在规范中,这是由函数的内部[[Call]]和[[Construct]]方法表示的。
new将触发内部[[Construct]]方法的调用。
.bind将返回一个具有不同实现的[[Call]]和[[Construct]]的新函数对象。那么,[[Construct]]是什么样的呢?
9.4.1.2 [构造] 当使用bind函数创建的绑定函数外来对象(F)的[Construct]内部方法使用参数argumentsList和newTarget列表调用时,将执行以下步骤:
这意味着绑定构造函数将使用绑定参数(F.[[BoundTargetFunction]])和传入参数(argumentsList)“构造”原始函数( this ),但它完全忽略了绑定this值(即F.[[BoundThis]])。
但是,除了传递给bind()的值之外,还有其他类型的函数正在被喂入吗?
是的,箭头起作用。箭头函数没有自己的this绑定(而是使用来自最近的this提供环境的值),因此绑定箭头函数也忽略绑定的this值。
https://stackoverflow.com/questions/68553794
复制相似问题