1 // vim: set et sw=4 ts=4 sts=4 fdm=marker ff=unix fenc=utf8
2 /**
3 * Javascript 的 Array 扩展包
4 *
5 * 获取自 Trba 库(http://tbra.googlecode.com)
6 *
7 * @see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array
8 */
9
10 /**
11 * 获取元素在数组中的位置
12 *
13 * @param Object 元素
14 * @param Intger fromIndex - 起始位置
15 * @return Intger
16 */
17 if (!Array.prototype.indexOf) {
18 Array.prototype.indexOf = function (obj, fromIndex) {
19 if (fromIndex == null) {
20 fromIndex = 0;
21 } else if (fromIndex < 0) {
22 fromIndex = Math.max(0, this.length + fromIndex);
23 }
24 for (var i = fromIndex; i < this.length; i++) {
25 if (this[i] === obj)
26 return i;
27 }
28 return -1;
29 };
30 }
31
32
33 /**
34 * 反向查找元素在数组中的位置
35 *
36 * @param object 元素
37 * @param fromIndex 起始位置
38 * @return int
39 */
40 if (!Array.prototype.lastIndexOf) {
41 Array.prototype.lastIndexOf = function (obj, fromIndex) {
42 if (fromIndex == null) {
43 fromIndex = this.length - 1;
44 } else if (fromIndex < 0) {
45 fromIndex = Math.max(0, this.length + fromIndex);
46 }
47 for (var i = fromIndex; i >= 0; i--) {
48 if (this[i] === obj)
49 return i;
50 }
51 return -1;
52 };
53 }
54
55
56 /**
57 * Executes a provided function once per array element.
58 *
59 * @param fucntion Function to test each element of the array.
60 * @link http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach
61 */
62 if (!Array.prototype.forEach) {
63 Array.prototype.forEach = function(fun /*, thisp*/) {
64 var len = this.length;
65 if (typeof fun != "function") {
66 throw new TypeError();
67 }
68 var thisp = arguments[1];
69 for (var i = 0; i < len; i++) {
70 if (i in this) {
71 fun.call(thisp, this[i], i, this);
72 }
73 }
74 };
75 }
76
77
78 /**
79 * Creates a new array with all elements that pass the test
80 * implemented by the provided function.
81 *
82 * @param fucntion Function to test each element of the array.
83 * @link http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter
84 * @return array
85 */
86 if (!Array.prototype.filter) {
87 Array.prototype.filter = function(fun) {
88 var len = this.length;
89 if (typeof fun != "function") {
90 throw new TypeError();
91 }
92 var res = [];
93 var thisp = arguments[1];
94 for (var i = 0; i < len; i++) {
95 if (i in this) {
96 var val = this[i]; // in case fun mutates this
97 if (fun.call(thisp, val, i, this)) {
98 res.push(val);
99 }
100 }
101 }
102 return res;
103 };
104 }
105
106
107 /**
108 * Creates a new array with the results of calling
109 * a provided function on every element in this array.
110 *
111 * @param fucntion Function to test each element of the array.
112 * @link http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map
113 * @return array
114 */
115 if (!Array.prototype.map) {
116 Array.prototype.map = function(fun /*, thisp*/) {
117 var len = this.length;
118 if (typeof fun != "function") {
119 throw new TypeError();
120 }
121 var res = new Array(len);
122 var thisp = arguments[1];
123 for (var i = 0; i < len; i++) {
124 if (i in this) {
125 res[i] = fun.call(thisp, this[i], i, this);
126 }
127 }
128 return res;
129 };
130 }
131
132
133 /**
134 * Tests whether some element in the array passes the
135 * test implemented by the provided function.
136 *
137 * @param fucntion Function to test each element of the array.
138 * @link http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
139 * @return bool
140 */
141 if (!Array.prototype.some) {
142 Array.prototype.some = function(fun /*, thisp*/) {
143 var len = this.length;
144 if (typeof fun != "function") {
145 throw new TypeError();
146 }
147
148 var thisp = arguments[1];
149 for (var i = 0; i < len; i++) {
150 if (i in this && fun.call(thisp, this[i], i, this)) {
151 return true;
152 }
153 }
154
155 return false;
156 };
157 }
158
159
160 /**
161 * Tests whether all elements in the array
162 * pass the test implemented by the provided function.
163 *
164 * @param function Function to test for each element.
165 * @link http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
166 */
167 if (!Array.prototype.every) {
168 Array.prototype.every = function(fun) {
169 var len = this.length;
170 if (typeof fun != "function") {
171 throw new TypeError();
172 }
173 var thisp = arguments[1];
174 for (var i = 0; i < len; i++) {
175 if (i in this && !fun.call(thisp, this[i], i, this)) {
176 return false;
177 }
178 }
179 return true;
180 };
181 }
182
183
184 /**
185 * Apply a function simultaneously against two values
186 * of the array (from left-to-right) as to reduce it to a single value.
187 *
188 * @param function Function to test for each element.
189 * @link http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:reduce
190 */
191 if (!Array.prototype.reduce) {
192 Array.prototype.reduce = function(fun /*, initial*/) {
193 var len = this.length;
194 if (typeof fun != "function") {
195 throw new TypeError();
196 }
197 // no value to return if no initial value and an empty array
198 if (len == 0 && arguments.length == 1) {
199 throw new TypeError();
200 }
201
202 var i = 0;
203 if (arguments.length >= 2) {
204 var rv = arguments[1];
205 } else {
206 do {
207 if (i in this) {
208 rv = this[i++];
209 break;
210 }
211 // if array contains no values, no initial value to return
212 if (++i >= len) {
213 throw new TypeError();
214 }
215 } while (true);
216 }
217
218 for (; i < len; i++) {
219 if (i in this) {
220 rv = fun.call(null, rv, this[i], i, this);
221 }
222 }
223
224 return rv;
225 };
226 }
227
228
229 /**
230 * Apply a function simultaneously against two values
231 * of the array (from right-to-left) as to reduce it to a single value.
232 *
233 * @param function Function to test for each element.
234 * @link http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:reduceRight
235 */
236 if (!Array.prototype.reduceRight) {
237 Array.prototype.reduceRight = function(fun /*, initial*/) {
238 var len = this.length;
239 if (typeof fun != "function") {
240 throw new TypeError();
241 }
242
243 // no value to return if no initial value, empty array
244 if (len == 0 && arguments.length == 1) {
245 throw new TypeError();
246 }
247
248 var i = len - 1;
249 if (arguments.length >= 2) {
250 var rv = arguments[1];
251 } else {
252 do {
253 if (i in this) {
254 rv = this[i--];
255 break;
256 }
257
258 // if array contains no values, no initial value to return
259 if (--i < 0) {
260 throw new TypeError();
261 }
262 } while (true);
263 }
264
265 for (; i >= 0; i--) {
266 if (i in this) {
267 rv = fun.call(null, rv, this[i], i, this);
268 }
269 }
270
271 return rv;
272 };
273 }
274
275
276 /**
277 * 删除数组中重复的元素
278 *
279 * @return Array
280 */
281 if (!Array.prototype.unique) {
282 Array.prototype.unique = function() {
283 var resultArr = [],
284 returnArr = [],
285 origLen = this.length,
286 resultLen;
287
288 function include(arr, value) {
289 for (var i = 0, n = arr.length; i < n; ++i){
290 if (arr[i] === value) {
291 return true;
292 }
293 }
294
295 return false;
296 }
297
298 resultArr.push(this[0]);
299 for (var i = 1; i < origLen; ++i) {
300 if (include(resultArr, this[i])) {
301 returnArr.push(this[i]);
302 } else {
303 resultArr.push(this[i]);
304 }
305 }
306
307 resultLen = resultArr.length;
308 this.length = resultLen;
309 for (var i = 0; i < resultLen; ++i){
310 this[i] = resultArr[i];
311 }
312
313 return returnArr;
314 }
315 }
316
317
318 /**
319 * 检查数组是否包含某元素
320 *
321 * @param object 元素
322 * @return bool
323 */
324 Array.prototype.contains = function (obj) {
325 return this.indexOf(obj) != -1;
326 };
327
328
329 /**
330 * 复制数组中的全部元素
331 *
332 * @return Array
333 */
334 Array.prototype.copy = function (obj) {
335 return this.concat();
336 };
337
338
339 /**
340 * 在 i 之后插入元素
341 *
342 * @param Object 元素
343 * @param Intger 位置
344 */
345 Array.prototype.insertAt = function (obj, i) {
346 this.splice(i, 0, obj);
347 };
348
349
350 /**
351 * 在指定元素之前插入元素
352 *
353 * @param Object obj 插入元素
354 * @param Object obj2 目标元素
355 */
356 Array.prototype.insertBefore = function (obj, obj2) {
357 var i = this.indexOf(obj2);
358 if (i == -1)
359 this.push(obj);
360 else
361 this.splice(i, 0, obj);
362 };
363
364
365 /**
366 * 删除指定位置的元素
367 *
368 * @param Intger 位置
369 */
370 Array.prototype.removeAt = function (i) {
371 this.splice(i, 1);
372 };
373
374
375 /**
376 * 删除一个数组中指定的元素
377 *
378 * @param Object obj 目标元素
379 */
380 Array.prototype.remove = function (obj) {
381 var i = this.indexOf(obj);
382 if (i != -1) {
383 this.splice(i, 1);
384 }
385 };
386
387
388 /**
389 * 删除全部数组中指定的元素
390 *
391 * @param Object obj 目标元素
392 */
393 Array.prototype.removeAll = function (obj) {
394 for (var i = 0, length = this.length; i < length; i++) {
395 var j = this.indexOf(obj);
396 if (j != -1) {
397 this.splice(j, 1);
398 } else {
399 break;
400 }
401 }
402 };