ES6 Class扩展Array:ES5 Babel transile的解决方法

时间:2017-10-23 19:51:06

标签: javascript class ecmascript-6 babeljs es6-class

我有一些继承自Array的ES6类:

class Cache extends Array {
  add(item) {
    if(!item.doNotRemove)
      this.push(item)
  }
  printLast() {
    if(this.length > 0)
      console.log(this[this.length - 1].text)
  }
}

以下代码可以正常使用

const myCache = new Cache()
myCache.add({text: 'hello'})
myCache.add({text: 'world'})
myCache.add({text: '!!!', doNotRemove: true})
myCache.printLast() // world

但我无法通过Babel将其转发给ES5(我知道有一个issue),目前我采用以下方法作为解决方法:

const CacheProto = {
  add(item) {
    if(!item.doNotRemove)
      this.push(item)
  },
  printLast() {
    if(this.length > 0)
      console.log(this[this.length - 1].text)
  }
}
function Cache() {
  return Object.assign(Object.create(Array.prototype), CacheProto)
}

这满足上面的代码(myCache = new Cache()等)。但正如您所看到的,它只是一个扩展的Array实例。

问题

是否可以使用原始类进行解决?当然,没有extends Array。是否可以在原型链上使用addprintLast方法以及所有Array.prototype方法,而不是在实例上?

我为可能的研究做了一点plunker

4 个答案:

答案 0 :(得分:2)

如果你想要魔术Array - 影响属性赋值(.length)行为或大多数数组方法,你只需要扩展arr[42] = 21;。如果您不需要,使用数组作为内部数据结构似乎是最简单(也是最兼容)的解决方案:

class Cache {
  constructor() {
    this._data = [];
  }

  add(item) {
    if(!item.doNotRemove)
      this._data.push(item)
  }

  printLast() {
    if(this.length > 0)
      console.log(this._data[this._data.length - 1].text)
  }
}

您可以轻松公开.length和其他方法。

Array.prototype引入多种方法的简便方法是:

['reduce', 'filter', 'find', ...].forEach(method => {
  Cache.prototype[method] = function(...args) {
    return this._data[method](...args);
  };
});

// Or if you want them to be non-enumerable
// (like they would if they were defined via `class` syntax)
Object.defineProperties(
  Cache.prototype,
  ['reduce', 'filter', 'find', ...].reduce((obj, method) => {
    obj[method] = {
      value: function(...args) { return this._data[method](...args); },
      enumerable: false,
      configurable: true,
      writeable: true,
    };
    return obj;
  }, {})
);

答案 1 :(得分:1)

您可以使用__proto__直接操作原型,由于向后兼容性原因,它现在也已经标准化,因此应该可以安全使用。

此处有更多信息 - > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

编辑:就像@Bergi所指出的那样,使用带Object.setPrototypeOf的垫片也将证明这种技术。

function Cache() {
  var arr = [];
  arr.push.apply(arr, arguments);
  arr.__proto__ = Cache.prototype;
  //if using a shim, (better option).
  //Object.setPrototypeOf(arr, Cache.prototype);
  return arr;
}
Cache.prototype = new Array;
Cache.prototype.printLast = function () {
  if(this.length > 0)
    console.log(this[this.length - 1].text)
}
Cache.prototype.add = function (item) {
  if(!item.doNotRemove)
    this.push(item)
}



const myCache = new Cache()
myCache.add({text: 'hello'})
myCache.add({text: 'world'})
myCache.add({text: '!!!', doNotRemove: true})
myCache.printLast() // world

myCache.forEach(function (item) { console.log(item); });

console.log("is Array = " + Array.isArray(myCache));

答案 2 :(得分:0)

这有点笨拙,但我很确定它能满足您的需求。



function Cache() {}
Cache.prototype = new Array;
Cache.prototype.add = function(item) {
  if (!item.doNotRemove) {
    this.push(item);
  }
};
Cache.prototype.printLast = function() {
  if (this.length <= 0) { return }
  console.log(this[this.length - 1].text);
}

let test = new Cache();
test.add({foo:'bar', text: 'cake' });
test.add({baz:'bat', doNotRemove: true});
test.add({free:'hugs', text: 'hello'});
test.printLast();
console.log(test);
&#13;
&#13;
&#13;

答案 3 :(得分:0)

经过一些讨论后,我能够构建一个满足这两个要求的解决方案:将原始ES6类保持为新功能的状态,并在原型上使用这个新功能,以及Array.prototype方法。

class CacheProto {
  add(item) {
    if(!item.doNotRemove)
      this.push(item)
  }
  printLast() {
    if(this.length > 0)
      console.log(this[this.length - 1].text)
  }
}

function Cache() {
  const instance = [];
  instance.push.apply(instance, arguments);
  Object.setPrototypeOf(instance, Cache.prototype);
  return instance;
}
Cache.prototype = Object.create(Array.prototype);
Object.getOwnPropertyNames(CacheProto.prototype).forEach(methodName =>
  Cache.prototype[methodName] = CacheProto.prototype[methodName]
);

CacheProto与问题中原始类的唯一区别是CacheProto类不会扩展Array

可以获得末端掠夺者here。它包含此解决方案和所有中间变体。