使用ES6类扩展数组

18 ecmascript-6 traceur

我听说ES6现在最终允许子类化Array.这是一个给出的例子

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
Run Code Online (Sandbox Code Playgroud)

当然,这很有效.但至少在Traceur中,明确设置长度并不会截断数组.当通过console.log打印时,输出是对象形式而不是数组形式,这表明某人并没有将其视为"真正的"数组.

这是Traceur如何实现内置对象的子类化或ES6限制的问题吗?

Jac*_*ter 15

答案很长

在正常情况下,Ecmascript 6中的子类只是语法上的含糖,所以它仍然是Ecmascript 5所做的原型链接.这意味着Traceur中的扩展类型在大多数情况下与在"真实"ecmascript 6中扩展完全相同.

数组实例很特殊 - ECMAScript 6规范称它们具有异国情调.他们对属性长度的处理不能通过普通的JavaScript复制.如果你调用你的构造函数,那么就会创建一个Stack实例,而不是异国情调的对象(异国情调实际上是ES6规范中的官方名称).

但不要绝望,解决方案不是由class extends糖本身提供,而是由(重新)引入该__proto__属性.

解决方案

Ecmascript 6重新引入了可写__proto__属性.它曾经只在Firefox上可用并且已被弃用,但现在又在ES6中完全恢复.这意味着您可以创建一个真正的数组,然后将其"升级"到您的自定义类.

所以现在你可以做到以下几点:

function Stack(len) {
    var inst = new Array(len);
    inst.__proto__ = Stack.prototype;
    return inst;
}
Stack.prototype = Object.create(Array.prototype);  
Run Code Online (Sandbox Code Playgroud)

简短的回答

因此,子类化应该适用于ES6.你可能不得不__proto__手动使用这个技巧,如果他们没有设法使用新的class extends语法来解决这个过程,并且有一些未公开的技巧.您将无法使用Traceur和Typescript之类的转发器在ES5中完成此操作,但是您可以使用Firefox(我记得)已经支持__proto__了很长一段时间在ES5中使用上面的代码.

  • 来自[MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/proto):«在大多数浏览器中支持`Object.prototype .__ proto__`,它的存在和确切行为仅在ECMAScript 6规范中标准化,作为确保Web浏览器兼容性的传统功能.»更好地使用[`Object.setPrototypeOf()`](https://developer.mozilla.org/docs/Web/JavaScript/ Reference/Global_Objects/Object/setPrototypeOf)或[`Reflect.setPrototypeOf`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Reflect/setPrototypeOf). (4认同)