JavaScript数组是一种特殊类型的对象。
JavaScript数组元素可以为任意类型,最大容纳232-1个元素。
JavaScript数组是动态的,有新元素添加时,自动更新length属性。
JavaScript数组元素索引可以是不连续的,它们之间可以有空缺。

创建数组

调用构造函数Array()创建数组:

var a = new Array();            //空数组,等同于数组直接量[]
var b = new Array(5);           //创建指定长度的数组
var c = new Array(1, 5, 9, 6);  //指定一个或多个元素的非空数组

数组直接量表示法:

var a = [];                     //空数组
var b = [2, 3, 5, 7];           //常规元素
var c = [5, true, "a"];         //元素不同类型的数组
var d = [{ x: 2 }, { x: 3 }];   //包含对象元素的数组

以上是数组的几种常见类型,但下面两种也符合数组语法。

var e = [1, , 3]; //该数组有3个元素,中间的元素为undefined
var f = [1, 5, ]; //该数组有2个元素,结尾逗号后面没有元素

如果省略数组直接量中的某个元素值,省略的元素值为undefined
数组直接量的语法中允许有可选结尾的逗号,故[1,5,]只有两个元素并非三个。

两种方法创建的数组无本质区别,但数组直接量表示法简单,实际使用中更为常见。

数组元素

读写数组元素最简单的方法就是通过索引。

var arr = ["one", "two"];
var res = arr[0];  //读第0的元素
arr[0] = "test";   //写第0的元素

数组本身就是对象,使用[]方括号访问数组元素就像方括号访问对象属性一样。数组的特别之处在于,当使用小于232的非负整数作为属性时数组会自动维护其length属性。当然,数组也可以有自定义属性,但不常见。如下:

var obj = [1, 2, 3];
obj["IsShow"] = false;   //现在obj数组为 [1, 2, 3, IsShow: false]

稀疏数组

稀疏数组就是包含从0开始的不连续索引的数组。

var a = new Array(5); //数组没有元素,但a.length等于5
var b = [];
b[1000] = 1000; //添加一个索引为1000的元素,但b.length等于1001

通过delete操作符删除数组元素可产生稀疏数组。delete不会改变数组长度,高位置索引元素也不会下移填补删除索引位置的空白。

注意,省略数组不等同于稀疏数组,省略的元素在数组中是存在的,值为undefined

数组长度

每个数组都有length属性,代表数组中元素的个数。针对非稀疏数组,其值比最大索引大1。

['a', 'b', 'c'].length; //最大索引为2,length为3

当设置length属性为一个小于当前数组长度的非负整数n时,当前数组中的那些索引大于或等于n的元素将被删除。

var a = [1, 2, 3, 4, 5]; //数组初始化5个元素
a.length = 3;  //现在a为[1,2,3]
a.length = 0;  //删除所有元素,a为[]
a.length = 5;  //数组长度为5,但是没有元素

在ECMAScript 5中,可以用Object.defineProperty()让数组的length属性变成只读的。

var b = [1, 2, 3];
Object.defineProperty(b, "length", { writable: false }); //让length变成只读属性
b.length = 0; //更改无效

数组遍历

使用for循环遍历数组元素是最常见的方法。如下:

var obj = { height: 175, weight: 60 }; //初始化一个对象
var keys = Object.keys(obj);           //获取对象obj属性名组成的数组
var values = [];                       //values用来保存对象obj属性值
for (var i = 0, len = keys.length; i < len; i++) {var key = keys[i];                 //获取当前索引的键值values[i] = obj[key];              //在values数组中保存属性值
}

针对稀疏数组遍历时,注意过滤掉不满足条件的元素。

for (var i = 0; i < arr.length; i++) {if (!arr[i]) continue;  //跳过null,undefined和不存在的元素if (arr[i] === undefined) continue; //跳过undefined和不存在的元素if (!(i in arr)) continue; //跳过不存在的元素//T0DO
}

多维数组

JavaScript不支持真正的多维数组,一般用数组的数组来近似。下面是一个具体的例子,使用二维数组作为一个9X9乘法表。

//创建一个多维数组
var table = new Array(10); //表格有10行
for (var i = 0; i < table.length; i++) {table[i] = new Array(10); //每行有10列
}
//初始化数组
for (var row = 0; row < table.length; row++) {for (var col = 0; col < table[row].length; col++) {table[row][col] = row * col;}
}
//使用多维数组来计算
var result = table[8][9]; //result = 72

数组方法

ECMAScript 3在Array.prototype中定义了一些很有用的操作数组的方法,下面介绍这些方法的基本用法。

join()
Array.join(separator)该方法可以将数组元素按照指定字符连接起来,返回最终生成的字符串。如果不指定字符separator,默认用逗号分隔。

var arr = [1, 2, 3];
arr.join();     //=>"1,2,3" 默认使用逗号作为元素连接符
arr.join(' ');  //=>"1 2 3" 以空格作为连接符
arr.join('|');  //=>"1|2|3" 以‘|’作为连接符

reverse()
Array.reverse()该方法将数组中的的元素颠倒顺序,在原数组上进行操作。方法返回值为对原来数组的引用。

var arr = [1, 2, 3];
arr.reverse().join(); //=>"3,2,1" ,并且现在arr为[3,2,1]

sort()
Array.sort([compareFunction])该方法将数组中的元素排序并返回对原来数组的引用。不传递参数调用时,默认按照字母顺序排序。

var fruits = ['banana', 'cherry', 'apple'];
fruits.sort().join();  //=>apple,banana,cherry

当按照其他方式排序时,就要提供一个比较函数compareFunction。该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:

  • 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
  • 若 a 等于 b,则返回 0。
  • 若 a 大于 b,则返回一个大于 0 的值。
var s = [33, 666, 12, 5];
s.sort();                 //字母顺序:12,33,5,666
s.sort(function (a, b) {  //数字顺序:5,12,33,666return a - b;
});

如果要排序的数组元素包含undefined,它们会被排到数组尾部。

concat()
Array.concat(arr1[,arr2,...])该方法用于连接两个或多个数组并返回一个新数组,不会改变现有数组本身。

var a = [1, 2];
a.concat(4, 5);           //=>[1,2,4,5]     连接每一个参数值
a.concat([4, 5]);         //=>[1,2,4,5]     连接一个数组
a.concat([4, 5], [6, 7]); //=>[1,2,4,5,6,7] 连接多个数组 

slice()
Array.slice(start[,end])该方法用来从已有的数组返回选定的元素,返回一个新的数组。两个参数分别指定要选定元素的开始位置和结束位置。

  • start参数表示从什么位置开始取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
  • end是一个可选参数。规定从何处结束选取,但不包括该下标元素。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
var a = [1, 2, 3, 4, 5];
a.slice(0, 3);     //返回[1,2,3]
a.slice(3);        //返回[4,5]
a.slice(1, -1);    //返回[2,3,4]
a.slice(-3, -2);   //返回[3]

splice()
Array.splice(index,count[, item1[, item2[, ...]]])该方法用来向数组中添加或删除元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。返回被删除的元素。该方法会改变原始数组。

  • index参数代表要添加或删除元素的索引。
  • count参数代表要从数组中删除的元素个数。如果省略,从index起点到数组结尾的元素全删除。
  • item1,item2,...从第三个参数开始是可选参数。代表向数组添加的新元素。
var names = ["George", "Thomas"];
names.splice(1, 0, "John");  //在索引为1的地方插入一个新元素
names.splice(0, 1, "Tom");   //将第一个元素'George'替换成'Tom'

splice()slice()方法,一个字母之差但是功能完全不同,注意区别使用。

push()和pop()
Array.push(element1,element2,...)该方法用来向数组的末尾添加一个或多个元素,并返回新的长度。
Array.pop()方法用来删除数组的最后一个元素,减小数组长度,返回删除的元素值。

组合push()pop()能够让JavaScript数组实现先进后出的栈功能:push()入栈、pop()出栈。

var stack = [];      //空栈
stack.push(1, 2);    //stack:[1,2]
stack.pop();         //stack:[1]
stack.push(3);       //stack:[1,3]
stack.pop();         //stack:[1]
stack.push([4, 5]);  //stack:[1,[4, 5]]
stack.pop();         //stack:[1]
stack.pop();         //stack:[]

unshift()和shift()
Array.unshift(element1,element2,...)该方法可向数组的开头添加一个或更多元素,并返回新的长度。
Array.shift()方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。如果数组为空,shift()不进行任何操作,返回undefined

这两个方法行为非常类似于push()pop()。不一样的是,这两个方法是在数组头部操作。

var arr = [3, 4];
arr.unshift(1,2);   // arr:[1,2,3,4]
arr.shift();        // arr:[2,3,4] 

toString()和toLocalString()
数组对象和普通对象一样拥有toString()方法。该方法会将数组元素转化为字符串,用逗号把生成的字符串连接起来,形成一个字符串。返回值与没有参数的join()方法返回的字符串相同。

[1, 2, 3].toString();        //"1,2,3"
["a", "b", "c"].toString();  //"a,b,c"
[1, [2, 'c']].toString();    //"1,2,c"

toLocalString()toString()的本地化方法。

ECMAScript 5中定义了9个新的数组方法来遍历,映射,过滤,检测,简化和搜索数组。有了这些方法就不用利用for循环来遍历数组了。

forEach()
Array.forEach(callback[, thisArg])方法用来从头致尾遍历数组,为每个元素调用回调方法。对于稀疏数组,不存在的元素不调用回调方法。

  • callback参数就是在数组每一项上执行的函数,接收三个参数:数组元素、元素索引和数组本身。
  • thisArg是可选参数,用来当作callback函数内this的值的对象。如果省略了thisArg参数,或者赋值为nullundefined,则 this 在非严格模式下将是全局对象,严格模式下为 undefined

下面看个综合例子:以数组元素为半径,计算所有圆的面积。

var numbers = [5, 6];  // Define an array.
var obj = {showResults: function(value, index,array) {var squared = this.calcSquare(value);document.write("value: " + value);document.write(" index: " + index);document.write(" squared: " + squared);document.write("<br />");},calcSquare: function(x) { return x * x }
};
numbers.forEach(function(value, index) { this.showResults(value, index) }, obj);
// Output:
//  value: 5 index: 0 squared: 25
//  value: 6 index: 1 squared: 36

注意:没有办法中止或者跳出forEach循环,除了抛出一个异常。它总是返回undefined,即没有返回值。

map()
Array.map(callback[, thisArg])方法和forEach()同样是用来遍历数组,为每个元素执行回调方法。该方法参数与forEach()方法参数一致,不再赘述。但是传给map()的函数应该有返回值。

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt); //求数组中每个元素的平方根
/* roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9] */

filter()
Array.filter(callback[, thisArg])方法用来过滤数组元素,将符合规则的元素组成一个新数组返回,不会改变原数组。callback参数就是用来测试数组中元素的方法,返回true表示通过测试。

var arr = [1, 2, 3, 4, 5];
var res = arr.filter(function (value, index, array) {return value > 3;  //过滤掉小于等于3的元素
});
alert(res.toString()); //=> 4,5

对其非稠密数组,压缩删除undefinednull元素,可以这样使用filter()

arr.filter(function (value) { return value != undefined && value != null; });

every()和some()
Array.every(callback[, thisArg])该方法用来测试数组元素是否都通过了指定函数的测试。
Array.some(callback[, thisArg])该方法用来测试数组某些元素是否通过了指定函数的测试。
这两个方法就是数组的逻辑判断。它们对数组元素调用指定方法,返回truefalse

var arr = [1, 2, 3, 4, 5];
arr.every(function (value) { return value < 10; }); //=>true 所有元素值<10
arr.every(function (value) { return value % 2 == 0; }); //false 并非所有元素都为偶数
arr.some(function (value) { return value % 2 == 0; }); //=>true 数组元素包含偶数
arr.some(isNaN); //=>false 数组不包含非数值元素

注意:当every()some()已确认该返回什么值的时候就会停止遍历数组。

reduce()和reduceRight()
Array.reduce(callback[, initialValue])该方法会针对数组中每个元素调用指定回调函数,将回调函数的返回值作为累积,然后以参数的形式传递到下个元素的回调方法中。

  • callback参数是数组元素要执行的回调函数。最多可接收4个参数:之前元素累积值、当前元素值、元素索引、数组本身。
  • initialValue是可选参数,表示元素最开始调用回调函数传入的初始值。如果缺省该参数,它会使用数组第一个元素作为初始值,这样数组就会少迭代一次。
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function (previous, current, index, array) {return previous + current;
}, 5);
var max = arr.reduce(function (previous, current, index, array) {return previous > current ? previous : current;
});
console.log(sum); //=>15  求和
console.log(max); //=>4   求最大值

利用reduce()可以轻松实现二维数组的扁平化:

var matrix = [ [1, 2], [3, 4], [5, 6] ];
var flatten = matrix.reduce(function (previous, current) {return previous.concat(current);
});
console.log(flatten); //=> [1, 2, 3, 4, 5, 6]

Array.reduceRight(callback[, initialvalue])方法的用法与reduce()方法一致,唯一区别是该方法按元素索引降序处理元素。

indexOf()和lastIndexOf()
Array.indexOf(searchvalue[, fromIndex])方法用来搜索数组中给定值的元素,并返回该元素的索引,如果找不到指定的元素则返回-1。indexOf()从数组头至尾开始搜,Array.lastIndexOf(searchvalue[, fromIndex])则相反,从数组尾部为起点开始搜。

  • searchvalue参数代表要搜索的元素值。
  • fromindex是可选参数,表示检索的起始位置。其值可以为字符串数值;填入字符自动忽略,默认为0。
var data = [2, 5, 7, 3, 5];
console.log(data.indexOf(5, "x")); //=> 1 "x"被忽略,用0代替
console.log(data.indexOf(5, "3")); //=> 4  从3号位开始搜索

大多数浏览器都支持以上方法。针对低版本IE6-IE8浏览器兼容性问题,可通过Array原型扩展实现以上方法。例如forEach方法:

if (!Array.prototype.forEach) {Array.prototype.forEach = function (callback, thisArg) {//TODO};
}

数组类型

数组是具有特殊行为的对象。开发中可能会遇到这样的情况:给定一个未知对象,判断它是否为数组对象。ECMAScript 5版本中可以用Array.isArray()方法鉴别。

console.log(Array.isArray([])); //=> true
console.log(Array.isArray({})); //=> false

在ECMAScript 5版本以前没有Array.isArray()这个方法,typeof可解决大部分的数据类型判断但是在这却帮不上忙。

instanceof操作符可以检测,但有局限性,只能作用于单页面的情形。

console.log([] instanceof Array);  //=> true
console.log({} instanceof Array);  //=> false

当页面中存在子页面iframe时,在子页面中声明一个数组object,并将其赋值给父页面的一个变量,这时判断该变量:object instanceof Array会返回false。原因是数组是引用类型,在赋值过程中,传递的是引用地址。但是每个页面都有自己的一套全局对象,并且每个全局对象有自己的构造函数。object是子页面Array对象,传递到父页面,在父页面判断时却是以父页面的Array对象为标准。

ECMAScript 3版本中,检测对象是否为数组的isArray()可以这样写:

var isArray = Array.isArray() || function isArray(arg) {return typeof arg === 'object' &&  //是否为对象object.length === 'number' &&  //验证length属性Object.prototype.toString.call(arg) === '[object Array]'; //判断基本类型*
}

根据数组的一些特性来判断,上面一段代码也正是ES5中Array.isArray()方法的实现形式。

类数组对象

通常把一个具有与数组相仿属性的常规对象叫做“类数组”对象,即具有length属性对应非负正整数属性。类数组对象不能直接调用数组的方法,但可以数组的形式遍历。

//定义一个类数组对象
var obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
//当作数组遍历
for (var i = 0; i < obj.length; i++) {console.log(obj[i]);
}

JavaScript函数体中Arguments对象是一个类数组对象。一些DOM方法也返回类数组对象,比如
document.getElementsByTagName()

可以用下面的方法检查对象是否为类数组:

function isArrayLike(o) {if (o &&                                //判断o非null,undefined等typeof o === 'object' &&            //o是对象isFinite(o.length) &&               //o.length是有限数o.length > 0 &&                     //o.length是非负数o.length < 4294967296 &&            //o.length小于2^32o.length === Math.floor(o.length))  //o.length是整数return true;elsereturn false;
}

ES5版本中,所有Array数组方法都是通用的,类数组对象上同样适用。类数组对象没有继承至Array.prototype不能直接调用,但可以通过Function.call方法调用:

var obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
console.log(Array.prototype.join.call(obj, '|'));  //=> a|b|c
var arr = Array.prototype.map.call(obj, function (value) {return value.toUpperCase();
});
console.log(arr.join); //=> A,B,C   此时arr已是真正的数组

参考与扩展

本篇内容源自我对《JavaScript权威指南》第7章 数组 章节的阅读总结和代码实践。总结的比较粗糙,你也可通过原著或MDN更深入了解数组。

[1] David Flanagan,JavaScript权威指南(第6版)
[2] MDN,JavaScript 参考文档 - Array - JavaScript | MDN

JavaScript权威指南 - 数组相关推荐

  1. 《JavaScript权威指南》笔记(一)

    2019独角兽企业重金招聘Python工程师标准>>> <JavaScript权威指南>真是名符其实的好书!真遗憾初学JavaScript时没有立即读这本书,甚为遗憾.不 ...

  2. JavaScript权威指南 - 函数

    函数本身就是一段JavaScript代码,定义一次但可能被调用任意次.如果函数挂载在一个对象上,作为对象的一个属性,通常这种函数被称作对象的方法.用于初始化一个新创建的对象的函数被称作构造函数. 相对 ...

  3. JavaScript 权威指南-学习笔记(一)

    本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! JavaScript 权威指南-学习笔记 ...

  4. Javascript权威指南学习笔记一:数据类型

    决定从最基础的开始学JavaScript,最近看了<<Javascript权威指南>>第3章,记些笔记备忘. 本章一个重点是类型.按我的理解应该如下表所示: 复合类型中,关联数 ...

  5. 《JavaScript权威指南》——JavaScript核心

    前言 这本由David Flanagan著作,并由淘宝前端团队译的<JavaScript权威指南>,也就是我们俗称的"犀牛书",算是JS界公认的"圣经&quo ...

  6. 翻译:《JavaScript 权威指南(第5版)》第一章(一)

    声明:翻译只有一个目的:学习用途.若有版权问题请及时联系本人. 本贴文根据篇幅将第一章的翻译分为两个部分,这是第一部分的内容. Chapter 1. Introduction to JavaScrip ...

  7. JavaScript权威指南 第11章JavaScript标准库

    JavaScript权威指南 第11章JavaScript标准库 第11章 JavaScript标准库 11.1 集合与映射 11.1.1 Set类 11.1.2 Map类 11.1.3 WeakMa ...

  8. JavaScript权威指南 第15章 网络编程 第三部分

    JavaScript权威指南 第15章 网络编程 第三部分 可伸缩矢量图形 15.7.1 在HTML中使用SVG 15.7.2 编程操作SVG 15.7.3 通过JavaScript创建SVG图片 1 ...

  9. 你是怎么看完《JavaScript权威指南》《JavaScript高级程序设计》等这类厚书的?

    参考博客原址:https://www.cnblogs.com/tonykair/p/7502276.html 你是怎么看完<JavaScript权威指南><JavaScript高级程 ...

最新文章

  1. access“idno”字段改为文本型_结构化文本计算示例(一)
  2. QCom MSM MDP显示驱动一些点的简记
  3. Python自动化之语法基础
  4. linux配置4g网络命令_树莓派移动网络连接(配置4G网卡)
  5. 使用注解配置spring如@Compnent、@Service、@Consroller、@scope和@value的使用
  6. 【OpenGL】理解GL_TRIANGLE_STRIP等绘制三角形序列的三种方式
  7. PL/SQL编程的简单学习
  8. 微信小程序引用php函数,微信小程序Page中data数据操作和函数调用详细介绍
  9. 解决float型数据精度损失问题
  10. ROS:launch文件的语法规范
  11. Android 开发者不得不面对的六个问题
  12. c语言程序长度单位换算表大全,小学数学单位换算公式大全(附专项训练)
  13. Aras innovator: 怎样把excel文件导入到Aras数据库
  14. CAD高版本窗体阵列LISP_AutoCAD高版本把阵列对话框调出来
  15. Python网络爬虫实例(爬一些小网站的图片)
  16. 百度超级链(xuperchain),make时出现错误
  17. 5G千兆工业路由器 poe供电
  18. 科大讯飞踩过的“坑”,还有多少AI企业要踩?
  19. 科技公司的域名大战!
  20. 计算机组成原理 微机,【2017年整理】计算机组成原理-微机实验指导书.doc

热门文章

  1. Oracle和al,ORACLEAL TERTABLE
  2. new blob文件设置编码_前端下载文件amp;下载进度
  3. 对于新安装的MySQL如何提升MySQL的安全级别
  4. 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  5. 微软推出Windows Sandbox:可安全运行任何应用的一次性VM\n
  6. 5G汽车联盟与欧洲汽车电信联盟签署合作谅解备忘录
  7. 如何提高微信公众号流量主收入
  8. 4种常用压缩格式在hadoop中的应用
  9. 试戴系统完全开放—zoomla!逐浪cms在后4.6时代的又一个亮点
  10. C#GDI绘制自定义字体