玩转现代javascript数组,这一篇就够了

作者: 张阳君 分类: 前端技术

最近项目很多地方都用到了数组,我就顺带总结一下现代javascript数组的玩法。本文涉及的数组知识都是基于es5+的,你可以使用chrome等现代浏览器直接运行本文的例子,或者用babel编码后执行。

js数组相关的知识点总结如下:一个构造函数一个扩展运算符三个静态方法一个length属性一堆数组实例方法。不吹牛皮,能掌握上述知识点,js数组就能玩得很溜了。

一个构造函数

Array是原生的js对象,他包含了三个静态方法,下面的小节会提到。Array也是js数组的构造函数。Array作为数组的构造函数,使用方法如下:

let list = new Array(6,6,6);

构造函数大家了解一下即可,因为Array不同的入参形式会生成不同格式的数组,行为比较怪异,一般情况下还是使用字面量来初始化数组比较靠谱:

let list = [6,6,6];

我们也可以使用Array.of()来创建数组,这个静态方法比构造函数要好用的多,下面会有提及。

一个扩展运算符

扩展运算符是es6+的新玩意,玩前端的都应该熟悉。这个新运算符看上去就是三个点...,可以用在所有Iterator结构的数据上,说通俗点就是js的数组和对象都能使用扩展运算符。扩展运算符可以把数组展开,一般都是配合其他表达式一起使用。数组有了扩展运算符真的是如鱼得水,操作数组的灵活性也上升到了全新的高度。

  1. 用扩展运算符实现浅拷贝:
let arr1 = [1,5,6];
let arr2 = [...arr2]; //arr2独立存在

注意:这里是浅拷贝,如果数组元素中还存在对象等类型的数据,该元素仅仅是指针被拷贝过去,实际还是指向同一个对象。

  1. 更快捷地函数传参:
// 示例1
let params = ['小明',18,'大学生'];
printInfo(...params); // 等于 printInfo('小明',18,'大学生')

// 示例2
let params2 = [98,35,21,54,78,3,26];
Math.max(...params2); // 等于 Math.max(98,35,21,54,78,3,26)
  1. 数组合并:
let params = [55,78,69,88];
let params2 = [98,35,21,54,78,3,26];
let params3 = [...params,...params2]; // [55,78,69,88,98,35,21,54,78,3,26]
  1. 解构赋值:
let [leader,...apprentices] = ['王重阳','马钰','丘处机','谭处端','王处一','郝大通','刘处玄','孙不二'];
console.log(leader); // '王重阳'
console.log(apprentices); // ['马钰','丘处机','谭处端','王处一','郝大通','刘处玄','孙不二']

三个静态方法

Array作为原生js对象,包含了三个静态方法。这些静态方法使用频率不高,但在有些场景下用起来非常方便。

Array.isArray()

Array.isArray()就是用来判断一个变量是否为数组的,简单直观,无需多言。

还记得原来怎么判断一个变量是数组类型的吗?你肯定不会忘记下面这个写法吧:

var arr = ['小明',18,3000];
console.log(Object.prototype.toString.call(arr) === '[object Array]'); // true

在es5到来之前这种写法是最保险的,但是现在我们可以这么写了:

var arr = ['小明',18,3000];
console.log(Array.isArray(arr)); // true

Array.from()

Array.from()可以把类数组对象转变成真正的数组。那么什么算是类数组对象呢?简而言之,如果一个对象包含length属性,我们就视其为类数组对象。类数组对象用Array.from()转换之后,就可以使用数组的实例方法了。下面几个小例子随意感受一下:

// 示例1 将类数组对象转换为数组
let userInfo = {
    '0': '小明',
    '1': '18',
    '2': '3000',
    length: 3
};
let userInfoArr = Array.from(userInfo); // ['小明',18,3000]

// 示例2 函数中的预置变量arguments也是个类数组对象
function foo() {
  var args = Array.from(arguments);
}

// 示例3 dom节点也是一个类数组对象
Array.from(document.querySelectorAll('div'))

Array.from()的第二个参数接受一个函数回调,具体是生成数组后,再进行一次map操作:

Array.from(obj,val=>val);
//等同于
Array.from(obj).map(val=>val);

Array.of()

Array.of()可以用来生成数组,其作用和Array构造函数一样,但是行为和字面量声明模式一致,推荐使用这种方法来生成数组。

var arr = Array.of('小明',18,3000);
//等同于
var arr = ['小明',18,3000];

一个length属性

length是数组实例的一个非常重要的属性,他代表该数组的长度。我们也可以给length赋值正整数,以此改变数组的长度,遵循多空少删的原则。

// 示例1 
var arr = ['小明',18,3000];
console.log(arr.length); // 3

// 示例2
var arr2 = ['小明',18,3000];
arr2.length = 1;

// 示例3
var arr3 = ['小明',18,3000];
arr3.length = 5;

一堆数组实例方法

数组的实例方法是操作数组的精髓,可以将这些方法归为异变、非异变和迭代器三种类型。异变类的方法会改变当前的数组变量,而非异变类的方法一般会生成新的返回值、对当前变量没有任何影响。迭代器方法则是对数组做迭代遍历操作,最后返回相应值,迭代器的入参都是回调函数。

异变类方法

1. push()pop()

push()可以向数组的尾部添加元素,pop()是从数组尾部删除元素,push()方法可以接收多个入参。这两个方法会改变数组本身的值,并返回最后一个添加/删除的元素。

// 示例1 push方法
var arr = [1];
console.log(arr.push(2,3)); // 3
console.log(arr); // [1,2,3]

// 示例2 pop方法
var arr2 = [1,2,3];
console.log(arr2.pop()); // 3
console.log(arr2); // [1,2]

2. shift()unshift()

unshift()可以向数组的头部添加元素,shift()则是从数组头部删除元素,unshift()方法可以接收多个入参。这两个方法会改变数组本身的值,并返回最后一个添加/删除的元素。这两个方法和push()pop()行为一致。

// 示例1 unshift方法
var arr = [1];
console.log(arr.unshift(2,3)); // 3
console.log(arr); // [2,3,1]

// 示例2 shift方法
var arr2 = [1,2,3];
console.log(arr2.shift()); // 1
console.log(arr2); // [2,3]

3. reverse()

reverse()方法用来反转数组,该方法会返回反转后的数组,同时数组本身也会改变。

var arr = [1, 2, 3];
console.log(arr.reverse()); // [3,2,1]
console.log(arr); // [3,2,1]

4. splice()

splice()方法用来在指定位置删除或插入数组元素。参数从1个到多个不等,来个公式感受一下:

arr.splice(以0为起点的初始位置<如果是负数则从尾部开始计数>,需要删除元素的数量<可选,不填写则表示删到数组尾部>,插入元素<可选>,插入元素<可选>...);

splice()方法会改变数组,并返回被删除元素组成的数组。

// 示例1 从某位置删除元素
var arr = [1, 2, 3];
console.log(arr.splice(0,1)); // [1]
console.log(arr); // [2,3]

// 示例2 从某位置删到底
var arr2 = [1, 2, 3];
console.log(arr2.splice(1)); // [2,3]
console.log(arr2); // [1]

// 示例3 从倒数某位置删到底
var arr3 = [1, 2, 3];
console.log(arr3.splice(-1)); // [3]
console.log(arr3); // [1,2]

// 示例4 从某位置插入元素
var arr4 = [1, 2, 3];
console.log(arr4.splice(3,0,4,5)); // []
console.log(arr4); // [1,2,3,4,5]

// 示例5 从某位置开始替换并增加元素
var arr5 = [1, 2, 3];
console.log(arr5.splice(2,1,4,5)); // [3]
console.log(arr5); // [1,2,4,5]

上述示例基本涵盖了splice()的所有用法,建议在浏览器里跑一下,看看执行结果。

5. sort()

sort()方法可以对数组里的元素进行排序,sort()默认的排序规则是字典排序,这种排序方式会把元素强制转变成字符串形式,按位比较大小。举个例子,按照这种方式,121会排在15之前。sort()也可以像迭代器那样,接收一个函数。迭代器函数按顺序比较前后两个元素,如果函数返回值大于0则前者排在后者之后,否则相反。

// 示例1 普通情况
var arr = [3,2,1];
console.log(arr.sort()); // [1,2,3]
console.log(arr); // [1,2,3]

// 示例2 特殊情况
var arr2 = [10,3,2,1];
console.log(arr2.sort()); // [1,10,2,3]
console.log(arr2); // [1,10,2,3]

// 示例3 迭代器
var arr3 = [10,3,2,1];
console.log(arr3.sort(function (prev, next) {
  return prev-next;
})); // [1,2,3,10]
console.log(arr3); // [1,2,3,10]

// 示例4 对象元素排序
var arr4 = [{name:'小赵',age:10},{name:'小钱',age:3},{name:'小孙',age:2},{name:'小李',age:1}];
console.log(arr4.sort(function (prev, next) {
  return prev.age-next.age;
})); // [{name:'小李',age:1},{name:'小孙',age:2},{name:'小钱',age:3},{name:'小赵',age:10}]
console.log(arr4); // [{name:'小李',age:1},{name:'小孙',age:2},{name:'小钱',age:3},{name:'小赵',age:10}]

6. copyWithin()

copyWithin()方法可以在当前数组复制元素到内部其他位置。看下使用公式:

arr.copyWithin(以0为起点的被替换位置,复制元素的起点<可选,默认值为0>,复制元素的终点<可选,默认值为数组长度>);

看几个代码示例:

// 示例1 普通复制
var arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 4);
console.log(arr); // [5, 2, 3, 4, 5]

// 示例2 倒序复制
var arr2 = [1, 2, 3, 4, 5];
arr2.copyWithin(0, -2, -1);
console.log(arr2); // [4, 2, 3, 4, 5]

7. fill()

fill()方法可以指定某个值来填充整个数组。上代码:

// 示例1 普通填充
var arr = [1, 2, 3, 4, 5];
arr.fill(6);
console.log(arr); // [6, 6, 6, 6, 6]

// 示例2 指定位置填充
var arr2 = [1, 2, 3, 4, 5];
arr2.fill(6, 2, 3);
console.log(arr2); // [1, 2, 6, 4, 5]

非异变类方法

1. valueOf()

valueOf()方法返回数组本身,注意不是拷贝!参考下面代码:

var arr = [1,2];
var arr2 = arr.valueOf();
arr[0]=5;
console.log(arr2) // [5,2]

这个方法对数组来说,并没有什么卵用。

2. toString()

toString()方法会将数组展平,并返回当前数组的字符串形式,元素之间以逗号隔开:

var arr = [1, 2, ['a', function foo() { alert(123123) }, 5, 7]];
console.log(arr.toString()); // 1,2,a,function foo() { alert(123123) },5,7

3. join()

join()方法可以指定分隔符,将数组转变为字符串,如果没有指定分隔符,则默认以逗号隔开。

// 示例1 不指定分隔符
var arr = [1, 2, 3, 4, 5];
console.log(arr.join()); // 1,2,3,4,5

// 示例2 指定分隔符
var arr2 = [1, 2, 3, 4, 5];
console.log(arr2.join('|')); // 1|2|3|4|5

4. concat()

concat()方法主要用来合并数组,这里的合并都是浅拷贝。

// 示例1 数组和数组合并
var arr = [1, 2, 3, 4, 5];
console.log(arr.concat([6,7,8,9])); // 1,2,3,4,5,6,7,8,9

// 示例2 数组和其他元素合并
var arr2 = [1, 2, 3, 4, 5];
console.log(arr2.concat('a','b',7)); // 1,2,3,4,5,a,b,7

5. slice()

slice()方法可以用来截取数组,数组本身不变。该方法公式如下:

arr.slice(截取的开始位置<默认为0,可以为负数>, 截取的终止位置<可选,默认是数组长度>);

slice()的常用代码:

// 示例1 普通截取
var arr = [1, 2, 3, 4, 5];
console.log(arr.slice(1,3)); // [2,3]

// 示例2 倒序截取
var arr2 = [1, 2, 3, 4, 5];
console.log(arr2.slice(-3,5)); // [3,4,5]

// 示例3 1个入参的普通截取
var arr3 = [1, 2, 3, 4, 5];
console.log(arr3.slice(1)); // [2, 3, 4, 5]

// 示例4 开始位置大于结束位置
var arr4 = [1, 2, 3, 4, 5];
console.log(arr4.slice(2,1)); // []

6. indexOf()lastIndexOf()

indexOf()返回指定元素第一次出现的位置,lastIndexOf()返回指定元素最后一次出现的位置。如果没有搜索到,则返回-1。

// 示例1 普通用法
var arr = [1, 2, 3, 4, 5];
console.log(arr.indexOf(5)); // 4

// 示例2 指定开始搜索的位置
var arr2 = [2, 2, 3, 4, 5];
console.log(arr2.indexOf(2,1)); // 1

// 示例3 倒序搜索
var arr3 = [1, 4, 3, 4, 5];
console.log(arr3.lastIndexOf(4)); // 3

// 示例4 NaN永远返回-1
var arr4 = [NaN, NaN, NaN, NaN, NaN];
console.log(arr4.indexOf(NaN)); // -1

7. entries()keys()values()

entries()返回当前数组的完整结构的遍历器、keys()返回当前数组的索引、values()返回当前数组的值。

// 示例1 entries()用法
var arr = [1, 2, 3];
var iterator=arr.entries();
console.log(iterator); // Iterator
console.log(iterator.next().value); // [0,1]
console.log(iterator.next().value); // [1,2]
console.log(iterator.next().value); // [2,3]

// 示例2 keys()用法
var arr2 = [1, 2, 3];
var iterator2=arr2.keys();
console.log(iterator2); // Iterator
console.log(iterator2.next().value); // 0
console.log(iterator2.next().value); // 1
console.log(iterator2.next().value); // 2

// 示例3 values()用法
var arr3 = [1, 2, 3];
var iterator3=arr3.values();
console.log(iterator3); // Iterator
console.log(iterator3.next().value); // 1
console.log(iterator3.next().value); // 2
console.log(iterator3.next().value); // 3

8. includes()

includes()方法搜索给定值是否在数组中,如果存在返回true,否则返回false。可以传第二个参数,指定开始搜索的位置。

// 示例1 常规用法
var arr = [1, 2, 3];
console.log(arr.includes(2)); // true

// 示例2 指定搜索位置
var arr2 = [1, 2, 3];
console.log(arr2.includes(2,2)); // false

// 示例3 可以检索出NaN
var arr3 = [1, NaN, 3];
console.log(arr3.includes(NaN)); // true

9. flat()

flat()方法可以拉平数组,其接收一个参数表示要拉平数组的层数,默认是一层。

// 示例1 常规用法
var arr = [1, 2, [3, 4]];
console.log(arr.flat()); // [1,2,3,4]

// 示例2 拉平2层
var arr2 = [1, 2, [3, 4, [5, 6,[7,8]]]];
console.log(arr2.flat(2)); // [1,2,3,4,5,6,[7,8]]

// 示例3 无论多少层都拉平
var arr3 = [1, 2, [3, 4, [5, 6,[7,8]]]];
console.log(arr3.flat(Infinity)); // [1,2,3,4,5,6,7,8]

迭代器方法

1. map()

map()可以将操作数组的每个元素,最终返回一个新的数组。

let arr = [1, 2, 3, 4];
console.log(arr.map(item=>item*2)); // [2,4,6,8]

2. forEach()

forEach()可以将操作数组的每个元素,但没有返回值。

let tmp = [];
let arr = [1, 2, 3, 4];
arr.forEach(item=>tmp.push(item*2))
console.log(tmp); // [2,4,6,8]

3. filter()

filter()可以将操作数组的每个元素,每次操作结果为true的元素塞入最终返回的数组。

let arr = [1, 2, 3, 4];
console.log(arr.filter(item=>item >2)); // [3,4]

4. some()

some()用来判断当前数组中是否包含符合条件的元素,没有匹配的话返回false,否则返回true。

// 示例1 没有匹配
let arr = [1, 2, 3, 4];
console.log(arr.some(item=>item >5)); // false

// 示例2 匹配
let arr2 = [1, 2, 3, 4];
console.log(arr2.some(item=>item===4)); // true

5. every()

every()用来判断当前数组中是否所有元素都符合判断条件,所有元素都匹配才返回true,否则返回false。

// 示例1 全匹配
let arr = [1, 2, 3, 4];
console.log(arr.every(item=>item < 5)); // true

// 示例2 匹配
let arr2 = [1, 2, 3, 4];
console.log(arr2.every(item=>item < 2)); // false

6. reduce()reduceRight()

reduce()方法是对当前数组从左到右依次执行函数操作,最后返回累计操作后的值。reduceRight()则是从右往左执行。

var arr = [1,2,3,4,5];
console.log(arr.reduce(function(prev,cur){
  return prev+cur;
})) // 15

7. find()

find()方法用来找到第一个符合条件的元素,返回该元素的值,如果没有任何值匹配条件,则返回undefined。

let arr = [1,2,3,4,5];
console.log(arr.find(item=>item>3)); // 4

8. findIndex()

findIndex()方法用来找到第一个符合条件的元素,返回该元素的序号,如果没有任何值匹配条件,则返回-1。

let arr = [1,2,3,4,5];
console.log(arr.findIndex(item=>item>3)); // 3

9. flatMap()

flatMap()方法先对原数组执行map()操作,然后将得到的数组进行flat()拉平操作,这里只能拉平一层。

let arr = [1,2,3,4,5];
console.log(arr.flatMap(item=>[item,item*2])); // [1,2,2,4,3,6,4,8,5,10]

小结

以上就是现代js数组的大部分知识点,将数组的这些用法融会贯通,前端业务水平绝对能上一个档次。这里作者给你留了一个问题:运用上述数组知识,提炼出数组中重复的值,并组成一个新的数组。欢迎关注下方的公众号,来和作者讨论吧!

(全文完)

0 条评论
回复
支持 Markdown 语法
暂无评论,来抢个沙发吧!