我为某项任务编写了一个简单的地图实现。然后,出于好奇,我又写了两篇。我喜欢map1,但代码有点难以阅读。如果有人感兴趣,我会很感激简单的代码审查。
哪一个更好?你知道在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);
};
谢谢!
修改
我正在考虑这种功能。
例如,现在我将使用它来迭代这样:
map(['class1', 'class2', 'class3'], function(cls) {
el.removeClass(cls);
});
或
ids = map(elements, extract_id);
/* elements is a collection of html elements,
extract_id is a func that extracts id from innerHTML */
答案 0 :(得分:5)
如果在Firefox和SpiderMonkey上本地使用的map实现怎么样,我认为这是非常直接的:
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;
};
}
如果您不想扩展Array.prototype
,请将其声明为正常的函数表达式。
答案 1 :(得分:3)
作为参考,map在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 );
}
这似乎与您的第一个实现最相似。我会说第一个是首选,因为它是最简单的阅读和理解。但如果您关注性能,请对其进行分析。
答案 2 :(得分:2)
我认为这取决于当func可能更改数组时你想要map做什么。我倾向于在简单性和样本长度方面犯错一次。
您始终可以在
中指定输出尺寸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;
};
我使用了func.call()形式而不仅仅是func(...),因为我不喜欢调用用户提供的代码而没有指定'this'是什么,而是YMMV。
答案 3 :(得分:2)
第一个是最合适的。对于每个数组项递归一个级别在函数式语言中可能有意义,但是在没有尾调用优化的过程语言中,它是疯狂的。
但是,map
上已经有Array
函数:它由ECMA-262第五版定义,作为内置函数,它将是最佳选择。使用:
alert([1,2,3].map(function(n) { return n+3; })); // 4,5,6
唯一的问题是所有当前浏览器都不支持第五版:特别是IE中不存在数组扩展。但你可以通过对Array原型进行一些补救工作来解决这个问题:
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;
};
}
根据ECMA标准,此版本允许在函数调用中传入可选对象以绑定到this
,并跳过任何缺失值(在JavaScript中合法,以获得长度列表3,没有第二项)。
答案 4 :(得分:1)
第二种方法有问题。 'funcmap'不应该更改为'map1'?
如果是这样 - 这个方法失败了,因为concat()方法很昂贵 - 从给定的方法创建新数组,所以必须分配额外的内存并在O(array1.length + array2.length)中执行。
我最喜欢你的第一个实现 - 它绝对是最容易理解的,并且似乎很快就可以执行了。没有额外的声明(比如第三种方式),额外的函数调用 - 只有一个用于循环和array.length赋值。
答案 5 :(得分:0)
我会说第一个赢得简单(并立即可理解);性能将高度依赖于手头的引擎优化,因此您必须在您想要支持的引擎中进行分析。