某人

此前素未谋面、此后遥遥无期

0%

Array对象

基本描述

Array时javaScript的内置对象,同时也是一个构造函数。用它可以创建数组。

1
2
3
var arr = ['a','b','c'];    // 返回:["a", "b", "c"]
new Array('abc'); // 返回:["abc"]
new Array(['a','b','c']) // 返回:Array[3]

Array对象属性

1
2
3
4
var arr = new Array();

arr.constructor // 返回:function Array() { [native code] }
arr.constructor == Array // 返回:true

静态方法isArray

Array.isArray() 方法用来判断某个值是否为数组。如果是,则返回 true,否则返回 false。

1
2
3
4
5
6
7
8
9
10
var arr = ['a','b','c'];

Array.isArray(arr); // 返回:true

//兼容老浏览器如:IE 8及以前版本,代码运行之前添加以下代码
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}

ECMAScript3的函数方法

ECMAScript3在Array.prototype中定义了一些函数,这些函数作为任何数组的方法都是可用的。

join()

join() 方法将数组中的所有元素连接成一个字符串。
参数:可选,用于指定连接每个数组元素的分隔符,默认逗号。

1
2
3
4
var a = ['a', 'b', 'c'];

a.join(); // 返回:"a,b,c"
a.join('-'); // 返回:"a-b-c"

push()和pop()

push方法用于在数组的末端添加一个或多个元素,并返回添加后的数组的长度。
pop方法用于删除数组的最后一个元素,并返回该元素

1
2
3
4
5
6
var arr = ['a','b','c'];

arr.push('e','f','g'); // 返回:6

arr.pop(); // 返回:"c"
[].pop(); // 返回:undefined

reverse()

reverse方法用于颠倒数组中元素的顺序,返回改变后的原数组

1
2
3
var arr = ['a', 'b', 'c'];

arr.reverse(); // 返回:["c", "b", "a"]

concat()

将传入的数组或非数组值与原数组合并,组成一个新的数组并返回
语法:array.concat(value1, value2, …, valueN)

1
2
3
var arr = ['a', 'b', 'c'];

arr.concat('e',['f','g']); 返回:["a", "b", "c", "e", "f", "g"]

shift()和unshift()

shift方法用于删除数组的第一个元素,并返回该元素。
unshift方法用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度

1
2
3
4
5
var arr = ['a', 'b', 'c'];

arr.shift(); // 返回:"a"

arr.unshift('-a','-b'); // 返回:5; arr is ["-a", "-b", "a", "b", "c"]

slice()和splice()

slice方法用于提取原数组的一部分,返回一个新数组。
语法:array.slice(begin [,end])
参数:begin,索引处开始,省略,则默认0; end,索引处结束,省略,则取到数组末尾

splice方法用于删除原数组的一部分成员,并可以在被删除的位置添加入新的数组成员。它的返回值是被删除的元素
语法:array.splice(start, deleteCount[, item1[, item2[, …]]])
参数:start索引处开始,超出了数组的长度,则从数组末尾开始,如是负值,则表示从数组末位开始的第几位;deleteCount,整数,移除的数组元素的个数,deleteCount大于start之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)

1
2
3
4
5
6
7
8
9
var arr = ['a', 'b', 'c'];

//数组未改变
arr.slice(); // 返回:["a", "b", "c"]
arr.slice(0,1); // 返回:["a"]

//数组已改变
arr.splice(0,1) // 返回:["a"]
arr.splice(0,2,'-a','-b'); // 返回:["a", "b"];arr is ["-a", "-b", "c"]

sort()方法

sort默认按照字典顺序排序,原数组将被改变。
语法:arr.sort([compareFunction])
参数:可选。用来指定按某种顺序进行排列的函数。如果省略,元素按照字典顺序进行排序。
补充: compareFunction(a, b),小于0,那么a会被排列到b之前;等于 0,a 和 b 的相对位置不变;大于0, b会被排列到a之前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Eg1:
var arr = ['b', 'a', 'c'];
arr.sort() // 返回:["a", "b", "c"]

//Eg2:
var arr = [
{name:'土豪1',money:500},
{name:'土豪2',money:1000},
{name:'土豪3',money:500},
{name:'土豪4',money:1}
]
arr.sort(function(a,b){
if(a.money > b.money ){ return 1;}
if(a.money < b.money ){ return -1;}
return 0;
});
排序结果arr是这样的:
var arr = [
{name:'土豪4',money:1}
{name:'土豪1',money:500},
{name:'土豪3',money:500},
{name:'土豪2',money:1000}
]

toString()和toLocaleString()

toString 把数组转换为字符串,并返回结果。
toLocaleString把数组转换为本地数组,并返回结果。

1
2
3
4
var arr = ['a', 'b', 'c'];

arr.toString(); // 返回:"a,b,c"
arr.toLocaleString(); // 返回:"a,b,c"

ECMAScript5中的数组方法

ECMAScript 5 定义了9个新的数组方法,分别是map、forEach、filter、every、some、reduce、reduceRight、indexOf和lastIndexOf;
这些方法可在数组、字符串、类数组上使用;
参数:(callback[, thisArg])
callback:currentValue当前项(指遍历时正在被处理那个数组项)的值;index当前项的索引(或下标);array数组本身。
thisArg:可选参数,用来当作callback 函数内this的值的对象

forEach方法

forEach() 方法让数组的每一项都执行一次给定的函数。
语法:array.forEach(callback[, thisArg])

1
2
3
4
5
6
7
var arr = [],
num = [1,2,3,4,5];
num.forEach(function(currentValue){
arr.push(currentValue+1);
},arr);

arr is : [2, 3, 4, 5, 6]

map方法

map方法对数组的所有成员依次调用一个函数,根据函数结果返回一个新数组。
语法:array.map(callback[, thisArg])

1
2
3
4
5
6
var num = [1,2,3,4,5];
num.map(function(currentValue){
return currentValue+1;
});

结果:[2, 3, 4, 5, 6]

filter方法

语法:arr.filter(callback[, thisArg])

filter() 方法使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组
语法:arr.filter(callback[, thisArg])

1
2
3
4
5
6
var num = [1,2,3,4,5];
num.filter(function(currentValue){
return currentValue % 2 == 0;
})

结果:[2, 4]

every和some方法

every() 方法测试数组的所有元素是否都通过了指定函数的测试。所有通过返回true,否则false
语法:arr.every(callback[, thisArg])

some() 方法测试数组中的某些元素是否通过了指定函数的测试。一有通过就返回true,否则false
语法:arr.some(callback[, thisArg])

1
2
3
4
5
6
7
8
9
10
11
var num = [1,2,3,4,5];
num.every(function(currentValue){
return currentValue>4;
})
结果:fasle;

var num = [1,2,3,4,5];
num.some(function(currentValue){
return currentValue>4;
})
结果:true

reduce和reduceRight方法

reduce方法和reduceRight方法的作用,是依次处理数组的每个元素,最终累计为一个值,reduce对数组元素的处理顺序是从左到右,reduceRight则是从右到左。
语法:arr.reduce(callback,[initialValue])
callback参数有:
previousValue:上一次调用回调返回的值,或者是提供的初始值(initialValue)
currentValue:数组中当前被处理的元素
index:下标
array:调用 reduce 的数组
initialValue:作为第一次调用 callback 的第一个参数。

1
2
3
4
5
6
7
8
9
10
11
var num = [1,2,3,4,5];
num.reduce(function(previousValue,currentValue){
return previousValue + currentValue;
});
结果是:15

var num = [1,2,3,4,5];
num.reduce(function(previousValue,currentValue){
return previousValue + currentValue;
},10)
结果是:25

indexOf和lastIndexOf方法

indexOf返回给定元素在数组中第一次出现的下标,如果没有出现则返回-1
语法:arr.indexOf(searchElement[, fromIndex = 0])

lastIndexOf返回给定元素在数组中最后一次出现的下标,如果没有出现则返回-1,从数组的后面向前查找,从 fromIndex 处开始
语法:arr.lastIndexOf(searchElement[, fromIndex = arr.length - 1])

1
2
3
var num = [1,2,3,4,5];
num.indexOf(3,1) // 返回:2
num.lastIndexOf(3,4) // 返回:2

兼容旧环境(Polyfill)

ECMAScript 5这些方法,一些旧浏览器不支持,主要是IE 8及以前版本,我们就要在使用之前对它进行处理,然而Mozilla网络开发者(Mozilla Developer Network,简称MDN)就对此进行了处理:

兼容forEach

这是我对MDN的forEach方法,加的一点注释。并保留了原来的英文注释。

看着似乎有点长,但是把注释去掉只有几行代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
if (!Array.prototype.forEach) {

Array.prototype.forEach = function forEach(callback, thisArg) {
var T, k;
if (this == null) {
throw new TypeError("this is null or not defined");
}

// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
// 将当前this对象作为参数传递给Obejct对象,返回一个与给定值对应类型的对象。该对象包装了给定的参数。
var O = Object(this);

// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
// 进行无符号位移运算符,将所有非数值转换成0,所有大于等于0数取整数部分,并赋值变量len
var len = O.length >>> 0;

// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== "function") {
throw new TypeError(callback + " is not a function");
}

// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
// 检查arguments对象是否有第二个参数,如果有则进行操作。
if (arguments.length > 1) {
T = thisArg;
}

// 6. Let k be 0
k = 0;

// 7. Repeat, while k < len
// 循环每一项,调用指定函数
while (k < len) {

var kValue;

// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
/*
* a. in运算符希望它的左操作数是一个字符串或可以转换为字符串;
* 希望他的右操作数是一个对象;
* 如果右侧对象拥有一个名为左操作数值的属性名,那么表达式返回true
* b. 对于数组属性需要指定数字形式的索引值来表示数组的属性名称(固有属性除外,如length)
* var arr =['a','b','c'];
* 0 in arr; => 返回:true
* 3 in arr; => 返回:false
*/
if (k in O) {

// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
// 获取值对应赋给给变量kValue
kValue = O[k];

// ii. Call the Call internal method of callback with T as the this value and
// argument list containing kValue, k, and O.
// 使用call方法,T(传进的对象),kValue(当前值),k(索引),O(理解为使用的数组)
callback.call(T, kValue, k, O);
}
// d. Increase k by 1.
k++;
}
// 8. return undefined
};
}

兼容map

MDN上已经有中文注释了,很好理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {

var T, A, k;

if (this == null) {
throw new TypeError(" this is null or not defined");
}

// 1. 将O赋值为调用map方法的数组.
var O = Object(this);

// 2.将len赋值为数组O的长度.
var len = O.length >>> 0;

// 3.如果callback不是函数,则抛出TypeError异常.
if (Object.prototype.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}

// 4. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined.
if (thisArg) {
T = thisArg;
}

// 5. 创建新数组A,长度为原数组O长度len
A = new Array(len);

// 6. 将k赋值为0
k = 0;

// 7. 当 k < len 时,执行循环.
while (k < len) {

var kValue, mappedValue;

//遍历O,k为原数组索引
if (k in O) {

//kValue为索引k对应的值.
kValue = O[k];

// 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
mappedValue = callback.call(T, kValue, k, O);

// 返回值添加到新数组A中.
A[k] = mappedValue;
}
// k自增1
k++;
}

// 8. 返回新数组A
return A;
};
}

兼容filter

方法中的void 0:

  1. void 0 === undefined => 返回:true
  2. undefined在JavaScript中并不属于保留字/关键字
  3. undefined在IE5.5~8中可将当变量赋值(IE9+及其他现代浏览器中赋值给undefined将无效)
  4. 无论void后的运算数是什么,只返回纯正的undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisArg */ ) {
"use strict";

if (this === void 0 || this === null)
throw new TypeError();

var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();

var res = [];
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t) {
var val = t[i];

// NOTE: Technically this should Object.defineProperty at
// the next index, as push can be affected by
// properties on Object.prototype and Array.prototype.
// But that method's new, and collisions should be
// rare, so use the more-compatible alternative.
if (fun.call(thisArg, val, i, t))
res.push(val);
}
}

return res;
};
}

兼容reduce

hasOwnProperty:是用来判断一个对象是否有你给出名称的属性或对象。不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
if ('function' !== typeof Array.prototype.reduce) {
Array.prototype.reduce = function(callback, opt_initialValue) {
'use strict';
if (null === this || 'undefined' === typeof this) {
// At the moment all modern browsers, that support strict mode, have
// native implementation of Array.prototype.reduce. For instance, IE8
// does not support strict mode, so this check is actually useless.
throw new TypeError(
'Array.prototype.reduce called on null or undefined');
}
if ('function' !== typeof callback) {
throw new TypeError(callback + ' is not a function');
}
var index, value,
length = this.length >>> 0,
isValueSet = false;
if (1 < arguments.length) {
value = opt_initialValue;
isValueSet = true;
}
for (index = 0; length > index; ++index) {
if (this.hasOwnProperty(index)) {
if (isValueSet) {
value = callback(value, this[index], index, this);
} else {
value = this[index];
isValueSet = true;
}
}
}
if (!isValueSet) {
throw new TypeError('Reduce of empty array with no initial value');
}
return value;
};
}

兼容reduceRight

与reduce的执行顺序相反,reduceRight则是从右到左。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if ('function' !== typeof Array.prototype.reduceRight) {
Array.prototype.reduceRight = function(callback /*, initialValue*/ ) {
'use strict';
if (null === this || 'undefined' === typeof this) {
throw new TypeError(
'Array.prototype.reduce called on null or undefined');
}
if ('function' !== typeof callback) {
throw new TypeError(callback + ' is not a function');
}
var t = Object(this),
len = t.length >>> 0,
k = len - 1,
value;
if (arguments.length >= 2) {
value = arguments[1];
} else {
while (k >= 0 && !k in t) k--;
if (k < 0)
throw new TypeError('Reduce of empty array with no initial value');
value = t[k--];
}
for (; k >= 0; k--) {
if (k in t) {
value = callback(value, t[k], k, t);
}
}
return value;
};
}

兼容some

some() 方法测试数组中的某些元素是否通过了指定函数的测试。一有通过就返回true,否则false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (!Array.prototype.some) {
Array.prototype.some = function(fun /*, thisArg */ ) {
'use strict';

if (this === void 0 || this === null)
throw new TypeError();

var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== 'function')
throw new TypeError();

var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t && fun.call(thisArg, t[i], i, t))
return true;
}

return false;
};
}

兼容every

every() 方法测试数组的所有元素是否都通过了指定函数的测试。全部通过,返回true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (!Array.prototype.every) {
Array.prototype.every = function(fun /*, thisArg */ ) {
'use strict';

if (this === void 0 || this === null)
throw new TypeError();

var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== 'function')
throw new TypeError();

var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t && !fun.call(thisArg, t[i], i, t))
return false;
}

return true;
};
}

兼容indexOf

indexOf()方法返回给定元素能找在数组中找到的第一个索引值,否则返回-1
语法:arr.indexOf(searchElement[, fromIndex = 0])
MDN的注释已全部去掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(searchElement, fromIndex) {
var k;
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (len === 0) {
return -1;
}
var n = +fromIndex || 0;
if (Math.abs(n) === Infinity) {
n = 0;
}
if (n >= len) {
return -1;
}
k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
while (k < len) {
if (k in O && O[k] === searchElement) {
return k;
}
k++;
}
return -1;
};
}

兼容lastIndexOf

从数组的后面向前查找,从 fromIndex 处开始
语法:arr.lastIndexOf(searchElement[, fromIndex = arr.length - 1])

floor() 方法可对一个数进行下舍入 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
if (!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
'use strict';

if (this === void 0 || this === null) {
throw new TypeError();
}

var n, k,
t = Object(this),
len = t.length >>> 0;
if (len === 0) {
return -1;
}

n = len - 1;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) {
n = 0;
} else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}

for (k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n); k >= 0; k--) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
};
}

ECMAScript5兼容

ECMAScript3的方法我们可以放心的使用,不担心兼容问题,但是ECMAScript5就得考虑了,但是上面这么多我还得自己一个个弄,太麻烦了,于是前辈们就造了es5-shim.js库

es5-shim里面通过测试的方法有:

在使用新方法前引用它,就可以了。

其他途径

1、jquery

jquery之强大,毋庸置疑,里面就有了这些方法。只要你引用了jquery,你就可以放心的使用。详情参考jquery API

2、Underscore

Underscore JavaScript 工具库,里面提供了100多个函数。

3、lodash

lodash一个JavaScript工具库

参考链接

  1. MDN-array文档
  2. JavaScript Array数组对象-w3school
  3. Underscore-中文文档
  4. lodash-文档