数组
Javascript数组是无类型的:数组元素可为任意类型,同一数组的不同元素也可以有不同类型。
7.1 创建数组
7.1.1 数组直接量
- 数组直接量中的值不一定是常量,可以为任意表达式
- 可以包含对象直接量或其他数组直接量
- 省略数组直接量中的某个值,省略元素为undefined
var empty=[]; //空数组
var misc=[1,true,"a"]; //不同类型元素
var x=1;
var table = [x,x+1,x+2]; //数组定义为了[1,2,3],元素是表达式
var b=[[1,{x:1}],[2,{y:2}]]; //元素是对象或者数组
var count=[1,,3];
count[1] //=> undefined
7.1.2 构造函数Array()
参数 | 含义 | 示例 |
---|---|---|
无 | 空数组 | var a = new Array() 等价于[] |
1个数值 | 指定数组长度 | var a = new Array(5) |
1个非数值 | 参数成为数组元素 | var a = new Array("a") 等价于["a"] |
多个 | 同上 | var a = new Array(1,true,"a") 等价于[1,true,"a"] |
7.2 数组元素的读和写
通过[]
来访问数组进行读写。
var a=[];
a[0] = 3; //写入元素
a[0] //=> 3: 读取
数组是对象的特殊形式。
- 使用[]访问对象属性和对象的属性访问是一样的。特别之处在于,使用小于232的非负整数作为属性名,会自动维护其length属性值。
- 所有索引都是属性名,只有在0到232-2之间的整数属性名才是索引。
- 可以使用非整数或者其他类型作为数组的属性名。
- 数组没有“越界”错误的概念,查询不到时,不会报错,只会得到undefined,和对象一样。
var a=["x"];
a[-1] = "y"; //数组a为["x", -1: "y"]
a[-1] //"y"
a[1] //=> undefined : -1并不会占索引位,虽然存在于数组中
a.length //=> 1: 参考上方第1条,属性名为-1的元素不会计算入length
a["1"] = "z" //数组a为["x", "z", -1: "y"],"1"会转成索引,表示数组的第1个元素(从0开始)
a[true] = 3 //数组a为["x", "z", -1: "y", true: 3],此种情况和"-1"类似
7.3 稀疏数组
稀疏数组是包含从0开始的不连续索引的数组。
通常(上小结中提到的特殊情况除外),数组的length属性代表数组中元素的个数。如果数组是稀疏的,length大于元素个数。
创建稀疏数组的方式:
方式 | 示例 | 产生的数组 |
---|---|---|
使用Array()构造函数 | var a=new Array(5); |
(5) [empty × 5] |
指定数组的索引值大于当前数组长度 | var a=[]; a[4] = 0; |
(5) [empty × 4, 0] |
delete操作符产生 | var a=[1,2,3]; delete a[0]; |
(3) [empty, 2, 3] |
省略数组直接量中的值(使用连续逗号) | var a=[1,,3] |
(3) [1, empty, 3] |
7.4 数组长度
- 数组length属性 = 该数组的最大索引 + 1
- 设置数组length属性,若小于或等于最大索引,数组会被截断
var a=[1,2,3]
a.length //=> 3: 数组长度为3
a[2] //=> 3: 最大索引为2
a.length = 2
a //=> [1,2]: 数组被截断
a.length = 5
a //=> [1, 2, empty × 3]: 在数组尾部创建空的区域
ECMAScript 5中,object.defineProperty()
(见6.7)可以让数组length属性变成只读,并设置可扩展性(见6.8.3)。
var a=[1,2,3];
Object.defineProperty(a,"length",{writable: false});
a.length=0;
a.length //=> 3: 不会改变
7.5 数组元素的添加和删除
7.5.1 添加
初始化数组:var a=[1,2]
方式 | 说明 | 示例 | 新数组 |
---|---|---|---|
新索引赋值 | 增加新索引并为其赋值 | a[2]="x" |
(3) [1, 2, “x”] |
push() 方法 |
在数组末尾增加元素 | a.push("x","y") |
(4) [1, 2, “x”, “y”] |
unshift() 方法 |
在数组首部增加元素 | a.unshift("x","y") |
(4) [“x”, “y”, 1, 2] |
7.5.2 删除
使用delete运算符。(其他方法详见7.8节)
注意:delete后不会修改数组的length属性,而是变成稀疏数组。 delete和赋值为undefined是有区别的。
var a=[1,2,3];
delete a[0]; //a变为:(3) [empty, 2, 3]
a.length //=> 3
0 in a //=> false
a[0]=undefined //a变为:(3) [undefined, 2, 3]
0 in a //=> true
7.6 数组遍历
使用forEach()
方法。
var data=[1,2,3,4,5];
data.forEach(function(x){
console.log(x)
})
7.7 多维数组
Javascript不支持真正的多维数组,但可以用数组的数组来近似。
var table = [[1,2,3],["x","y","z"]];
table[0] //=> [1,2,3]
table[0][0] //=> 1
table[1][2] //=> "z"
7.8 数组的方法
7.8.1 join()
Array.join()将数组中所有元素转化为字符串并连接在一起,返回生成的字符串。
可以指定分隔符,默认使用逗号。
var a=[1,2,3];
a.join(); //=> "1,2,3"
a.join(' '); //=> "1 2 3"
var b= new Array(5);
b.join("-"); //=> "----":由于b是长度为5的空数组,所以得到的字符串为4个连接符
7.8.2 reverse()
Array.reverse()将数组中的元素逆序,返回逆序数组。
注意:会改变原数组
var a=[1,2,3];
a.reverse().join() //=> "3,2,1"
a //=> [3, 2, 1]
7.8.3 sort()
Array.sort()将数组中的元素排序,返回排序后的数组。
注意:会改变原数组
默认按照字母顺序(区分大小写),undefined会排在尾部。
其他方式排序,可以传递一个比较函数,返回负数(参数1在前)、0、正数(参数2在前)。
//--默认排序例子--
var a=["apple","Zoo",,"cat"];
a.sort(); //=> ["Zoo", "apple", "cat", empty]: 区分大小写
//--传递比较函数,数字排序--
var a=[33,4,1111,222];
a.sort() //=> [1111, 222, 33, 4]: 默认排序按照字母顺序
a.sort(function(a,b){ return a-b;}); //=> [4, 33, 222, 1111]
a.sort(function(a,b){ return b-a;}); //=> [1111, 222, 33, 4]
//--传递比较函数,不区分大小写的字母排序--
var a=['ant','Bug','cat','Dog'];
a.sort(); //=>["Bug", "Dog", "ant", "cat"]: 区分大小写
a.sort(function(a,b){
var al=a.toLowerCase();
var bl=b.toLowerCase();
if(al<bl) return -1;
if(al>bl) return 1;
return 0;
}); //=> ["ant", "Bug", "cat", "Dog"]: 不区分大小写
7.8.4 concat()
Array.concat()合并数组,返回新数组,包含原始数组以及各个参数。
var a=[1,2,3];
a.concat(4,5); //=> [1,2,3,4,5]
a.concat(4,[5,6]) //=> [1,2,3,4,5,6]
a.concat([4,[5,6]]) //=> [1,2,3,4,[5,6]]
7.8.5 slice()
Array.slice()返回指定的数组片段,两个参数分别为开始和结束(不含)位置。
位置从0开始计算,如果是负数则从末尾开始,例如-1是最后一个元素。
var a=[1,2,3,4,5];
a.slice(0,2); //=> [1,2]
a.slice(2,4); //=> [3,4]
a.slice(1,-1); //=> [2,3,4]
7.8.6 splice()
Array.splice()在数组中插入或删除元素。
注意:会改变原数组
- 参数1:插入和(或)删除的起始位置
- 参数2:删除的元素个数
- 参数n:需要插入到数组中的元素
var a=[1,2,3,4,5,6,7,8];
a.splice(4); //=> [5,6,7,8], a为[1,2,3,4]
a.splice(1,2)//=> [2,3], a为[1,4],注意上一步已经将a数组改变了,所以得到这样的结果
var a=[1,2,3,4,5];
a.splice(5,0,'x'); //=> [], a为[1,2,3,4,5,"x"]
a.splice(1,3,[4,5],'y')//=> [2,3,4], a为[1,[4,5],"y",5,"x"]
7.8.7 push()
和pop()
push()和pop()分别在数组尾部添加和删除元素。
注意:两个方法都会改变原数组
方法 | 作用 | 返回 |
---|---|---|
push() |
数组尾部添加元素 | 数组新长度 |
pop() |
删除最后一个元素 | 删除的值 |
组合使用者两个方法,用数组实现先进后出的栈。
var a=[1,2,3];
a.push('x','y'); //=> 5, a为[1,2,3,"x","y"]
a.pop(); //=> "y", a为[1,2,3,"x"]
7.8.8 unshift()
和shift()
unshift()和shift()分别在数组头部添加和删除元素。
注意:两个方法都会改变原数组,且自动调整索引避免空缺。
方法 | 作用 | 返回 |
---|---|---|
unshift() |
数组头部添加元素 | 数组新长度 |
shift() |
删除第一个元素 | 删除的值 |
var a=[1,2,3];
a.unshift('x','y'); //=> 5, a为["x","y",1,2,3]
a.shift(); //=> "x", a为["y",1,2,3]
7.8.9 toString()
和toLocaleString()
toString()
等价于join()不带参数的情况。
toLocaleString()
是toString()的本地化版本。
[1,[2,3]].toString() //=> "1,2,3"
[4567].toString(); //=> "4567"
[4567].toLocaleString(); //=> "4,567"
var a = new Array(new Date());
a.toString(); //=> "Mon Jun 11 2018 15:09:57 GMT+0800 (CST)"
a.toLocaleString(); //=> "6/11/2018, 3:09:57 PM"
7.9 ECMAScript 5中的数组方法
注意:ECMAScript 5中的数组方法都不会修改原始数组
7.9.1 forEach()
在7.6有简单介绍了1个参数(遍历的元素)的情况。forEach()
还可以使用3个参数:数组元素、元素索引、数组本身。
//--1个参数--
var sum=0;
[1,2,3,4,5].forEach(function(x){
sum+=x;
});
sum //=> 15
//--3个参数--
['x','y','z'].forEach(function(v,i,a){
console.log(v); //分别是x,y,z
console.log(i); //分别是0,1,2
console.log(a); //三次都是["x", "y", "z"]
})
forEach()没有break语句,如果要提前终止,需要把它放在try块中,并能抛出异常。
7.9.2 map()
map()遍历原数组元素,操作后返回一个新数组,原始数组不会修改。
var a=[1,2,3];
a.map(function(x){return x*x;})//=> [1,4,9]
a //=> [1,2,3]
7.9.3 filter()
filter()遍历数组返回符合要求的元素组成的数组子集。参数是一个函数,返回true或者fals。
会跳过缺少的元素,返回的数组总是稠密的。
var a=[1,-2,3,4,-5]
a.filter(function(x){return x>0;}) //=> [1,3,4]
a.filter(function(x,i){return i<2;}) //=> [1,-2]
[1,,2,3].filter(function(){return true;}) //=> [1,2,3]
[1,undefined,null].filter(function(){return true;}) //=> [1, undefined, null]
[1,undefined,null].filter(function(x){return x;}) //=> [1]: undefined 和null在布尔判定都是false
7.9.4 every()
和some()
every()
是否所有元素满足;some()
是否存在元素满足。返回结果为布尔型。
var a=[1,2,3,4,5];
a.every(function(x){ return x < 10}) //=> true: 所有值都小于10
a.every(function(x){ return x < 5}) //=> false
a.some(function(x){ return x < 5}) //=> true
[1,'a',2].some(isNaN) //=> true: "a"不是数字
7.9.5 reduce()
和reduceRight()
reduce()和reduceRight()使用指定函数,生成单个值。区别在于后者为数组倒序。
第1个参数: 函数
第2个参数(可选): 初始值
var a=[1,2,3,4,5]
a.reduce(function(x,y){ return x+y},0) //=> 15: 求和,初始值为0
a.reduce(function(x,y){return (x>y)?x:y;}) //=> 5: 求最大值
a.reduce(function(x,y){return x.toString()+y.toString()}) //=> "12345"
a.reduceRight(function(x,y){return x.toString()+y.toString()}) //=> "54321"
7.9.6 indexOf()
和lastIndexOf()
indexOf()和lastIndexOf()搜索数组返回找到满足的第一个元素的索引,没有找到返回-1。区别在与后者为倒序搜索。
第1个参数: 需要搜索的值
第2个参数(可选): 开始搜索的位置,可以为负数(-1表示最后一个元素)
a=[1,2,3,2];
a.indexOf(2) //=> 1: a[1]的值为2
a.indexOf(5) //=> -1: 没有为5的元素
a.indexOf(2,3) //=> 3: 从索引为3开始搜索
a.lastIndexOf(2) //=> 3: 倒序找到的第一个2是a[3]
7.10 数组类型
ECMAScript 5中,可以使用Array.isArray()
来判断是否是数组。
不能用typeof判断。
typeof([1,2]); //=> "Object"
Array.isArray([1,2]); //=> true
Array.isArray({}); //=> false
7.11 类数组对象
拥有一个数值length属性和对应非负整数属性的对象成为“类数组对象”。可以用针对真正数组遍历的代码来遍历它们。
可以理解为,它是一个对象,只是碰巧具有以数字为索引的属性。
7.12 作为数组的字符串
ECMAScript 5中,字符串的行为类似于只读数组。除了使用charAt()
来访问单个字符外,也可以像数组一样使用[]
。
var str="abcede";
str.charAt(1); //=> "b"
str[1]; //=> "b"
Array.prototype.join.call(str,"-"); //=> "a-b-c-e-d-e"