1 /**
2 * JS数组
3 * 类型:JS数组是无类型的,数组元素可以是任意类型
4 * 索引:基于零的32位数值,索引(下标)范围:0 到 (2的32次方)-2 [即 0 到 4 294 967 294],
5 * 即4 294 967 295个元素,在这个下标范围内,数组的 length 属性可以自动维护
6 * 特性:
7 * 1、动态;创建数组无需声明大小,其长度会根据需要动态增长或缩减
8 * 2、连续性:JS数组可能是稀疏的,元素索引不一定要连续
9 * 属性:length属性,表示数组长度(数组中数字索引的长度)
10 */
11
12 /**
13 * 数组的创建:
14 * 1、使用直接量字符创建
15 * 2、调用构造函数 Array() 创建
16 */
17 //使用数组直接量创建数组
18 var arr=[];
19
20 // 数组的直接量的语法允许有可选逗号作结尾,直接量中被省略的值是不存在的,
21 //访问时会输出 undefined, 且直接量中的值不一定要是常量,也可以是表达式
22 var arr=[,,];
23 console.log(arr);//[ <2 empty items> ] 这里数组为空,没有元素
24 //解析:上面语句实际上与 var arr=[,]; 相同
25 //第一个逗号左边和右边各有一个 item,第二个逗号可选(即可有可无)
26
27 var num=1024;
28 var arr=[undefined,undefined,++num];
29 console.log(arr);//[ undefined, undefined, 1025 ]
30 //解析:这里的两个元素值为:undefined (这里数组有值,并不为空,只不过值刚好为:undefined)
31
32 //调用构造函数Array()创建数组
33 var arr=new Array();//[]
34 var arr=new Array(10);//[ <10 empty items> ] 指定数组长度为10
35 //var arr=new Array(4294967296);//RangeError: Invalid array length
36 //解析:数组索引范围(0 到 4 294 967 294),即4 294 967 295个元素,创建数组时超出范围报错
37 var arr=new Array(123,"abc",{});//[ 123, 'abc', {} ] //显式指定多个数组元素
38
39 /**
40 * 数组元素的读写:
41 * 数组是对象的特殊形式,使用方括号访问数组元素就像使用方括号访问对象的属性一样
42 * 数组索引和对象属性的区分:
43 * 1、所有索引都是属性名
44 * 2、只有在范围内(0 到 (2的32次方)-2)的整数属性名才是索引
45 * 3、因为所有数组都是对象,因此可以为数组创建任意名字的属性,如果使用的
46 * 属性名是数组索引(范围内的整数),那么数组就会根据需要更行它的 length 属性值
47 * 4、事实上数组索引仅仅是对象属性名的一种特殊情况,这意味着js数组没有"越界"错误概念
48 * 即当试图查询对象(数组是对象)中不存在的属性时,不会报错,只会得到 undefined
49 */
50 var arr=[];
51 arr[1]="num1";
52 arr[2.000]="num2";//与 arr[2]="num2";相等
53 arr[-1.23]=true;//超出范围,不是索引,是属性
54 console.log(arr,arr[100]);
55 //[ <1 empty item>, 'num1', 'num2', '-1.23': true ] undefined
56 //解析:arr[0] 没有赋值,所以为空。arr[1],arr[2]对应数组索引。
57 //最后面的 '-1.23': true 就跟对象中的键值对一样,可通过 arr[-1.23]/arr["-1.23"] 访问到
58 //arr[100]超出当前数组的长度,但访问时不会报错,而是输出 undefined
59
60
61 /**
62 * 稀疏数组:
63 * 稀疏数组就是包含从0开始的不连续的索引的数组
64 */
65 var arr=[];
66 arr[20]="hello";
67 console.log(arr,arr.length);//[ <20 empty items>, 'hello' ] 21
68 //解析:虽然数组长度为 21,但是数组是稀疏的,只有一个元素,前面元素全部为空
69
70
71 /**
72 * 数组的长度 length 属性:
73 * 更准确地说数组的 length 属性,表示的是数组中数字索引的长度,而不是数组中元素的个数
74 */
75
76 var arr=[];//一个空数组,length=0
77 arr[3]="num3",arr["test"]="hello world",arr[-100]="-100";
78 console.log("length:"+arr.length,arr);
79 //length:4 [ <3 empty items>, 'num3', test: 'hello world', '-100': '-100' ]
80 //解析:数组前面3个元素为空,arr[3]在上面赋值为 num3,后面两个不是索引,而是被当成对象属性
81 //数字索引有4个(arr[0]、arr[1]、arr[2]、arr[3]),也就说明:length 表示的是数组中数字索引的长度(这个就是数组长度)
82 //由此引出了下面这样一个特殊行为
83
84 //当设置 length 属性为一个小于当前数组长度的非负数n时,当前数组中那些索引值大于或等于n的元素将从中删除
85 //当设置 length 属性为一个大于当前数组长度的非负值n时,不会添加新元素,而是在数字索引元素后面添加空元素
86 var arr=new Array(1,2,3,4,5,6,7,8);
87 arr["a"]="a",arr["test"]="hello";
88 console.log("length:"+arr.length,arr);
89 //length:8 [ 1, 2, 3, 4, 5, 6, 7, 8, a: 'a', test: 'hello' ]
90
91 arr.length=2;
92 console.log("length:"+arr.length,arr);
93 //length:2 [ 1, 2, a: 'a', test: 'hello' ]
94 //解析:可以看到索引arr[2]到arr[7]都被删除了,因为 length 表示的是数组中数字索引的长度(这个就是数组长度)
95
96 arr.length=5;
97 console.log("length:"+arr.length,arr);
98 //length:5 [ 1, 2, <3 empty items>, a: 'a', test: 'hello' ]
99 //解析:可以看到数组增加了3个空元素,且长度增加了,因为 length 表示的是数组中数字索引的长度(这个就是数组长度)
100
101
102 /**
103 * 数组的方法:
104 * join()、reverse()、sort()、concat()、slice()、splice()、
105 * push()、pop()、shift()、unshift()、toString()、toLocalString()、valueOf()
106 * forEach()、map()、filter()、every()、some()
107 * reduce()、reduceRight()、indexOf()、lastIndexOf()
108 */
109
110 //join()方法,按指定字符串将数组中各个元素(这里指有索引的元素,下同)连接起来并返回
111 //始末状态:不会改变数组本身
112 //参数:分隔符
113 var data=[1,2,3,4,5,6,7,8];
114 data["test"]="test";
115 console.log(data.join(" @--> "));//1 @--> 2 @--> 3 @--> 4 @--> 5 @--> 6 @--> 7 @--> 8
116 console.log(data);//[ 1, 2, 3, 4, 5, 6, 7, 8, test: 'test' ] 不会改变数据本身
117
118 //reverse()方法,将数组中的元素倒序,并返回倒序后的数组(是倒序,不是从大到小排序,只是把元素位置倒转)
119 //始末状态:会改变数组本身
120 //参数:无
121 var data=[3,"d",1,"hello",{},-1,9,"b"];
122 data["test"]="test";
123 console.log(data.reverse());//[ 'b', 9, -1, {}, 'hello', 1, 'd', 3, test: 'test' ]
124 console.log(data);//[ 'b', 9, -1, {}, 'hello', 1, 'd', 3, test: 'test' ] 会改变数据本身
125
126 //sort()方法,将数组元素按指定顺序排序并返回排序后的数组,数组元素默认按照字母表顺序排序
127 //始末状态:会改变数组本身
128 //参数:可传入一个比较函数作为参数
129 var data=["z","x","p",5,4,3,2,1,12,19,25,21," ",""];
130 data["test"]="test";
131 console.log(data.sort());
132 //[ '', ' ', 1, 12, 19, 2, 21, 25, 3, 4, 5, 'p', 'x', 'z', test: 'test' ]
133 //解析:虽然"2"的值比"12","19"要小,但是按照字符串比较时,"12","19",位于"2"前面,可以看出,数组元素默认按照字母表顺序排序
134
135 //比较函数,接受两个参数:
136 //如果第一个参数应该位于第二个之前则返回一个负数
137 //如果两个参数相等则返回0
138 //如果第一个参数应该位于第二个之后则返回一个正数
139 //原理:类似于冒泡排序
140
141 function compare(a,b){return a-b}//从小到大排序
142 var data=[5,4,3,2,1,12,19,25,21];
143 data.sort(compare);
144 console.log(data);//[ 1, 2, 3, 4, 5, 12, 19, 21, 25 ]
145
146 //原理:如果把上面的比较函数稍加修改,并记录下比较次数和比较的元素,
147 //输出结果可以看到,一共调用了15次,每次将元素两两比较,仔细查看结果类似于冒泡排序
148 var count=0,result="";
149 function compare(a, b) {
150 //other code
151 result+="#"+(++count)+"->"+a+"和"+b+"比较 ";
152 if (a < b) {
153 return -1;
154 }
155 else if (a > b) {
156 return 1;
157 }
158 else {
159 return 0;
160 }
161 //other code
162 }
163 console.log(result);
164 //#1->5和4比较 #2->5和3比较 #3->4和3比较 #4->5和2比较 #5->4和2比较 #6->3和2比较 #7->5和1比较 #8->4和1比较
165 //#9->3和1比较 #10->2和1比较 #11->5和12比较 #12->12和19比较 #13->19和25比较 #14->25和21比较 #15->19和21比较
166
167 // concat()方法,创建并返回一个新数组,新数组元素包括调用concat()方法的原始数组的元素和concat()中的每个参数
168 // 如果concat()参数中的任意一个参数是数组,则返回的是该数组中的元素,而不是该数组本身
169 // 始末状态:不会改变数组本身
170 // 参数:任意类型
171 var data=[1,2,3];
172 console.log(data.concat(0,[11,22],[ 33, [44] , [ {} , [55] , "test"], 66] ));
173 //[ 1, 2, 3, 0, 11, 22, 33, [ 44 ], [ {}, [ 55 ], 'test' ], 66 ]
174 //解析:(1,2,3)为数组原来的元素,所以直接返回,concat()中有3个参数,其中两个是数组,简化后相当于data.concat(0,[数组一],[数组二])
175 //因此返回的是0,和[数组一]、[数组二]里面的元素(数组里面元素可以是任意类型,因此元素也可以是数组)
176 console.log(data);//[ 1, 2, 3 ]
177
178 //slice()方法,返回指定数组的一个片段或者子数组
179 //始末状态: 不会改变数组本身
180 //参数:可不带参数或一个参数或两个参数,只有一个参数时,返回指定位置开始到当前数组末尾的所有项,负数表示倒数第几个数
181 //参数一:截取字符串的起始位置 参数二:截取字符串的结束位置(截取时不包括该位置的字符) 不带参数:与 Array.prototype.slice(0)返回的结果一样
182 var data=[1,2,3,4,5,6,7,8];
183 data["test"]="test";
184 console.log(data.slice(3));//[ 4, 5, 6, 7, 8 ] 从下标位3的位置开始一直到数组末尾
185 console.log(data.slice(2,-1));//[ 3, 4, 5, 6 ] 从下标位2的位置开始一直到数组倒数第二个数(截取时不包括该位置的字符)
186 console.log(data);//[ 1, 2, 3, 4, 5, 6, 7, 8, test: 'test' ]
187
188 //splice()方法,在数组中插入或删除元素,返回在数组中删除的元素
189 //始末状态:会改变数组本身
190 //参数:可有一个或两个参数或多个,只有一个参数时,从起始位置到数组末尾的所有元素都将被删除(这里指有索引的元素,前面已经提过了)
191 //参数一:插入或删除的起始位置 参数二:从数组中删除的元素个数 参数二后面的参数:这些参数将会插入数组参数一中的位置
192 var data=[1,2,3,4,5,6,7,8];
193 data["test"]="test";
194 console.log(data.splice(6));//[ 7, 8 ]
195 console.log(data);//[ 1, 2, 3, 4, 5, 6, test: 'test' ]
196 console.log(data.splice(3,2));//[ 4, 5 ]
197 console.log(data);//[ 1, 2, 3, 6, test: 'test' ]
198 console.log(data.splice(2,0,11,[22],{}),data);
199 //输出:[] ,从下标为2的位置开始删除0个元素(即不删除),在将后面的参数插入数组,插入位置是下标2的位置(即参数一)
200 console.log(data);//[ 1, 2, 11, [ 22 ], {}, 3, 6, test: 'test' ]
201
202 //push()方法,在数组末尾添加参数,并返回修改后数组的长度(即length的值)
203 //始末状态:会改变数组本身
204 //参数:任意个任意类型的参数
205 var data=[1,2,3];
206 data["test"]="test";
207 console.log(data.push(4,[5],{}));//6
208 console.log(data);//[ 1, 2, 3, 4, [ 5 ], {}, test: 'test' ]
209
210 //pop()方法,删除并返回数组最后一个元素
211 //始末状态:会改变数组本身
212 //参数:无
213 var data=[1,2,3];
214 data["test"]="test";
215 console.log(data.pop());//3 删除被返回元素 3
216 console.log(data);//[ 1, 2, test: 'test' ]
217
218 //unshift()方法,与push()类似,只不过添加的参数是在数组开头
219 //shift()方法,与pop()类似,只不过删除的参数是在数组开头
220
221 //forEach()方法,对数组中的每一项运行给定函数,无返回值
222 //始末状态:不会改变数组本身
223 //参数:给定的函数
224 //函数参数:可以有3个参数,参数一:当前数组元素 参数二:当前元素索引 参数三:数组本身
225 var data=[1,2,3,{}];
226 var count=0;
227 data["test"]="test";
228 console.log(data.forEach(function(item,index,arr){count++;}));//undefined 无返回值
229 console.log(data,"count:"+count);//[ 1, 2, 3, {}, test: 'test' ] 'count:4' 可以看出循环了4次
230
231 //map()方法,将数组每个元素传递给指定函数,返回一个数组,该数组包含指定函数的返回值
232 //始末状态:不会改变数组本身
233 //参数:给定的函数
234 //函数参数:可以有3个参数,参数一:当前数组元素 参数二:当前元素索引 参数三:数组本身
235 var data=[1,2,3,4,5];
236 data["test"]="test";
237 console.log(data.map(function(item,index,arr){return item*2;}));//[ 2, 4, 6, 8, 10 ]
238 console.log(data);//[ 1, 2, 3, 4, 5, test: 'test' ]
239
240 //filter()方法,对数组中的每一项运行给定函数,返回指定函数运行结果为true 的项组成的数组
241 //始末状态:不会改变数组本身
242 //参数:给定的函数
243 //函数参数:可以有3个参数,参数一:当前数组元素 参数二:当前元素索引 参数三:数组本身
244 var data=[1,2,3,4,5];
245 data["test"]="test";
246 console.log(data.filter(function(item,index,arr){return item%2==0;}));//[ 2, 4 ] 过滤出偶数
247 console.log(data);//[ 1, 2, 3, 4, 5, test: 'test' ]
248
249 //every()方法,对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true
250 //始末状态:不会改变数组本身
251 //参数:给定的函数
252 //函数参数:可以有3个参数,参数一:当前数组元素 参数二:当前元素索引 参数三:数组本身
253 var data=[1,2,3,4,5];
254 data["test"]="test";
255 console.log(data.every(function(item,index,arr){return item%2==0;}));//false 部分返回 true
256 console.log(data.every(function(item,index,arr){return item>0;}));//true 全部都返回 true
257 console.log(data);//[ 1, 2, 3, 4, 5, test: 'test' ]
258
259 //some()方法,对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true
260 //始末状态:不会改变数组本身
261 //参数:给定的函数
262 //函数参数:可以有3个参数,参数一:当前数组元素 参数二:当前元素索引 参数三:数组本身
263 var data=[1,2,3,4,5];
264 data["test"]="test";
265 console.log(data.some(function(item,index,arr){return item%2==0;}));//true 部分返回 true
266 console.log(data.some(function(item,index,arr){return item>0;}));//true 全部都返回 true
267 console.log(data);//[ 1, 2, 3, 4, 5, test: 'test' ]
268
269 //reduce()方法,按照指定函数,迭代数组的每一项,然后返回一个构建的最终值
270 //始末状态:不会改变数组本身
271 //参数:参数一:执行简化操作的函数 参数二(可选):传递给函数的初始值,当没有改参数时会将数组的第一个元素作为初始值
272 //函数参数:可以有4个参数,参数一:当前为止累计操作的结果 参数二:当前数组元素 参数三:当前元素索引 参数四:数组本身
273 var data=[1,2,3,4,5];
274 data["test"]="test";
275 console.log(data.reduce(function(x,y){return x+y},10));//25 (即10+1+2+3+4+5的累加结果)
276 console.log(data.reduce(function(accumulative,item,index,arr){
277 console.log("accumulative:"+accumulative);
278 return accumulative+item
279 }));//accumulative:1(数组第一个元素作为初始值) accumulative:3(1+2) accumulative:6(3+3) accumulative:10(6+4) ,15 (即1+2+3+4+5的累加结果)
280 console.log(data);//[ 1, 2, 3, 4, 5, test: 'test' ]
281
282 //reduceRight()方法,与reduce(),不过是按照索引从高到低运算
283 var data=[1,2,3,4,5];
284 data["test"]="test";
285 console.log(data.reduceRight(function(x,y){return x+y},10));//25 (即10+1+2+3+4+5的累加结果)
286 console.log(data.reduceRight(function(accumulative,item,index,arr){
287 console.log("accumulative:"+accumulative);
288 return accumulative+item
289 }));//accumulative:5(数组最后一个元素作为初始值) accumulative:9(5+4) accumulative:12(9+3) accumulative:14(12+2) ,15 (即5+4+3+2+1的累加结果)
290 console.log(data);//[ 1, 2, 3, 4, 5, test: 'test' ]
291
292
293 //indexOf()方法,搜索整个数组中具有给定值得元素,返回找到的第一个元素的索引,没有找到则返回-1
294 //始末状态:不会改变数组本身
295 //参数:参数一:要搜索的元素(这里指有索引的元素,前面已经提过了) 参数二(可选):指定从哪个元素开始搜索,默认为0,负数表示从倒数第几个数开始
296 var data=[1,1,2,3,4,5,{},"str","str",6,7];
297 data["test"]="test";
298 console.log(data.indexOf(1),data.indexOf("str",-4),data.indexOf("test"));//0 7 -1
299 //解析:对于元素“1”,找到遇到的第一个“1”,返回该元素下标"0"。对于元素"str",从倒数第4个数(即从左往右的第一个“str”)开始搜索,
300 //找到遇到的第一个"str",返回该元素下标“7”。对于"test",由于这里是指有索引的元素,因此没有找到对应的元素,返回"-1"
301
302 //lastIndexOf()方法,与indexOf()方法类似,只不过搜索的方向是从数组尾部开始搜索
303 var data=[1,1,2,3,4,5,{},"str","str",6,7];
304 data["test"]="test";
305 console.log(data.lastIndexOf(1),data.lastIndexOf("str",-4),data.lastIndexOf("test"));//1 7 -1
306 //解析:对于元素“1”,因为是从尾部开始搜索,所以先遇到的是数组中的第二个"1",返回该元素下标"1"。
307 //对于"str"和“test"解析同上