6

It should be quite easy to implement array.map() that is defined in ECMA-262, which takes a function and this function will be called by 3 arguments: element value, index, the array.

But what about for sparse array? Obviously we don't want to iterate from index 0 to 100,000 if only index 0, 1, 2, and 100,000 has an element and otherwise is sparse from index 3 to 99,999. I can think of using arr.slice(0) or arr.concat() to clone the array, and then put in the replaced values, but what if we don't use slice or concat, is there another way to do it?

The solution I came up with using slice() is:

Array.prototype.collect = Array.prototype.collect || function(fn) {
    var result = this.slice(0);

    for (var i in this) {
      if (this.hasOwnProperty(i))
        result[i] = fn(this[i], i, this);  // 3 arguments according to ECMA specs
    }
    return result;
};

(collect is used to try out the code, as that's another name for map in some language)

4

2 回答 2

3

这应该很容易,但有一些特殊的地方。

允许回调函数修改相关数组。它添加或删除的任何元素都不会被访问。因此,我们似乎应该使用 Object.keys 之类的东西来确定要访问的元素。

此外,结果被定义为一个新数组,“好像由”数组构造函数使用旧数组的长度“创建”一样,所以我们不妨使用该构造函数来创建它。

这是一个考虑到这些事情的实现,但可能缺少其他一些细微之处:

function map(callbackfn, thisArg) {
  var keys = Object.keys(this),
    result = new Array(this.length);

  keys.forEach(function(key) {
    if (key >= 0 && this.hasOwnProperty(key)) {
      result[key] = callbackfn.call(thisArg, this[key], key, this);
    }
  }, this);

  return result;
}

我假设 Object.keys 按数字顺序返回数组的键,我认为这是实现定义的。如果没有,您可以对它们进行排序。

于 2012-10-10T15:00:45.370 回答
0

你不需要使用this.slice(0). 您可以创建result一个数组并将值分配给任何索引:

Array.prototype.collect = Array.prototype.collect || function(fn) { 
  var result = [];
  for(var i in this) {
    if (this.hasOwnProperty(i)) { 
      result[i] = fn(this[i]);
    }
  }
  return result;
}
于 2012-10-10T14:30:54.300 回答