简体   繁体   中英

How to implement Javascript ECMA 5's array.map() for sparse array?

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)

It should be easy, but there are a few peculiar points.

The callback function is allowed to modify the array in question. Any elements it adds or removes are not visited. So it seems we should use something like Object.keys to determine which elements to visit.

Also, the result is defined to be a new array "created as if by" the array constructor taking the length of the old array, so we might as well use that constructor to create it.

Here's an implementation taking these things into account, but probably missing some other subtleties:

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;
}

I am assuming Object.keys returns the keys of the array in numerical order, which I think is implementation defined. If it doesn't, you could sort them.

You don't need to use this.slice(0) . You can just make result an array and assign values to any index:

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM