JavaScript里的数组详解

前言:这篇文章用于了解总结JS里的数组的相关知识。我会从基本概念,构造方法和常用的API这几个方面来介绍数组。部分概念与代码摘自阮一峰JS教程

1、数组是什么

数组(array)是按次序排列的一组值。每个值的位置都有编号(从0开始),整个数组用方括号表示。

其实本质上,数组属于一种特殊的对象。typeof运算符会返回数组的类型是object。
数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2…)。而由于数组成员的键名是固定的(默认总是0、1、2…),因此数组不用为每个元素指定键名,而对象的每个成员都必须指定键名。

2、数组的length属性

数组的length属性,返回数组的成员数量。只要是数组,就一定有length属性。该属性是一个动态的值,等于键名中的最大整数加上1。

3、数组的构造方法

  • var x = new Array(3) ; // 3表示数组的长度,每一项都为undefined
  • var y = new Array(3,3); // 此时得到一个数组[3,3] ,即里面的两个参数表示数组的第0项和第1项

上面两行代码展示了JS的不一致行,即不同的参数个数,导致相同位置的参数所表示的意义是不同的。
使用new Array()的构造方法,是仿自Java中的写法,不常用。

因此,其实众所周知的函数构造方法是直接定义,如:
var a = [3,3] ; // 得到了一个数组a,其中第0项和第一项分别为3、3

4、in 运算符 && for…in 循环

检查某个键名是否存在的运算符in,适用于对象,也适用于数组。
因此,数组也是可以使用for in循环的,for...in循环不仅可以遍历对象,也可以遍历数组,毕竟数组只是一种特殊对象。
如:

var a = [1, 2, 3];

for (var i in a) {
  console.log(a[i]);
}
// 1
// 2
// 3

但是,for...in不仅会遍历数组所有的数字键,还会遍历非数字键。因此不建议使用。

var a = [1, 2, 3];
a.foo = true;

for (var key in a) {
  console.log(key);
}
// 0
// 1
// 2
// foo

5、数组的遍历

上面讲了使用for…in来遍历数组,但是不建议使用,我们常用的数组遍历方法有for循环或while循环

如:

var a = [1, 2, 3];

// for循环
for(var i = 0; i < a.length; i++) {
  console.log(a[i]);
}

// while循环
var i = 0;
while (i < a.length) {
  console.log(a[i]);
  i++;
}

var l = a.length;
while (l--) {
  console.log(a[l]);
}

6、数组的空位

当数组的某个位置是空元素,即两个逗号之间没有任何值,我们称该数组存在空位(hole),下面代码表明,数组的空位不影响length属性。
如:var a = [1, , 1]; a.length // 3
数组的空位是可以读取的,返回undefined。
使用delete命令删除一个数组成员,会形成空位,并且不会影响length属性。如:

var a = [1, 2, 3];
delete a[1];

a[1] // undefined
a.length // 3

注:数组的某个位置是空位,与某个位置是undefined,是不一样的。如果是空位,使用数组的forEach方法、for...in结构、以及Object.keys方法进行遍历,空位都会被跳过,如果某个位置是undefined,遍历的时候就不会被跳过。
如:

// 数组中有空位时
var a = [, , ,];

a.forEach(function (x, i) {
  console.log(i + '. ' + x);
})
// 不产生任何输出

for (var i in a) {
  console.log(i);
}
// 不产生任何输出

Object.keys(a)
// []

//数组中的值为undefined时
var a = [undefined, undefined, undefined];

a.forEach(function (x, i) {
  console.log(i + '. ' + x);
});
// 0. undefined
// 1. undefined
// 2. undefined

for (var i in a) {
  console.log(i);
}
// 0
// 1
// 2

Object.keys(a)
// ['0', '1', '2']

这就是说,空位就是数组没有这个元素,所以不会被遍历到,而undefined则表示数组有这个元素,值是undefined,所以遍历不会跳过。

7、类数组对象

如果一个对象的所有键名都是正整数或零,并且有length属性,那么这个对象就很像数组,语法上称为“类似数组的对象”(array-like object)。
典型的“类似数组的对象”是函数的arguments对象,以及大多数 DOM 元素集,还有字符串。

数组与类数组对象最本质的区别为:类数组对象的原型链中没有Array.prototype,即:
数组.__proto__ === Array.protype
类数组对象.__proto__ === Object.prototype

因此产生了一句很神奇的话:数组之所以是数组不是因为它本身是数组,而是因为你认为它是数组所以它才是数组。

8、数组的各种API

  • forEach() 遍历
    不支持breakcontinue
    代码示例:
array = ['a','b','c','d'] ;
array.forEach(function(value,key){
  console.log(key+':'+value);
})
// 0:a
// 1:b
// 2:c
// 3:d

其中:使用forEach循环遍历,原数组不会被改变,没有返回值

  • sort() 排序
    该方法是JS封装的一个重排序方法,使用的算法是“快速排序”。不传参时默认为升序排列。注:sort()方法返回的是原数组,即使用该方法会改变原来的数组序列
    =>arr.sort(function(a,b){return a-b}) 升序
    =>arr.sort(function(a,b){return b-a}) 降序
    上面两行代码中,为什么return a-b会升序排列,return b-a会降序排列呢?
    原理如下:

函数返回值 小于等于 -1 时,a在前,b在后
函数返回值 在区间(-1,1)时,序列不变
函数的返回值 大于等于 1 时 ,b在前,a在后

  • join() 分隔
    该方法返回的是字符串,参数表示用什么分隔数组的每一项,不传参默认逗号分隔,参数为空数组时,数组每一项之间没有间隔。
    代码示例:
array = ["a", "b", "c", "d"];
array.join('-');
// "a-b-c-d"
  • concat() 连接
    该方法返回的是新数组,原数组不会被改变。
    代码示例:
a = [1,2,30] ;
b = [42,22,33];
a.concat(b);
// 得到新数组 [1, 2, 30, 42, 22, 33]

使用concat()方法可以用于复制数组,如:

arr = [1,2,3,4,5,6];
var newArr = arr.concat([]);
// newArr 的值为 [1, 2, 3, 4, 5, 6]
newArr === arr; // false

注:关于newArr === arr返回的是false,因为数组也是对象,所以参照对象的相等可得,newArr 和 arr 是两个不同地址的引用,只是恰好他们引用的地址中的值是一样的而已,而两个对象本身的值肯定是不同的。

  • map()
    功能与forEach相同,但map()有返回值。同样不会改变原数组的值,返回的一个新数组。
    代码示例:
arr = [1, 2, 3, 4, 5, 6];
arr.map(function(value,key){
    return value * 2;
})
// [2, 4, 6, 8, 10, 12]
  • filter() 过滤、筛选
    用法与map()一样,代码示例:
arr = [1, 2, 3, 4, 5, 6];
arr.filter(function(value,key){
    return value > 3
})
// [4, 5, 6]
  • reduce() 可接收一个函数作为累加器
    代码示例:计算数组中每一项相加的值
arr = [1, 2, 3, 4, 5, 6];
arr.reduce(function(previous,current){
    return previous + current;
},0)
// 21

reduce()方法,第一个参数传一个函数作为累加器,第二个参数表示初始值。

可以用reduce()方法来写map()数组每一项×2:

a = [1, 2, 3, 4, 5, 6];
a.reduce(function(array,n){
    array.push(n * 2);
    return array;
},[])
// [2, 4, 6, 8, 10, 12]

可以用reduce()方法来写filter()筛选偶数:

a = [1, 2, 3, 4, 5, 6];
a.reduce(function(array,n){
    if(n % 2 === 0){
            array.push(n);
        }
    return array;
},[])
// [2, 4, 6]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容