Skip to content Skip to sidebar Skip to footer

Es6 Class Extends Array: Workaround For Es5 Babel Transpile

I have some ES6 class inherited from Array: class Cache extends Array { add(item) { if(!item.doNotRemove) this.push(item) } printLast() { if(this.length > 0)

Solution 1:

You only really have to extend Array if you want to the magic .length-affecting property assignment (arr[42] = 21;) behavior or most of the array methods. If you don't need that, using an array as internal data structure seems to be the simplest (and most compatible) solution:

classCache {
  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)
  }
}

You can easily expose .length and other methods.


An easy way to pull in multiple methods from Array.prototype would be:

['reduce', 'filter', 'find', ...].forEach(method => {
  Cache.prototype[method] = function(...args) {
    returnthis._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) { returnthis._data[method](...args); },
      enumerable: false,
      configurable: true,
      writeable: true,
    };
    return obj;
  }, {})
);

Solution 2:

You can manipulate the prototype directly using __proto__, it's also now kind of been standardised for backward compatibility reasons so should be safe to use.

More info here -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

edit: Like @Bergi pointed out, using a shim with Object.setPrototypeOf would future proof this technique too.

functionCache() {
  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 = newArray;
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 = newCache()
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));

Solution 3:

This is a little hacky, but I'm pretty sure it does what you are looking for.

functionCache() {}
Cache.prototype = newArray;
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 = newCache();
test.add({foo:'bar', text: 'cake' });
test.add({baz:'bat', doNotRemove: true});
test.add({free:'hugs', text: 'hello'});
test.printLast();
console.log(test);

Solution 4:

After some discussions here I was able to build a solution satisfied both of the requirements: keep original ES6 class as a state for new functionality and have this new functionality on the prototype as well as it is for the Array.prototype methods.

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

functionCache() {
  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]
);

The only difference between this CacheProto and the original class from the Question is that the CacheProto class does not extend the Array.

The end plunker could be obtained here. It contains this solution and all intermediate variants.

Post a Comment for "Es6 Class Extends Array: Workaround For Es5 Babel Transpile"