重学JavaScript系列之——数组

我心飞翔 分类:javascript

数组是ECMAScript中最重要的数据存储类型之一,数组是一组有序的数据,每个槽位可以存储任意类型的数据。也就是说可以创建这样一个数组:第一个元素是字符串,第二个元素是数值,第三元素是函数,第四个元素是数组,甚至存放下文即将讲到的Map、WeakMap数据结构。数组具有length值,每增加减一个元素,length的值也会随之变化。

数组内部每一项元素,其实也是按照key:value的结构存储的。你认为的['a','b','c']其实是这样存储的[0:'a',1:'b',2:'c']。比如你给数组新增元素时,下标若是非数值类型,则会尽量被转换为数值,若无法转换为数值,则会调用下标参数的toString方法转换为字符串。

var arr = [];
arr[0] = 'a';   // ['a']
arr['1'] = 'b';  // ['a','b']
arr['str'] = 'valueStr'  // ['a','b','str':'valueStr']
arr[{a:1}] = 'valueObject';   // ['a','b','str':'valueStr','[object Object]':'valueObject']
arr[['1']] = 'valueArr';  // ["a", "valueArr", str: "valueStr", [object Object]: "valueObject"]
 

最后一个或许你会有点迷糊,其实是这样的:下标值['1']是数组,这个时候会隐式的调用数组的toString(),也就是Array原型链上的toString方法转换为"1",然后再将字符串类型的1转换为数值类型的1,所以最后一句相当于执行了arr[1] = 'valueArr'。注意:每一个元素的key值若不是数值类型,则不会计入数组的length属性,所以上述数组最终的length值是2

一、创建数组

以下方法可以创建或者生成数组

var arr = new Array(2);
var arr2 = new Array('a','b','c');
var arr3 = ['a','b','c'];
var arr4 = Array.prototype.slice.call(arguments);
var arr5 = Array.from(arguments || nodeList);   //此方法用于替换第四行ES5提供的转换arguments为数组的方法
var arr6 = Array.of('a','b','c');
 

Array.from()方法的第一个参数是一个类数组对象,即任何可迭代的结构,或者拥有length属性和可索引元素的结构,常见的有arguments、nodeList等。第二个为可选的映射函数,其参数结构类似数组的map方法,加上第二个参数等于转换为数组后再将元素一一通过函数过滤一遍。还可以增加第三个可选参数,第三个参数用于映射函数中this的值。

function fn(a,b,c){
  return Array.from(arguments,function(item){
    return item + 1
  })
}
fn(1,2,3);  
// [2,3,4]
 

Array.of()方法将一组给定的数值转换成数组。

二、增加数组

push()在数组尾部增加新元素,并返回新数组的长度length

var arr = ['a','b'];
arr.push('c','d');  // 4
 

unshift()在数组头部增加新元素,并返回新数组的长度length

var arr2 = ['a'];
arr2.unshift('b','c');  // 4
 

三、删除数组

pop()删除数组最后一项,并返回删除的元素

var arr = ['a','b'];
arr.pop();  // 'b'
 

shift()删除数组第一项,并返回删除的元素

var arr2 = ['a','b'];
arr2.shift();  // 'a'
 

splice()支持三个参数,都是非必需的。

  • 第一个参数是起始位置,第二个是删除截止位置,第三个参数用来填充删除后的坑位;
  • 返回删除的元素组成的数组,若没删除则返回空数组;
  • 第一个参数、第二个参数具有顾前不顾后的原则,也就是包含第一个位置元素,不包含第二个参数位置的元素;
var arr = ['a','b','c','d'];
arr.splice(0,1);  // ['a']
arr.splice(-1);   //  ['d']
arr.splice(0,1,1);
// [1,'c']
 

若只有第一个参数,则默认删除到数组最后一位。若第一个参数为负数,则默认倒数第N位置删除,直到数组最后一位。

四、改变数组

以下几个方法在执行完毕后都会修改原数组(包括上面的push、unshift、pop、shift、splice)
reverse()将指定的数组翻转顺序。

copyWithin(beReplaceIndex,startIndex,endIndex)在当前数组内部,将指定范围内的一组元素复制并覆盖另外一组元素,最后返回修改过的数组。最多支持三个参数,从startIndex位置开始,endIndex位置结束,复制一段数组后,再从beReplaceIndex位置开始替换内容。

fill(newTarget,start,end)使用给定值替换数组内部元素。也是最多支持三个参数(均为可选),第一个参数为新替换的元素,第二个元素为指定开始替换的位置,第三个参数为结束位置。若无任何参数,则数组元素都替换为undefined,若只有一个参数,则默认全部替换。若只有两个参数,则默认替换到数组尾部。

flat()可以将多维数组(数组嵌套数组)“拍扁”变成一维数组。支持添加整数参数,即需要“拍扁”几维数组,就填数字几。若不知维度,可填写无穷大数组Infinity

sort()对数组元素进行排序,并返回排序后的数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的。无法保证排序的时间和空间复杂性。支持compareFunction参数,若为空,则按照字符串的首字母Unicode排序。若调用方法,则按照调用函数的返回值排序。

  • 如果 compareFunction(a,b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a,b) 等于 0 ,则 a b的相对位置不变;
  • 如果 compareFunction(a,b) 大于 0 ,则 b 会排在 a 前面

五、查询数组

indexOf()查找给定元素的第一个索引值,若不存在则返回-1。语法:第一个参数是要查找的元素,第二个参数是开始查找的位置(可选)。

lastIndexOf()与上面方法类似。区别是:从尾部开始倒叙查询,返回数组中最后一个匹配元素的索引值。

find()查找并返回第一个满足函数的元素,若没有则返回undefined。支持第二个可选参数,为执行回调时this的指向。

findIndex()与上面方法类似。区别在于返回索引值,若没有则返回-1。

every()第一个参数为函数,第二个为可选的thisArg值(执行callback时使用的this指向)。该方法返回一个布尔值,只有每个元素都满足函数并返回true,最终才返回true,若有一项返回false,则终止执行后续操作,直接返回false

some()与上述方法类似。区别在于只要有一项满足内部函数,则整体返回true

includes()用来判断一个数组是否包含给定元素,若存在则返回true,否则返回false

六、迭代遍历

forEach()对数组的每个元素执行给定的方法,无返回值。第二个参数老样子,基本上每个支持遍历的方法均支持thisArg作为函数中this的指向(后续方法介绍略过)。注:稀疏数组会被跳过。提到forEach就要好奇如何跳出循环?目前来说只有一个办法跳出或终止循环,那就是抛出异常。

var arr = [1,2,3,4,5,6,7];
try{
  arr.forEach(function(item){
    console.log(item)
    if(item > 3){
      throw new Error('error')
    }
  })
}catch(e){
  console.log(e)
}
 

map()将数组中的每个元素调用给定函数后再返回一个新数组。

filter()对数组的每个元素执行给定给定函数,返回一个符合条件的新数组。

七、转换或复制

slice()语法:(beginIndex,endIndex),还是一句话可以形容,顾前不顾后。从beginIndex位置开始(包含)到endIndex位置(不含)拷贝元素出来,组成并返回一个新的数组。注意:是浅拷贝,所有原生数组提供的方法涉及到拷贝的,都是浅拷贝。该方法不会改变原始数组。

concat()此方法用于合并两个或多个数组,返回一个新数组,不会改变原数组。

join()用指定的字符串将数组的每一项连接起来,返回一个字符串。若为空则默认为,

toString()返回一个字符串,表示指定的数组及其元素。

toLocalString()返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开。

八、其他高级用法

flatMap()也是“拍扁”数组,区别是:优先对数组执行一个map的功能,然后再对返回数组成员执行flat(),然后再返回一个新数组,该方法不会修改原数组,类似执行arr.map().flat()

reduce()从左向右对数组中的每个元素执行一个reducer函数,常用于累加等操作。语法:第一个参数为函数,第二个参数为初始值。注:若初始值为空,则会将数组的第一个元素作为初始值,从第二个元素开始执行函数。

[1, 1, 2, 3, 4].reduce((prev, curr) => prev + curr );
 

reduceRight()同上述方法,区别在于从右向左执行。

keys(),values(),entries()用于遍历数组。它们都返回一个遍历器对象(详见《Iterator》一章),可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。—— 摘自阮一峰的《ECMAScript 6 入门》

回复

我来回复
  • 暂无回复内容