2016-12-15
JavaScript
JavaScript Array
老文章恢复

数组太常见了,以至于经常忽略它

# 声明定义

00// 调用构造函数声明数组
01var a = new Array();   // √ 长度是0 是空数组
02var b = new Array(3);  // length is 3 
03var s = new Array("1", "2");  // 其值是 ["1", "2"]
04
05// 或者简单地把字面量赋过去
06var colors = ["red", "blue", "green"]; 
07var stack = []; // 空数组
08
09// length 长度不是只读,可以被赋值。 
10// 给length赋值的结果是数组变长或者变短。 
11// 变短 末项会变成undefined
12var colors = ["red", "blue", "green"]; 
13colors.length = 2; 
14console.log(colors[2]);  // undefined 
15
16// 变长 多余的末项也是undefined
17var colors002 = ["red", "blue", "green"]; 
18colors002.length = 4; 
19console.log(colors001[3]);  // undefined

# 检测

js的数组也是对象。所以就出现了“确定某个对象是不是数组”的问题。
00if (colors instanceof array) {
01	// if colors is array
02	// do something to colors 
03}
typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型。
它返回值是一个字符串,该字符串说明运算数的类型。
typeof 一般只能返回如下几个结果:
number, boolean, string, function, object, undefined
我们可以使用 typeof 来获取一个变量是否存在,如:
00if(typeof a!="undefined"){
01    alert("ok")
02}
不建议去使用 if(a) 因为如果 a 不存在(未声明)则会出错,对于 Array, Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。
除了上述的判断方法外,更推荐用 Array.isArray() 进行判断
00Array.isArray(colors) // true

# 转换

00var colors = ["red", "blue", "green"]; 
01console.log(colors.toString());  // red,blue,green
02console.log(colors.valueOf());   // red,blue,green
03console.log(colors);             // red,blue,green
04
05// toLocaleString
06var personA = {
07	toLocaleString: function(){
08		return "nachi"; 
09	}, 
10	toString: function(){
11		return "なち"; 
12	}
13}
14var personB = {
15	toLocaleString: function(){
16		return "nomico"; 
17	}, 
18	toString: function(){
19		return "のみこ"; 
20	}
21}
22var persons = [personA, personB]; 
23console.log(persons);  // ["なち", "のみこ"]
24console.log(persons.toString());  // なち,のみこ
25console.log(persons.toLocaleString());  // nachi,nomico
执行结果
执行结果

#

同时使用 pop push 可以实现入栈出栈操作。
00var Stack = []; 
01Stack.push("a");
02Stack.push("b");
03
04console.log(Stack); // ["a", "b"]
05
06var temp = Stack.pop(); 
07console.log(temp);  // b
08console.log(Stack); // ["a"]

# 队列

同时使用 unshift pop 或者 shift push 可以实现队列的入队出队操作。
00var Queue = ["a", "b"]; 
01Queue.push("c"); 
02console.log(Queue);  // ["a", "b", "c"]
03
04var head = Queue.shift(); 
05var tail = Queue.pop(); 
06console.log(head);  // "a"
07console.log(tail);  // "c"
08console.log(Queue); // ["b"]
09
10Queue.unshift("x"); 
11console.log(Queue); // ["x", "b"]

# 裂项 合并

# 分割数组

array.slice(from, to)
  • splice会创建并返回一个新数组,这个数组是原数组array的一个子集,从下标from开始到下标to结束(不包括to下标)。
  • from 和 to 可以使用负数表示 倒数
  • 再次声明,slice不会改变原数组
00var a = [0, 1, 2, 3, 4, 5, 6, 7]; 
01a.slice(3);     // return [3, 4, 5, 6, 7]
02a.slice(0, 3);  // return [0, 1, 2]
03a.slice(0, -2); // return [0, 1, 2, 3, 4, 5]
04a.slice(-2);    // return [6, 7]
05a.slice(-3, -2);// return [5]
array.splice(index,howmany,item1,…,itemX)`
  • index是添加/删除项目的位置,使用负数可从数组结尾处指定位置
  • 要删除的项目数量,如果设置为 0,则不会删除项目。
  • 注意,splice会改变原数组
00var a = [0, 1, 2, 3, 4, 5, 6, 7]; 
01a.splice(4);    // reutrn [4, 5, 6, 7] 
02a;              // now a is [0, 1, 2, 3] 
03
04a = [0, 1, 2, 3, 4, 5, 6, 7]; 
05a.splice(2, 5); // return [2, 3, 4, 5, 6]
06a;              // now a is [0, 1, 7]
07
08// insert value to array 
09a = [0, 1, 2, 3, 4, 5, 6, 7]; 
10a.splice(2, 0, 'A');  // return []
11a;                    // [0, 1, 'A', 2, 3, 4, 5, 6, 7]; 
12
13// replace an item in array 
14a = [0, 1, 2, 3, 4, 5, 6, 7]; 
15a.splice(2, 1, 'A');  // return [2]
16a;                    // [0, 1, 'A', 3, 4, 5, 6, 7]

# 合并数组

00var a = [1, 2, 3]; 
01a.join(); // "1,2,3"
02a.join(' '); // "1 2 3"
03a.join(''); // "123"

# 排序

可以简单的调用 sort 方法排序
00var values = [1, 2, 3, 4, 5]; 
01values.sort();
02console.log(values);  // [5, 4, 3, 2, 1]
sort方法对数值的排序比较好,但是如果要排序对象,怕是不行了,因此sort提供了回调来完成这方面的排序
00var personA = {
01	age: 16
02}
03var personB = {
04	age: 23
05}
06var personC = {
07	age: 20
08}
09var persons = [personA, personB, personC]; 
10persons.sort();  // also [personA, personB, personC]
11persons.sort(function(a, b){
12	if (a.age < b.age){
13		return -1;
14	} else if (a.age == b.age){
15		return 0; 
16	} else {
17		return 1; 
18	}
19}); 
20console.log(persons);  // [personA, personC, personB]
任何排序都需要这样的函数:使得其比较运算 f(a, b) 的结果在 {-1, 0, 1} 上取值,可以认为a b组成的集合G所构成代数系统的某种运算x:<G, x>
任何排序都需要构造这样的映射f, 使得 f(a, b) 值域为形如 {-1, 0, 1} 的集合。
可以认为a b组成的集合G所构成代数系统的某种运算x:<G, x>

# 位标

js的数组下标是从 0 开始的
00var numbers = [1, 2, 3, 4, 5, 4]; 
01console.log(numbers.indexOf(4));  // 3
02console.log(numbers.lastIndexOf(4));  // 5 
03
04// 如果数组里没有这个元素会返回 -1 而不是 false 或 undefined 之流 
05console.log(numbers.indexOf("ooooops!")); // -1

# 迭代

数组迭代方法
  • every(cb): 对每一项执行cb回调函数,全部返回true的时候返回true
  • filter(cb): 对每一项执行cb回调函数,返回true项构成的新数组返回
  • forEach(cb): 对每一项执行cb回调函数
  • map(cb): 对每一项执行cb回调函数,返回值组成新数组返回
  • some(cb): 对每一项执行cb回调函数,只要有一个返回true 就返回true
00var values = [1, 2, 3, 4, 5]; 
01
02// 回调参数 elem index array 指的是 当前迭代项 下标 数组本身
03// 对于任意数组项,如果都是正数,则返回true 否则返回false
04var every_result_true = values.every(function(elem, index, array){
05	if (elem >= 0){
06		return true; 
07	}
08}); // every_result_true is true 
09
10// 对于任意数组项,如果都大于3,则返回true 否则返回false
11var every_result_normal = values.every(function(elem, index, array){
12	if (elem > 3){
13		return true;
14	} else {
15		return false; 
16	}
17}); // every_result_normal is false 
18
19var filter_result = values.filter(function(elem, index, array){
20	if (elem > 3){
21		return true;
22	} else {
23		return false; 
24	}
25}); // filter_result is [4, 5]
26
27var forEach_result = values.forEach(function(elem, index, array){
28	return elem; 
29}); // forEach_result is undefined
30
31var map_result = values.map(function(elem, index, array){
32	if (elem > 3){
33		return elem+"这一项比3大";
34	} else {
35		return elem+"这一项不大于3"; 
36	}
37}); // map_result is ['1这一项不大于3', '2这一项不大于3', '3这一项不大于3', '4这一项比3大', '5这一项比3大']
38
39// 如果数组存在大于3的项 则返回true 否则返回false
40var some_result_true = values.some(function(elem, index, array){
41	if (elem > 3) {
42		return true; 
43	} else {
44		return false; 
45	}
46}); // some_result_true is true
47
48// 如果数组里存在项的值是 'oooops!' 则返回true 否则返回false
49var some_result_normal = values.some(function(elem, index, array){
50	if (elem == 'oooops!') {
51		return true; 
52	} else {
53		return false; 
54	}
55}); // some_result_normal is fasle 
56
57console.log(every_result_true); 
58console.log(every_result_normal); 
59console.log(filter_result); 
60console.log(forEach_result); 
61console.log(map_result); 
62console.log(some_result_true); 
63console.log(some_result_normal);
result
result

# 归并

初始值 prev 在不断迭代元素的时候逐渐接近结果
下面的求和就很好的表示了这个过程
00// reduce
01var values = [1, 2, 3, 4, 5]; 
02console.log(values); 
03var sum = values.reduce(function(prev, cur, index, array){
04	console.log(prev); // 1  3  6  10 
05	return prev + cur; 
06}); 
07console.log("sum: " + sum); // 15 
08
09// reduceRight
10var values02 = [1, 2, 3, 4, 5]; 
11console.log(values02); 
12var sum = values02.reduceRight(function(prev, cur, index, array){
13	console.log(prev); // 5  9  12  14 
14	return prev + cur; 
15}); 
16
17// 15 
18console.log("sum: " + sum);

# 灵活的数组

JS数组提供了很多接口,编程的时候要额外注意,避免重复造轮子。
遍历模式不只有 for循环 ,还可以用回调的方式遍历,这是JS的特性。
SQ
SQ
Stack && Queue
队列栈
  • push pop
    • 对末项的操作
  • shift unshift
    • 对首项的操作
割补
  • splice
    • 替换 splice(where, 1, value)
    • 插入 splice(where, 0, value)
  • slice
    • 返回start到end的一段拷贝 slice(start, end)
    • 不包括 end
  • join
    • 用sep合并数组项 join(sep)
    • 无参时默认用 ',' 合并
回调
  • 遍历 (elem, index, array) => {};
    • every some 公共属性 特征属性
    • filter 有条件过滤
    • map 有条件替换
    • forEach 回调遍历
  • 排序 (a, b) => {};
    • 关键是做 映射f 到集合E: {-1, 0, 1}
  • 归并 (prev, cur, index, array) => {};
    • 如前面所述初始值 prev 在不断迭代元素的时候逐渐接近结果




回到顶部