1
\$\begingroup\$

As it is impossible to use Array methods on new Array(n), e.g. new Array(5).map(/* [some callback] */), I deviced a pseudo static Array method.

The idea is to call an anonymous function that fills an empty Array with n times the value undefined. In its simplest form it returns an Array for which Array-methods are applicable.

If you supply parameters (a callback method (Function), the method identifier itself (String, default = 'map') and optionally an initial value, the callback method mapCB is applied to the (Array)method, and the resulting Array is returned.

It looks like this:

window.addEventListener('load', function () {
    Array.create = function (n, mapCB, method, initial) {
                             method = method in [] ? method : 'map';
                             var nwArr = ( function (nn){
                                             while (nn--) 
                                               this.push(undefined); 
                                             return this; } )
                                           .call([],n);
                             return mapCB ? nwArr[method](mapCB, initial) : nwArr;
    };
    // usage examples
    var someArr0 = Array.create(100).map(function (v, i) {return i;});
    var someArr1 = Array.create(100, function (v, i) {return this + i;}, 'map', 5);
    var someArr2 = Array.create(100, function (p, n, i) {return p+i;}, 'reduce', 0);
    Helper.log2Screen('someArr0: [ <code>',someArr0.join(', '),'</code> ]');
    Helper.log2Screen('someArr1: [ <code>',someArr1.join(', '),'</code> ]');
    Helper.log2Screen('someArr2: <code>',someArr2,'</code>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://www.nicon.nl/genericsvc/fiddle/fiddlemeta.js"></script>

Do you think it's useful, or are there better way to achieve this?

I'm aware of the Array.apply(undefined, Array(n)) to create a usable Array, but that will run into a maximum call stack error at some point with a large n used.

Based on the comments and given answer, a more readable approach would be:

    function createArrayWithNElements(nElements, defaultValue) {
      var arr = [];
      for (var i=0; i < nElements; i+=1) {
         arr.push(defaultValue);
      };
      return arr;
    }
    function createArrayWithNElementsAndApplyMethod(n, methodObj) {
      var arr = createArrayWithNElements(n);
      return arr[methodObj.method](methodObj.callback, methodObj.initialValue);
    }
    Array.create = createArrayWithNElements;
    Array.createAndApply = createArrayWithNElementsAndApplyMethod;
    // usage examples
    Array.create( 10, 0 ); //=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    Array.createAndApply( 10, { method:'map', 
                                callback: function (v, i) {return this + i;},
                                initialValue: 5 } );
    //=> [5, 6, 7, 8, 9, 10, 11, 12, 13, 14] 
\$\endgroup\$
  • \$\begingroup\$ Why don't you explain in words what you're trying to accomplish rather than try to make us reverse engineer what you have? \$\endgroup\$ – jfriend00 Oct 28 '14 at 10:02
  • \$\begingroup\$ Myself and a colleague were talking about this the other day when trying to make a repeatString function with new Array(5).join('x');. join() does work on a newly constructed array but we found map() didn't. \$\endgroup\$ – Adrian Lynch Oct 28 '14 at 10:12
  • \$\begingroup\$ @jfriend00: better? \$\endgroup\$ – KooiInc Oct 28 '14 at 10:14
  • 2
    \$\begingroup\$ If I ran into any of those last three lines of code in some code I was working on, I would have absolutely no idea what they did and once I found the .create() method somewhere, I'd still not know what they did without a lot of study. I'd much rather see separate named functions that have clear names indicating what they do. This looks cryptic as it tries to overload a single non-descriptive method with a whole bunch of functionality. In my hierarchy of importance, readability and ease of understanding are way more important than brevity and this appears to only be optimizing for brevity. \$\endgroup\$ – jfriend00 Oct 28 '14 at 10:21
4
\$\begingroup\$

As the comments already say, I'd not put too much into such a function, that is, IMO creating the array with initial size and elements is probably enough to make a difference.

Array.create = function (n, initial) {
  var result = new Array (n);
  for (var i = 0; i < n; ++i)
    result[i] = initial;
  return result;
};

// Array.create (3);
// Array.create (5, "hi").map (...);

Which also could just be a regular function makeArray or so I guess. So you get one benefit without the rather cryptic calling convention (mapCB/method) you have at the moment. Sure, it's a matter of opinion, but I had to take a moment to understand what that is supposed to do, so arguably that is not a good choice if you want other people to read that later.

And good point about the apply, I wouldn't want to see that in real code as well.

\$\endgroup\$
  • \$\begingroup\$ A reasonable extension to this would be instead of passing an initial value to pass a function that accepts the index and lets you return what you want from there. So Array.create(10, identity); //=> [0 .. 9] and Array.create(5, square); //=> [0, 1, 4, 9, 16]. This strikes me as quite useful without getting into the complexity in the original solution. \$\endgroup\$ – Scott Sauyet Oct 30 '14 at 18:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.