我正在阅读《JavaScript 权威指南》,遇到了这个辅助构造函数:
function SetFromArray(a) {
Set.apply( this, a );
}
SetFromArray.prototype = Set.prototype;
//
var s = new SetFromArray( [1,2,3] );
console.assert( s instanceof Set ); // => true
这是设置功能:
function Set() {
this.values = {};
this.n = 0;
this.add.apply(this, arguments);
}
正文进一步说道:
在 ECMAScript 5 中,函数的 bind() 方法具有特殊的行为,允许它创建这种辅助构造函数。
这里指的是哪些特殊行为以及如何使用它来创建那种辅助构造函数?甚至可以在 JavaScript 中创建辅助构造函数吗?
我尝试使用bind()方法重新创建这个函数:
function SetFromArray(a) {
Set.bind(null).apply(this, a);
}
但是后来,我意识到,为了利用 bind() 方法的行为(其中,boundFunction 在用作构造函数时继承原始原型),我必须在构造函数调用中使用boundfunction 作为构造函数,因此我定义的 SetFromArray 函数的工作方式可能与未绑定时定义的函数不同。
这里指的是哪些特殊行为以及如何使用它来创建这种辅助构造函数?
从我们在该章末尾找到的单个短语来看,这一点并不明显,但我认为作者并不打算像您在尝试中那样使用
bind
,因为:
SetFromArray
更长的代码,同时仍然保留已经存在的相同代码。bind
返回的函数,这意味着您可以直接使用 apply
或 call
来代替。 bind
用于以下场景:您不立即调用它返回的函数,而是将其传递给其他代码段(如使用 return
),然后该代码可能会调用它。注意作者是如何写的 “...这允许它[即
bind
]创建这个...构造函数”,他们似乎建议您可以以某种方式调用bind
来获取所需的构造函数作为返回值。所以他们暗示了类似的事情:
var SetFromArray = <something>.bind(<something>);
虽然乍一看这听起来很有希望——因为
bind
返回一个函数——
有几个原因导致这是不可能的,包括:
当调用
bind
返回的函数时,数组参数不会像 apply
那样分散为单独的参数,但这种转换是首先拥有 SetFromArray
函数的全部意义。
如果我们想要解决上述问题,我们仍然需要调用
apply
,结果如下:
var SetFromArray = Function.apply.bind(<something>);
但是
apply
不是构造函数,因此 new SetFromArray([])
会引发异常。即使它是一个构造函数,它也不会创建 Set
的实例。
在严格模式下(在现代开发中应该打开该模式),
bind
返回一个不是构造函数的函数,破坏了bind
将为我们创建构造函数的整个想法。
这本书于 1996 年首次出版,而 ECMAScript 5 于 2009 年才出版。JavaScript: The Definitive Guide 的第 6 版于 2011 年出版,在其介绍中
第六版涵盖 HTML5 和 ECMAScript 5
您在第9章中引用的短语就是在这种情况下添加的。我怀疑作者/回归者是否在测试中添加了这一附加声明,只是想 “嘿,这里我们有另一个函数,它只是传递一些参数......让我们添加他们可以使用
bind
来给它一个现代的 ECMAScript 5味道!”
自 2011 年以来发生了很多变化:
Set
现在是原生 ECMAScript 的一部分。不再需要引用的代码。我们可以使用 new Set([1,2,3])
创建一个新集合。new MyConstructor(...myArray)
。class
和 extends
,减少了您仍然想修改 prototype
属性的原因。Symbol
,使得像prop = "|**objectid**|"
这样的东西变得不必要通过篡改原型链来提供辅助构造函数的想法看起来与良好的 OOP 设计背道而驰。如果我们看看 ECMAScript 本身是如何解决这个“问题”的,我们可以发现以下例子:
Array.from
和 Array.of
提供了创建 Array
实例的替代方法。Object.create
] 和 [Object.fromEntries
] 提供了创建普通对象的替代方法这表明在 ECMAScript 中,static 函数是提供创建类实例的替代方法的标准方法。