Three map implementations in javascript. Which one is better?

I wrote a simple map implementation for some task. Then, out of curiosity, I wrote two more. I like map1, but the code is pretty hard to read. If anyone is interested, I would appreciate a simple code review.

Which one is better? Do you know any other way to implement this in javascript?

var map = function(arr, func) { var newarr = []; for (var i = 0; i < arr.length; i++) { newarr[i] = func(arr[i]); } return newarr; }; var map1 = function(arr, func) { if (arr.length === 0) return []; return [func(arr[0])].concat(funcmap(arr.slice(1), func)); }; var map2 = function(arr, func) { var iter = function(result, i) { if (i === arr.length) return result; result.push(func(arr[i])); return iter(result, i+1); }; return iter([], 0); }; 

Thanks!

EDIT

I think of such a function in general.

For example, right now I will use it for iteration as follows:

 map(['class1', 'class2', 'class3'], function(cls) { el.removeClass(cls); }); 

or

 ids = map(elements, extract_id); /* elements is a collection of html elements, extract_id is a func that extracts id from innerHTML */ 
+4
source share
6 answers

I think it depends on what you want to do when func can modify the array. I would often be mistaken on the side of simplicity and length of the sample.

You can always specify the size of the output, as in

 var map = function(arr, func) { var n = arr.length & 0x7fffffff; // Make sure n is a non-neg integer var newarr = new Array(n); // Preallocate array size var USELESS = {}; for (var i = 0; i < n; ++i) { newarr[i] = func.call(USELESS, arr[i]); } return newarr; }; 

I used the form func.call () instead of just func (...) because I don't like calling the code provided by the user without specifying what 'this' is, but YMMV.

+2
source

What about the map implementation used initially on Firefox and SpiderMonkey, I think it's very simple:

 if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; // make sure length is a positive number if (typeof fun != "function") // make sure the first argument is a function throw new TypeError(); var res = new Array(len); // initialize the resulting array var thisp = arguments[1]; // an optional 'context' argument for (var i = 0; i < len; i++) { if (i in this) res[i] = fun.call(thisp, this[i], i, this); // fill the resulting array } return res; }; } 

If you do not want to extend Array.prototype , declare it as an expression of a normal function.

+5
source

As a reference, the map is implemented as follows in jQuery

 map: function( elems, callback ) { var ret = []; // Go through the array, translating each of the items to their // new value (or values). for ( var i = 0, length = elems.length; i < length; i++ ) { var value = callback( elems[ i ], i ); if ( value != null ) ret[ ret.length ] = value; } return ret.concat.apply( [], ret ); } 

which seems most similar to your first implementation. I would say that the first one is preferable, as it is easy to read and understand. But if performance is your concern, profile them.

+3
source

This first one is most suitable. Repeating one level for each element of the array may make sense in a functional language, but in the language of procedures without tail tail optimization, this is crazy.

However, Array already has a map function: it is defined by ECMA-262 Fifth Edition and, as a built-in function, would be the best choice. Use this:

 alert([1,2,3].map(function(n) { return n+3; })); // 4,5,6 

The only problem is that Fifth Edition is not supported by all current browsers: in particular, Array extensions are not available in IE. But you can fix this with a little correction work on the Array prototype:

 if (!Array.prototype.map) { Array.prototype.map= function(fn, that) { var result= new Array(this.length); for (var i= 0; i<this.length; i++) if (i in this) result[i]= fn.call(that, this[i], i, this); return result; }; } 

This version, according to the ECMA standard, allows you to pass an optional object to bind to this in a function call and skips any missing values ​​(for this, JavaScript has a list of length 3, where there is no second element).

+2
source

Something is wrong with the second method. "funcmap" should not be changed to "map1"?

If so - this method loses, since the concat () method is expensive - it creates a new array from the given ones, so it must allocate additional memory and execute in O (array1.length + array2.length).

I like your first implementation best - it’s definitely the easiest to understand and seems fast to me. No additional declaration (for example, in third order), additional function calls - only one for loop assignment and array.length.

+1
source

I would say that the first wins on simplicity (and is immediately clear); performance will depend heavily on what the engine optimizes, so you will need to profile in the engines you want to support.

0
source

All Articles