js 的数组

数组是表示集合的值,每一个值是一个元素,每一个元素在数组中有一个位置,以数字表示,叫索引。数组继承自 Array.prototype.

js 的内置对象: 数组Array

数组声明

  • 直接量方式创建数组
1
2
3
4
var empty = []; // 没有元素的空数组
var num = [1,3,2,4,5]; // 有5个元素的数组
var misc = [1, true, "a", ]; // 有不同数据类型元素的数组
var misc2 = [[1], {x: 1, y: 2},[2, {x:2, y: 1}]];

数组直接量中可以是任意的表达式。

  • 使用构造函数
1
2
3
var arr = new Array();// 数组的构造函数 创建的是一个空数组
var arr = new Array("4");// 只有传入一个数值的时候 才表示数组元素的个数
var arr = new Array(5, 4, "abc"); // 显示的指定两个或多个数组元素或者数组的一个非数值元素

数组元素的读和写

数组的合法表达式

1
2
3
4
5
6
7
8
9
10
11
12
var a = ["world"];
var value = a[0]; // 读取第 0 个元素
a[1] = 10; // 设置值
var b = [];
for (var i = 0; i < 5; i++){
a[length++] = i; // 将 0 - 4 的数值装到数组中
}
var j = 2;
a[j] = 3; // 写第二个元素
a[j+1] = "abc"; // 写第三个元素
a[a[j]] = a[0]; // 读第 0 个元素和第 2 个元素,写第 3 个元素

数组索引和对象属性

数组是对象的特殊形式。 常规的对象如:o = {}; o[1] = "one"; // 可以用一个整数来访问。数组的索引只能是 0 ~ 2的32次幂 - 2 之间的整数,所有的索引是属性名。负数和浮点数也可以来索引数组。这种情况下转成字符串当成常规对象的属性,而非负整数字符串被使用了: arr["99"], 当做数组的索引,而非对象的属性。数组的索引是属性的特殊类型,因此数组的索引找不到值时不会报错,而是 undefined。

数组的长度

每一个数组都有一个 length 属性。

1
2
3
var arr = new Array();
console.log(arr.lengh); //获取数组元素的个数
// length属性是动态改变的 通过arr.length可以动态追加

可以将数组的长度设置。

1
2
3
4
var arr = [1,2,3];
arr.length = [1]; // arr 现在为 [1];
arr.length = []; // 删除 arr 中的元素
arr.length = 5; // 长度为 4,但没有元素,相当于 new Array(5);

ECMAScript 5,可以使用 Object.defineProperty() 来设置数组的 length 为只读的。

稀疏数组

稀疏数组是包含从 0 开始的不连续索引的数组。可以使用 Array() 构造函数或简单指定数组索引大于当前数组的长度来定义稀疏数组。还可以使用 delete 操作符来创建稀疏数组。

1
2
3
4
var a = new Array(5);
var arr[99] = 1; // 赋值添加一个元素1,length 变为 100
var a2 = [];
var a3 = [,]; // 此时数组没有元素,长度是 1;也是稀疏数组

注:当给直接量中省略值时不会创建稀疏数组。因为省略的值是 undefined 类型。

1
2
var a5 = [,,,]; // 不是稀疏数组
var a4 = [undefined]; // 此时数组包含一个数值 undefined 类型。

数组冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var arr17 = [56,45,23,78,67,34,96,39,44,23,45,37,85];
var outer = 0;
var inner = 0;
for(var i = 0; i < arr17.length - 1; i++){
var flag = true;
for(var j = 0 ; j < arr17.length - 1 - i; j++){
if(arr17[j] > arr17[j+1]){
var tempValue = arr17[j+1];
arr17[j+1] = arr17[j];
arr17[j] = tempValue;
flag = false;
}
inner++;
}
outer++;
if(flag){
break;
}
}

数组的方法

  • push();
    • 尾部追加一个或多个元素,push 一个元素与给数组 a[a.length] 赋值一样;
    • 返回新数组长度
    • 操作原数组,末尾追加
1
2
3
4
var a = [];
a.push("ab");
a.push("bc","cd"); // a = ["ab","bc","cd"];
a.push("123",["e","f"]); // a = ["ab","bc","cd","123",["e","f"]];
  • pop();
    • 删除数组中最后一个元素,
    • 返回值是被删除的这个元素
    • 操作原数组
  • shift();
    • 删除数组中的第一个元素,
    • 返回值是被删除的元素
  • unshift();
    • 向数组中第一个元素之前插入一个或多个新的元素
    • 返回值是新数组的长度
  • concat(); Array.concat() 方法创建并返回新数组
    • 新的数组和旧的数组拼接,产生一个新的数组
    • 不修改原数组
1
2
3
var arr = [1,2];
arr.concat([3,4]); // 返回 [1,2,3,4]
arr.concat(3,[4,[5,6]]); // 返回 [1,2,3,4,[5,6]]
  • slice(); Array.slice()方法返回指定数组的一个片段或子数组
    • 两个参数: 开始索引,结束索引,返回包含开始索引,不包含结束索引位置之间的所有数组元素;
    • 指定一个参数,返回包含开始位置到数组结尾的所有元素
    • 参数是负数,相对于最后一个位置的。如参数 -1 指定了最后一个元素,-2 是倒数第二个
    • 从原来的数组中截取出来指定的一部分元素,产生新的数组
    • 不操作原数组
1
2
3
4
5
var a = [0,1,2,3,4,5];
a.slice (0,3); // [0,1,2];
a.slice(3); // [3,4,5]
a.slice(1,-1); // [1,2,3,4];
a.slice(-3,-2); // [3]
  • splice(); Array.splice()是数组中插入或删除元素的方法。
    • 会修改调用数组,
    • 第一个参数是开始的下标,第二个参数是指定了删除原数组元素的个数;
    • 如果省略了第二个参数,从开始索引位置后的元素都被删除;
    • 可以有第三个参数,第四个参数…跟在第二个参数后的任意多个参数是需要插入原数组中的元素,从第一个参数指定的索引位置插入;
    • 该方法返回的是删除元素组成的数组,如果没有替换则返回空数组。
  • join(); 将数组中的所有元素都转化成字符串并连接到一起
    • 返回最终生成的字符串
    • 是 String.split() 方法的逆向操作。String.split() 是将字符串分隔成分隔,返回数组;
  • reverse();
    • 反转数组
    • 操作原数组
    • 返回操作后的逆向数组
  • sort(); Array.sort() 方法将数组中的元素排序并返回排序后的数组
    • 操作原数组;
    • 返回排序后的数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function sort(arr, fn) {
for (var i = 0; i < arr.length - 1; i++) {
var flag = true;
for (var j = 0; j < arr.length - 1 - i; j++) {
if (fn(arr[j], arr[j + 1]) > 0) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = false;
}
}
if (flag) {
break;
}
}
return arr;
}
  • toString()
    • 和不使用任何参数调用 join() 方法返回的字符串是一样的。
1
2
[1,2].toString(); // "1,2"
[1,2,[3,"c",5]].toString(); // "1,2,3,c,5"
  • toLocalString() 方法是 toString() 方法的本地化版本,使用本地化分隔符将这些字符串连接起来生成最终字符串。

ECMAScript 5 中的数组方法

ECMAScript 5 定义了 9 个新的数组方法来遍历、映射、过滤、检测、简化和搜索数组;大多数 ECMAScript 5 数组方法的第一个参数是一个函数,第二个参数是可选的,如果有第二个参数,则调用的函数被看做是第二个参数的方法。即在调用函数时传递的第二个参数作为它的 this 关键字的值来使用。ECMAScript 5 中的数组方法都不会修改原始数组。

  • indexOf()和lastIndexOf(); 搜索整个数组中具有给定值的元素
    • 查找某个元素,
    • 第一个参数是要查找的元素,
    • 第二个参数是开始查找的下标,
    • 找到则返回找到的第一个元素的索引,找不到则返回-1
  • lastIndexOf();
    • 这个方法也是查找元素,从后面向前面找,找到则返回对应的下标,找不到则返回-1;
    • 第二个元素可以是负数,代表相对数组末尾的偏移量;
1
2
3
4
5
6
7
8
9
10
11
12
function findall(a, x){
var results = [],
len = a.length,
index = 0;
while(index < len){
index = a.indexOf(x, index);
if (pos === -1) break; // 未找到,完成搜索
results.push(index); // 否则在数组中存储索引
index = index + 1;
}
returen results; // 返回包含索引的数组
}
  • every() 和 some(); 数组的逻辑判定,传入一个函数,判断每个数组中的元素是否满足条件;
    • every() 方法针对所有的元素判断调用函数返回全为 true,则返回true;
    • every() 方法有一个不满足条件的则返回 false
    • some() 方法所有的元素判断调用函数有一个满足条件的则返回 true
    • some() 方法全为 false, 则返回 false
  • map() 方法,将调用的数组的每个元素传递给指定的函数,并返回一个包含该函数的数组。
    • 返回新数组
    • 不修改原数组
    • 稀疏数组调用返回的还是稀疏数组
      • 一个例子:arr.map(Math.sqrt);
        • map这个方法可以传入一个回调函数,
        • 直接传入了一个Math.sqrt方法,sqrt方法是为某个数字开平方的
        • 调用map方法传入Math.sqrt的时候,去掉了括号,也没有传入参数
        • map方法内部帮我们遍历并且传入数组的每个元素
  • filter() 方法,返回的是调用的数组的一个子集,传递的回调函数用来逻辑判断,该函数的返回值是布尔值;
    • 压缩空缺或并删除 undefined 和 null 元素,也可以使用 filter();
1
2
3
a = a.filter(function(x){
return x !== undefined && x !== null;
});

检测数组

  • instanceof
1
2
[] instanceof Array; // true
{} instanceof Array; // false

但是在web浏览器多窗口或窗体存在时,每个全局对象有自己的一组构造函数。一个窗体中的对象不可能是另外一个窗体中构造函数和实例。因此,instanceof 操作符不能视为一个可靠的数组检测方法。

  • isArray(); ECMAScript 5 中给出的检测数组类型的方法;
    • 这个方法是判断变量是不是数组

因此,封装检测数组的方法

1
2
3
var isArray = Function.isArray || function(o) {
return typeof o === "object" && Object.prototype.toString.call(o) === "[object Array]";
}
  • forEach 方法,从头至尾遍历数组,为每个元素调用指定的函数;
    • 三个参数,数值元素、数组索引、数组本身
    • 无法再所有元素传递完调用函数之前终止遍历
1
2
3
4
5
6
7
8
9
10
11
var data = [1,2,3,4,5];
// 计算数组元素和值
var sum = 0;
data.forEach(function(v){
sum += v;
});
console.log(sum); // sum => 15
data.forEach(funciton (v,i,a) {
a[i] = v + 1;
});
console.log(data); // [2,3,4,5,6];
1
2
3
4
5
6
7
8
9
// 终止 forEach 循环
function foreach (a, f, t){
try { a.forEach (f, t)}
catch (e) {
if (e === foreach.break) return;
else throw e;
}
}
foreach.break = new Error("StopIteration");
  • reduce()和 reduceRight()
    • reduce() 和 reduceRight() 方法使用指定的函数将数组元素进行组合,生成单个值。
1
2
3
4
5
6
7
8
var a = [1,2,3,4,5];
var sum = a.reduce(function(x, y){
return x + y;
}); // 求和
var max = a.reduce(function(x, y){
return (x>y)?x:y;
}); // 求最大值
  • reduce() 两个参数:
    • 第一个是执行简化操作的函数。化简函数的任务就是用某种方法把两个值组合和化简为一个值,并返回简化后的值。
    • 第二个参数是可选参数
  • reduceRight() 的工作原理和 reduce() 一样,不同的是它按照数组索引从高到低处理数组;

reduce() 和 reduceRight() 都能接收一个可选的参数,它指定了化简函数调用时的 this 关键值。

计算两个对象的并集,返回一个新对象:

1
2
3
4
5
6
7
8
9
10
11
/**
* [union description] 如果有重名属性,使用 p 中的属性
* @param {[type]} o [description]
* @param {[type]} p [description]
* @return {[type]} [description] 返回一个新对象这个对象同时拥有 o 的属性
*/
function union (o, p) {
return extend (extend({}, o), p);
}
var objs = [{x:1}, {y:2}, {z:3}];
var merged = objs.reduce(union); // {x:1, y:2, z:3}

拥有同名属性时,reduce() 和 reduceRight() 方法返回值不同;

1
2
3
var objs = [{x:1, a:1}, {y:2, a:2}, {z:3, a:3}];
var lUnion = objs.reduce(union); // {x:1, y:2, z:3, a:1}
var lUnion = objs.reduceRight(union); // {x:1, y:2, z:3, a:3}

ECMAScript 6 中数组新方法

  • Array.prototype.find 方法用于找出第一个符合条件的数组成员。
    • 参数是一个回调函数,找到第一个返回 true 的数组项,然后返回该数组项;
    • 找不到返回undefined;
1
2
3
4
var arr = [123,23];
arr.find(functiton(num){
return num === 123;
});
  • 两个静态方法
    • Array.from
      • 将一个伪数组转成正真的数组
    • Array.of
      • 将方法中参数都添加到一个数组中
  • 操作、填充和过滤数组的方法
    • Array.prototype.copyWidthin
    • Array.prototype.fill
    • Array.prototype.find
      • 接收一个回调函数,每一项执行调用它
1
2
3
4
5
6
7
8
9
var users = [
{name: 'bb', age:24},
{name: 'cc', age:32},
{name: 'dd', age:12},
{name: 'aa', age:16},
{name: 'ed', age:18},
{name: 'aa', age:29}
];
console.log(users.find(u => u.name === 'aa')); // {name: 'aa', age:16}
  • Array.prototype.findIndex
    • 有关数组迭代的方法
  • Array.prototype.keys
  • Array.prototype.values
  • Array.prototype.entries
  • Array.prototype[Symbol.iterator]

类数组对象(伪数组)

JavaScript 的类数组对象:把拥有数组 length 属性和对应非负整数属性的对象看着一种类型的数组。

1
2
3
4
5
6
7
8
9
10
11
12
var a = {};
var i = 0;
while (i < 10) {
a[i] = i * i;
i++;
}
a.length = i;
// 那么可以当成真正的数组遍历
var total = 0;
for (var j = 0; j < a.length; j++){
total += a[j];
}

判断是否是伪数组

1
2
3
4
5
6
7
8
9
10
function isArrayLike(o) {
if (o && typeof o === "object"
&& isFinite(o.length)
&& o.length >=0
&& o.length === Math.floor(o.length)
&& o.length < 4294967296)
return true;
else
return false;
}

作为数组的字符串

ECMAScript 5 中的字符串除了用 charAt() 访问单个元素之外,还可以使用方括号:

1
2
3
var str = "string";
console.log(str.charAt(1)); // => "t";
console.log(s[1]); // => "t";

数组方法总结:

  • push();
    • 尾部追加一个或多个元素,push 一个元素与给数组 a[a.length] 赋值一样;
    • 返回新数组长度
    • 操作原数组,末尾追加
  • pop();
    • 删除数组中最后一个元素,
    • 返回值是被删除的这个元素
    • 操作原数组
  • shift();
    • 删除数组中的第一个元素,
    • 返回值是被删除的元素
  • unshift();
    • 向数组中第一个元素之前插入一个或多个新的元素
    • 返回值是新数组的长度
  • concat(); Array.concat() 方法创建并返回新数组
    • 新的数组和旧的数组拼接,产生一个新的数组
    • 不修改原数组
  • slice(); Array.slice()方法返回指定数组的一个片段或子数组
    • 两个参数: 开始索引,结束索引,返回包含开始索引,不包含结束索引位置之间的所有数组元素;
    • 指定一个参数,返回包含开始位置到数组结尾的所有元素
    • 参数是负数,相对于最后一个位置的。如参数 -1 指定了最后一个元素,-2 是倒数第二个
    • 从原来的数组中截取出来指定的一部分元素,产生新的数组
    • 不操作原数组
  • splice(); Array.splice()是数组中插入或删除元素的方法。
    • 会修改调用数组,
    • 第一个参数是开始的下标,第二个参数是指定了删除原数组元素的个数;
    • 如果省略了第二个参数,从开始索引位置后的元素都被删除;
    • 可以有第三个参数,第四个参数…跟在第二个参数后的任意多个参数是需要插入原数组中的元素,从第一个参数指定的索引位置插入;
    • 该方法返回的是删除元素组成的数组,如果没有替换则返回空数组。
  • join(); 将数组中的所有元素都转化成字符串并连接到一起
    • 返回最终生成的字符串
    • 是 String.split() 方法的逆向操作。String.split() 是将字符串分隔成分隔,返回数组;
  • reverse();
    • 反转数组
    • 操作原数组
    • 返回操作后的逆向数组
  • sort(); Array.sort() 方法将数组中的元素排序并返回排序后的数组
    • 操作原数组;
    • 返回排序后的数组
  • toString()
    • 和不使用任何参数调用 join() 方法返回的字符串是一样的。
  • toLocalString() 方法是 toString() 方法的本地化版本,使用本地化分隔符将这些字符串连接起来生成最终字符串。
  • indexOf()和lastIndexOf(); 搜索整个数组中具有给定值的元素
    • 查找某个元素,
    • 第一个参数是要查找的元素,
    • 第二个参数是开始查找的下标,
    • 找到则返回找到的第一个元素的索引,找不到则返回-1
  • lastIndexOf();
    • 这个方法也是查找元素,从后面向前面找,找到则返回对应的下标,找不到则返回-1;
    • 第二个元素可以是负数,代表相对数组末尾的偏移量;
  • every() 和 some(); 数组的逻辑判定,传入一个函数,判断每个数组中的元素是否满足条件;
    • every() 方法针对所有的元素判断调用函数返回全为 true,则返回true;
    • every() 方法有一个不满足条件的则返回 false
    • some() 方法所有的元素判断调用函数有一个满足条件的则返回 true
    • some() 方法全为 false, 则返回 false
  • map() 方法,将调用的数组的每个元素传递给指定的函数,并返回一个包含该函数的数组。
    • 返回新数组
    • 不修改原数组
    • 稀疏数组调用返回的还是稀疏数组
      • 一个例子:arr.map(Math.sqrt);
        • map这个方法可以传入一个回调函数,
        • 直接传入了一个Math.sqrt方法,sqrt方法是为某个数字开平方的
        • 调用map方法传入Math.sqrt的时候,去掉了括号,也没有传入参数
        • map方法内部帮我们遍历并且传入数组的每个元素
  • filter() 方法,返回的是调用的数组的一个子集,传递的回调函数用来逻辑判断,该函数的返回值是布尔值;
    • 压缩空缺或并删除 undefined 和 null 元素,也可以使用 filter();
  • instanceof
  • isArray(); ECMAScript 5 中给出的检测数组类型的方法;
    • 这个方法是判断变量是不是数组
  • forEach 方法,从头至尾遍历数组,为每个元素调用指定的函数;
    • 三个参数,数值元素、数组索引、数组本身
    • 无法再所有元素传递完调用函数之前终止遍历
  • reduce()和 reduceRight()
    • reduce() 和 reduceRight() 方法使用指定的函数将数组元素进行组合,生成单个值。
    • reduce() 两个参数:
      • 第一个是执行简化操作的函数。化简函数的任务就是用某种方法把两个值组合和化简为一个值,并返回简化后的值。
      • 第二个参数是可选参数
    • reduceRight() 的工作原理和 reduce() 一样,不同的是它按照数组索引从高到低处理数组;

本文参考自:《JavaScript 权威指南》

感谢您的支持!