我刚刚在MDN上翻译了一篇关于Symbol.species的文章,当时我对以下部分进行了讨论:
您可能希望在派生数组类MyArray中返回Array对象。例如,当使用返回默认构造函数的map()等方法时,您希望这些方法返回父Array对象,而不是MyArray对象。物种符号可以让你这样做:
class MyArray extends Array { // Overwrite species to the parent Array constructor static get [Symbol.species]() { return Array; } } var a = new MyArray(1,2,3); var mapped = a.map(x => x * x); console.log(mapped instanceof MyArray); // false console.log(mapped instanceof Array); // true
除了难以翻译文本之外,没有让我感觉知道发生了什么,代码并没有证明他们的观点。当我注释掉static get [Symbol.species]() { return Array; }
行时,结果完全相同。
这是我的代码:
"use strict";
class MyArray extends Array {
// Overwrite species to the parent Array constructor
// static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
我的控制台输出:
➜ node test.js
false
true
那篇文章是错误的,还是我作为JS / Node的初学者,错过了一个重要的细节?
答案 0 :(得分:4)
您缺少重要细节。如果您继承数组,然后使用Symbol.species执行map
,则可以返回数组,而不是派生类的成员。有时您需要这样,例如,如果您将API作为库作者公开。您可能需要一些特殊的子类,以供内部使用,但是公开返回常规数组以供公共使用的方法。
并且没有实际限制,您可以为任何事情设置替代构造函数。
至于为什么注释掉该行并没有改变任何东西,请记住,子类化内置函数是新的,可能没有完全正确地实现,并且对于node.js尤其如此,如果他们跳转在早期他们被困在支持一些错误的事情上。多年来在LTS(他们在Object.observe上被烧毁了。)
答案 1 :(得分:1)
当我将
static get [Symbol.species]() { return Array; }
行注释掉时,结果是完全一样的。
在ES6的正确实现中,情况会有所不同!
对于需要更多示例的人,Keith Cirkel的this article(Github上的 keithamus )在解释概念方面比MDN文档做得更多。
这是摘录(重点是我的):
“现在,如果您要创建一个
class Foo extends Array
-每次您调用Foo#map
,而之前它会返回一个数组(不好玩),那么您将为了编写自己的Map实现而只是创建Foo
而不是Array
,现在Foo#map
返回Foo
,这要感谢{{1 }}“