PowerArray icon indicating copy to clipboard operation
PowerArray copied to clipboard

PowerArray constructor is too slow.

Open Hypercubed opened this issue 10 years ago • 3 comments

Intro

I've put together some Array speed tests for testing the speed of various "fast" array methodologies. I've been trying to implement fast version of concat in PowerArray. However, the PowerArray constructor is too slow. This in turn makes methods that return arrays (map, filter, concat) slow. The constructor is slow, in part, because of the cost of creating a new object (in other words new PowerArray() is slower new Array() which is slower than []) and also because recasting an existing array as a PowerArray requires copying each element to the new object. My approach in Hypercubed/BoostArray is to attach BoostArray prototype methods to normal arrays (or to the Array prototype), therefore never/rarely creating new objects. This method will not work in PowerArray which must create a new instance (different philosophies between the two projects).

Proposal

Therefore, I propose a new constructor in PowerArray based on the very detailed article How ECMAScript 5 still does not allow to subclass array by kangax.

function PowerArray() {
    var arr = [];
    arr.push.apply(arr, arguments);
    arr.__proto__ = PowerArray.prototype;
    return arr;
}

or the modified version consistent with current implementation.

function PowerArray(array) {
    var load = (arguments.length > 0) ? array.slice(0) : [];
    load.__proto__ = PowerArray.prototype;
    return load;
}

Proposed PowerArray constructor vs. existing PowerArray constructor

Pros:

  • Fast version of concat, slice.
  • Fast conversion of Array to PowerArray.

Cons:

  • non-standard proto property

PowerArray vs. BoostArray:

Pros:

  • Unlike BoostArray(), the PowerArray() constructor does not alter the original array, returning a new object.
  • Uses standard method names (.forEach, .map, .filter).

Cons:

  • "Constructor" is slower.
  • Requires slower PowerArray constructor in every prototype method.
  • No option to add fast methods to Array.prototype.
  • No standard compliant Array.prototype methods. (BoostArray has both compliant .forEach and faster .$forEach)

Hypercubed avatar Dec 05 '14 10:12 Hypercubed

Hey Jayson, agreed with everything you said. The biggest problem for me is represented by the proto non standard property, is this going to kill PowerArray in IE? I'd assume we can even implement some logic on whether to use or not proto if we are in an IE environment, but it sounds ugly at best.

techfort avatar Dec 08 '14 13:12 techfort

If you look at the table at the end of the article I linked above (http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/) I think it shows that Direct Extension (what I have done in BoostArray) is the most compatible method. According to MDN (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) __proto__ is deprecated but compatible with IE >= 11. In ECMAScript 6 they add Object.setPrototype() which can be shimmed as:

Object.setPrototypeOf = function(oInstance, oProto) {
  oInstance.__proto__ = oProto;
  return oInstance;
};

Unfortunately I don't see any other way to make a fast constructor.

Hypercubed avatar Dec 09 '14 02:12 Hypercubed

Could have both ways; comparable & fast constructor. Bit of extra work since it would likely require a build tool to split the 2 versions (like lodash does). But some will appreciate having a better targeted version for their use-case.

tomByrer avatar Jun 14 '15 23:06 tomByrer