简体   繁体   English

使用ES6类扩展数组

[英]Extending Array with ES6 classes

I have heard that ES6 now finally permits subclassing Array. 我听说ES6现在最终允许子类化Array。 Here's an example given by 这是一个给出的例子

class Stack extends Array {
    constructor() { super() }
    top() { return this[this.length - 1]; }
  }

  var s = new Stack();
  s.push("world");
  s.push("hello");
  console.log(s.top());  // "hello"
  console.log(s.length); // 2

Sure, that works. 当然,这很有效。 But in Traceur at least, setting the length explicitly does not truncate the array. 但至少在Traceur中,明确设置长度并不会截断数组。 And when printing via console.log, the output is in object form rather than array form, suggesting that somebody is not looking at it as a "real" array. 当通过console.log打印时,输出是对象形式而不是数组形式,这表明有人不会将其视为“真正的”数组。

Is this a problem with how Traceur implements subclassing built-in objects, or a limitation of ES6? 这是Traceur如何实现内置对象的子类化或ES6限制的问题吗?

Long answer 答案很长

In the normal case, the subclassing in Ecmascript 6 is just syntactic sugaring, so it still does the prototypical chaining that Ecmascript 5 does. 在正常情况下,Ecmascript 6中的子类只是语法上的含糖,所以它仍然是Ecmascript 5所做的原型链接。 This means that extending types in Traceur is in most cases exactly the same as extending in "real" ecmascript 6. 这意味着Traceur中的扩展类型在大多数情况下与在“真实”ecmascript 6中扩展完全相同。

Array instances are special – the ECMAScript 6 specification calls them exotic. 数组实例很特殊 - ECMAScript 6规范称它们具有异国情调。 Their handling of the property length can't be replicated via normal JavaScript. 他们对属性长度的处理不能通过普通的JavaScript复制。 If you invoke your constructor then an instance of Stack is created, not an exotic object (exotic is actually the official name in the ES6 spec). 如果你调用你的构造函数,那么就会创建一个Stack实例,而不是异国情调的对象(异国情调实际上是ES6规范中的官方名称)。

But do not despair, the solution is not provided by the class extends sugaring itself, but by the (re)introduction of the __proto__ property. 但是不要绝望,解决方案不是由class extends加糖本身提供,而是通过(重新)引入__proto__属性。

The solution 解决方案

Ecmascript 6 reintroduces the writable __proto__ property. Ecmascript 6重新引入了可写的__proto__属性。 It was once only available on Firefox and was deprecated, but is now back in full force in ES6. 它曾经只在Firefox上可用并且已被弃用,但现在又在ES6中完全恢复。 This means that you can create a real array and then "upgrade" it to your custom class. 这意味着您可以创建一个真正的数组,然后将其“升级”到您的自定义类。

So now you can do the following: 所以现在你可以做到以下几点:

function Stack(len) {
    var inst = new Array(len);
    inst.__proto__ = Stack.prototype;
    return inst;
}
Stack.prototype = Object.create(Array.prototype);  

Short answer 简短的回答

So subclassing should work in ES6. 因此,子类化应该适用于ES6。 You might have to use the __proto__ trick manually if they have not manage to sugar the process using the new class extends syntax with some yet undisclosed trickery. 你可能不得不手动使用__proto__技巧,如果他们没有设法使用新的class extends语法来解决这个过程,而且还有一些未公开的技巧。 You will not be able to use the transpilers such as Traceur and Typescript to accomplish this in ES5, but you might be able to use the code above in ES5 using Firefox that (as far as I remember) have supported __proto__ for quite some time. 您将无法使用Traceur和Typescript之类的转发器在ES5中完成此操作,但您可以使用Firefox(我记得)已经支持__proto__已经有一段时间在ES5中使用上面的代码了。

The problem is that you are overriding the constructor. 问题是你要覆盖构造函数。 If you remove your constructor () { super(); } 如果你删除你的constructor () { super(); } constructor () { super(); } , your example works perfectly, including s.length = 0 truncating the array. constructor () { super(); } ,您的示例工作正常,包括截断数组的s.length = 0。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM