Wanted: standard Array function to append an array's elements to another array

Jeff Walden jwalden+es at MIT.EDU
Mon Jul 25 12:54:50 PDT 2011


If I have one array, and I want to append the contents of an arbitrary array to it, and I don't need the unmodified first array after appending the second array's elements to it, I have three options.

First, I can use Array.prototype.concat to create a new array consisting of the first array, then the contents of the second.  But this creates a new array rather than mutating the first array, so it potentially wastes memory proportional to the size of the first array, barring complicated heuristics to recognize and avoid the waste.  Potentially worse, if any element of the second array is an Array, instead of that array being appended, its elements will be appended.

Second, I can use Array.prototype.push:

   Array.prototype.push.apply(firstArray, secondArray);

This avoids the memory-wastefulness concern, and it doesn't treat Array items specially.  But it introduces a third concern: the JavaScript stack size limit, if the second array contains a particularly large number of elements.  This might manifest itself as causing a stack overflow exception, or it might cause only some of the elements of the second array to be appended (an arguably buggy mitigation mechanism, but one some engines use, at least currently).

Third, I can use Array.prototype.splice, passing in |start = length| and |deleteCount = 0|.  But splice too encounters the stack size limit problem.  Worse, because its arguments are (start, deleteCount, newElt1, newElt2, ...), constructing the array of arguments with which to apply the splice method seems to require complicated copy-on-write array-element-sharing to mutate the first array without consuming twice the first array's memory, or some other tricky scheme.  For such schemes to be effective here, the programmer would have to structure his code pretty carefully, being sure to only use Array.prototype.unshift, say, to implement it.  And there's a bootstrapping problem to creating the array of arguments to supply to splice in order to append the elements of an array to the first array.

I see no problem-free way to append an array's elements to another array without doing it manually.  That's not hard, but it's error-prone, and it's much trickier to recognize and correctly optimize.  I think there should be a way to append elements of an arbitrarily sized array to another array, mutating that array in-place, without consuming excess memory.  I'm not too concerned about its precise semantics or about what it's named.  For a starting point I'll propose Array.prototype.pushAll (or extend, following Python, but again, I don't really care about the exact name right now):

   Object.defineProperty(Array.prototype, "pushAll",
   {
     enumerable: false, configurable: true, writable: true,
     value: function pushAll(other)
     {
       "use strict";
       var t = ToObject(this);
       var length = ToUint32(t.length);
       var otherLen = other.length;
       for (var i = 0, j = length; i < otherLen; i++, j++)
         t[j] = other[i];
       t.length = j;
       return void 0;
     },
   });

Comments?  Suggestions?  Requests for changes?

I also had the thought that it might be nice to be able to push a subrange of the elements of an array.  You could do that by adding optional |start, length| or |start, end| arguments to the method, with corresponding implementation changes.  I'm not sure whether this would be useful enough to warrant the complexity, but it would be easy to add if people thought it made sense.

Jeff


More information about the es-discuss mailing list