1 /**
  2  * @fileOverview This file contains new methods for the Array class
  3  */
  4 /**
  5  * @name Array
  6  * @class A built-in class for expressing ordered lists of values.
  7  */
  8 
  9 /**
 10  * Create a new array of a specified length filled with a certain value
 11  * 
 12  * @constructs
 13  * @param {Number} size The size of the array to create
 14  * @param [value=undefined] The value to populate all the items in the array with
 15  */
 16 Array.fill = function fill(size, value) {
 17 	var arr = new Array(Number(size||0));
 18 	for ( var i = arr.length-1; i >= 0; --i )
 19 		arr[i] = value;
 20 	return arr;
 21 };
 22 
 23 /**
 24  * Return a new array with the contents of this array repeated over
 25  * `num` amount of times.
 26  * 
 27  * @param {Number} num The number of times to repeat the array
 28  * @return {Array} The new repeated array
 29  */
 30 Array.prototype.repeat = function repeat(num) {
 31 	return Array.prototype.concat.apply([], Array.fill(num, this));
 32 };
 33 
 34 /**
 35  * Check if the array contains an item
 36  * 
 37  * @param {Number} item The item to look for
 38  * @return {Boolean} Whether or not the item was found within the array
 39  */
 40 Array.prototype.has = function has(item) {
 41 	return this.indexOf(item) > -1;
 42 };
 43 
 44 /**
 45  * Return an array where all duplicate items have been removed
 46  * 
 47  * @return {Array} A new array with a unique list of all items in this array
 48  */
 49 Array.prototype.unique = function unique() {
 50 	return this.filter(function(item, i, arr) { return arr.indexOf(item) >= i; });
 51 };
 52 
 53 /**
 54  * Shuffle the array
 55  * 
 56  * @return {Array} The same array for convenience
 57  */
 58 Array.prototype.shuffle = function shuffle() {
 59 	return this.sort(function() { return Math.random() > 0.5 ? 1 : -1; });
 60 };
 61 
 62 /**
 63  * Return an item from an index in the array
 64  * This is provided for client-side convenience so you have the same technique
 65  * for getting an item on both an array and a list of html nodes.
 66  * 
 67  * @param {Number} i The index to return the item from
 68  */
 69 Array.prototype.item = function item(i) {
 70 	return this[i];
 71 };
 72 
 73 /**
 74  * Remove the first (or more) occurrence(s) of an item from the array
 75  * 
 76  * @param item The item to remove
 77  * @param {Number} [max=1] The max number of items to remove, use Infinity to remove them all
 78  */
 79 Array.prototype.remove = function remove(item, max) {
 80 	max = max || 1;
 81 	while(max) {
 82 		var i = this.indexOf(item);
 83 		if( i < 0 ) break;
 84 		this.splice(i, 1);
 85 		max--;
 86 	}
 87 	// ToDo: Determine a reasonable return value
 88 };
 89 
 90 /**
 91  * Append a list of items from an array onto the end of this array
 92  * 
 93  * @param items Array The array of items to append to this array
 94  */
 95 Array.prototype.append = function append(items) {
 96 	return Array.prototype.push.apply( this, items );
 97 };
 98 
 99 /**
100  * Clear an array of all items
101  */
102 Array.prototype.clear = function clear() {
103 	return this.splice(0, this.length);
104 };
105 
106 /**
107  * Clean out all undefined and null values inside of an array
108  * if false is passed to empty then only undefined items are cleaned
109  * if true is passed to empty then empty strings will also be cleaned
110  * 
111  * @param {Boolean} [empty=undefined] Whether to also clean out empty strings or to not clear out nulls
112  */
113 Array.prototype.clean = function clean(empty) {
114 	return this.filter(function(item) {
115 		if ( item === undefined ) return false;
116 		if ( empty !== false && item === null ) return false;
117 		if ( empty === true && item === "" ) return false;
118 		return true;
119 	});
120 };
121 
122 /**
123  * Return a random item from this array.
124  * 
125  * @return A random item from the array
126  */
127 Array.prototype.rand = function() {
128 	return this[Math.rand(0, this.length-1)];
129 };
130 
131 /**
132  * A version of array.reduce() which only passes the two values to reduce on
133  * to the callback so you can use native methods like Math.max inside a reduce.
134  * 
135  * @param Function fn The callback function
136  */
137 Array.prototype.reduceNative = function reduceNative(fn) {
138 	return this.reduce(function(a, b) { return fn(a, b); });
139 };
140 
141 /**
142  * Returns a new version of this array which has been flattened
143  * Flattening turns an array like [[1,2,3], [4,5,6], [7,8,9]];
144  * into one like [1,2,3,4,5,6,7,8,9];
145  * 
146  * @return {Array} The new flattened array
147  */
148 Array.prototype.flat = function flat() {
149 	var arr = [];
150 	function reduce(item) {
151 		if( item instanceof Array )
152 			item.forEach(reduce);
153 		else arr.push(item);
154 	};
155 	this.forEach(reduce);
156 	return arr;
157 };
158 
159