Skip to content

Instantly share code, notes, and snippets.

@kangax
Created July 19, 2010 04:34
Show Gist options
  • Save kangax/481016 to your computer and use it in GitHub Desktop.
Save kangax/481016 to your computer and use it in GitHub Desktop.
// @kangax fix yur SubArray (ES5 flavor) kthxbai
// http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/#ecmascript_5_accessors_to_the_rescue

// (C) Juriy Zaytsev (aka @kangax) - MIT Style License
// http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/

var SubArray = (function() {

  var MAX_SIGNED_INT_VALUE = Math.pow(2, 32) - 1,
   hasOwnProperty = {}.hasOwnProperty,
   isArray = function(v) { return toString.call(v) == '[object Array]'; },
   slice = [].slice,
   toString = {}.toString;

  function getMaxIndex(object) {
    var key, index, maxIndex = 0;
    for (key in object) {
      index = key >>> 0;
      if (index === +key &&
          index < MAX_SIGNED_INT_VALUE &&
          index > maxIndex &&
          hasOwnProperty.call(object, key)) {
        maxIndex = index;
      }
    }
    return maxIndex;
  }

  function isArrayLike(object) {
    return object && (isArray(object) || object.constructor == SubArray);
  }

  function makeSubArray() {
    var length = 0;
    return Object.create(SubArray.prototype, {
      'length': {
        'get': function() {
          var maxIndex = getMaxIndex(this);
          return Math.max(length, maxIndex && maxIndex + 1);
        },
        'set': function(value) {
          var uint = value >>> 0,
           i = uint - 1, oldLen = this.length;

          if (uint !== +value) {
            throw new RangeError;
          }
          while (++i < oldLen) {
            delete this[i];
          }
          length = uint;
        }
      }
    });
  }

  function SubArray(length) {
    var result = makeSubArray(), argLen = arguments.length;
    if (argLen) {
      if (argLen === 1 && typeof length === 'number') {
        result.length = length;
      } else {
        result.push.apply(result, arguments);
      }
    }
    return result;
  }

  if (typeof Array.isArray == 'function' && Array.isArray([]) === true) {
    isArray = Array.isArray;
  }

  SubArray.prototype = [];
  SubArray.prototype.constructor = SubArray;
  SubArray.prototype.toString = SubArray.prototype.toLocaleString = Array.prototype.join;
  SubArray.prototype.concat = function() {
    var item, itemLen, j, i = -1,
     length = arguments.length,
     object = Object(this),
     result = isArrayLike(object) ? slice.call(object, 0) : [object],
     n      = result.length;

    while (++i < length) {
      item = arguments[i];
      if (isArrayLike(item)) {
        j = 0; itemLen = item.length;
        for ( ; j < itemLen; j++, n++) {
          if (j in item) result[n] = item[j];
        }
      } else {
        result[n++] = item;
      }
    }
    return result;
  };

  return SubArray;
})();
@jdalton
Copy link

jdalton commented Jul 19, 2010

hawt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment