思考几个个问题:
- 数组的构造器有哪些?
- 数组的方法?
- 数组遍历的方法?
- forEach 、for … in、for … of 三者的区别?
数组的构造器
常见创建数组的两种方式
- Array构造器
- 函数自变量
- Array构造器 var A = new Array (arg1, arg2, …)
new Array (arg1, arg2, …) 会根据传入的参数,按顺序依次成为数组的第0-N项
注意两点:
第一,当有且仅有一个参数,参数值不能超过 32 位无符号整型,即需要小于 2 的 32 次方(最大为 Math.pow(2,32));
第二,当有且仅有一个参数l,参数值不超过 32 位无符号整型时,返回的是一个长度为参数的空数组
复制代码
var a = new Array(1, 2, 3, 4)
var b = new Array(4)
var c = new Array('4')
var d = new Array()
console.log(a) // [1, 2, 3, 4]
console.log(b) // [empty * 4]
console.log(c) // ["4"]
console.log(d) // []
复制代码
- 函数自变量 var a = []
var a = [arg1, arg2, arg3, …] 会根据传入的参数,按顺序依次成为数组的第0-N项,无法直接返回指定长度的空数组,通过var a = [], a.length=4 的方式返回指定长度为4的空数组
var a = [1, 2, 3, 4]
var b = [4]
var c = ['4']
var d = []
var e = []
e.length = 4
console.log(a) // [1, 2, 3, 4]
console.log(b) // [4]
console.log(c) // ["4"]
console.log(d) // []
console.log(e) // [empty * 4]
复制代码
es6新增的构造方法
- Array.of
- Array.from
-
Array.of (arg1, arg2, …)与 new Array (arg1, arg2, …)的区别在于,当参数为有且仅有一个的数字时,Array.of 返回的是[arg1]数组, new Array返回的是[empty * arg1]的空数组,也就是说 Array.of 和函数自变量的返回结果一致
-
Array.from / Array.prototype.slice.call() / [].slice.call()的作用 将两类对象转换成数。这两类对象分别为:
(1)可遍历(interable)的对象(包括 Set 和 Map)
(2)典型的“类似数组的对象”是函数的arguments对象,以及大多数 DOM 元素集,还有字符串。类数组的本质是拥有length属性,只要有length属性就可以用Array.from转换成数组
Array.from(arg1, arg2, arg3)接收三个参数, 第一个参数为类数组对象,必选参数,第二个和第三个为可选参数,分别为回调函数和回调函数的this,函数回调也可以直接使用箭头函数,就不需要第三个参数来指定this了,回调函数中可对返回的数组进行处理。返回新的数组,不改变原对象。
var obj = {0: 'a', 1: 'b', 2:'c', length: 3};
Array.from(obj, function(value, index){
console.log(value, index, this, arguments.length);
return value.repeat(3); //必须指定返回值,否则返回 undefined
}, obj);
复制代码
var a = Array.from('abc');
var b = Array.from(new Set(['abc', 'def']));
var c = Array.from(new Map([[1, 'ab'], [2, 'de']]));
var obj = {0: 'a', 1: 'b', 2:'c', length: 3};
var d = Array.from(obj, (value) => value.repeat(3));
console.log(a) // ["a", "b", "c"]
console.log(b) // ["abc", "def"]
console.log(c) // [[1, "ab"], [2, "de"]]
console.log(d) // ["aaa", "bbb", "ccc"]
复制代码
数组的方法
改变自身的方法
pop、push、reverse、shift、sort、splice、unshift,以及两个 ES6 新增的方法 copyWithin 和 fill。
// pop、push、shift、unshift
var a = [1, 2, 3, 4, 5]
var aa = a.pop()
var b = [1, 2, 3, 4, 5]
var bb = b.push(9)
var c = [1, 2, 3, 4, 5]
var cc = c.shift()
var d = [1, 2, 3, 4, 5]
var dd = d.unshift(0)
// pop 删除数组最后一个数据,返回删除的数据
console.log(a) // [1, 2, 3, 4]
console.log(aa) // 5
// push 数组末尾增加一个元素,返回增加后数组的长度
console.log(b) // [1, 2, 3, 4, 5, 9]
console.log(bb) // 9
// shift 删除数组第一个元素,返回删除的元素
console.log(c) // [2, 3, 4, 5]
console.log(cc) // 1
// unshift 数组开始增加一个元素,返回增加后数组的长度
console.log(d) // [0, 1, 2, 3, 4, 5]
console.log(dd) // 6
复制代码
// splice、reverse、sort
var e = [1, 2, 3, 4, 5]
var ee = e.splice(2, 2)
var f = [1, 2, 3, 4, 5]
var ff = f.reverse()
var g = [1, 4, 5, 2, 3]
var gg = g.sort()
// splice(start, len) 删除数组中的元素,start开始位置的index, len删除几个,返回一个数组,由删除的元素组成
console.log(e) // [1, 2, 5]
console.log(ee) // [3,4]
// reverse 数组翻转,返回翻转后的数组
console.log(f) // [5, 4, 3, 2, 1]
console.log(ff) // [5, 4, 3, 2, 1]
// sort 数组排序
console.log(g) // [1, 2, 3, 4, 5]
console.log(gg) // [1, 2, 3, 4, 5]
复制代码
// copyWithin、fill
var h = [1, 2, 3, 4, 5]
var i = [1, 2, 3, 4, 5]
var hh = h.copyWithin(1, 2)
var ii = i.copyWithin(1, 2, 3)
var j = [1, 2, 3, 4, 5]
var k = [1, 2, 3, 4, 5]
var jj = j.fill(6, 1)
var kk = k.fill(6, 1, 2)
// copyWithin(target, start, end) 数组中start-end位置值,复制到以target为开始的位置
console.log(hh)
console.log(ii)
// fill(value, start, end) 采用一默认值填初始化数组,可以指定填充的位置
console.log(jj)
console.log(kk)
复制代码
不改变自身的方法
concat、join、slice、toString、toLocaleString、indexOf、lastIndexOf、未形成标准的 toSource,以及 ES7 新增的方法 includes。
// concat方法
var array = [1, 2, 3];
var array2 = array.concat(4,[5,6],[7,8,9]);
console.log(array2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(array); // [1, 2, 3], 可见原数组并未被修改
// join方法
var array = ['We', 'are', 'Chinese'];
console.log(array.join()); // "We,are,Chinese"
console.log(array.join('+')); // "We+are+Chinese"
// slice方法
var array = ["one", "two", "three","four", "five"];
console.log(array.slice()); // ["one", "two", "three","four", "five"]
console.log(array.slice(2,3)); // ["three"]
// toString方法
var array = ['Jan', 'Feb', 'Mar', 'Apr'];
var str = array.toString();
console.log(str); // Jan,Feb,Mar,Apr
// tolocalString方法
var array= [{name:'zz'}, 123, "abc", new Date()];
var str = array.toLocaleString();
console.log(str); // [object Object],123,abc,2016/1/5 下午1:06:23
// indexOf方法
var array = ['abc', 'def', 'ghi','123'];
console.log(array.indexOf('def')); // 1
// includes方法
var array = [-0, 1, 2];
console.log(array.includes(+0)); // true
console.log(array.includes(1)); // true
var array = [NaN];
console.log(array.includes(NaN)); // true
复制代码
数组遍历的方法
forEach、every、some、filter、map、reduce、reduceRight,以及 ES6 新增的方法 entries、find、findIndex、keys、values。
// 数组遍历
var arr = [1, 2, 3, 4, 5]
var a = arr.every((item) => item < 10)
var b = arr.some((item) => item < 2)
var c = arr.filter((item) => item < 2)
var d = arr.map((item) => item < 2)
var e = arr.forEach((item) => item < 2)
var f = arr.reduce((pre, next) => pre * next)
// 数组遍历返回值
console.log(a) // true
console.log(b) // true
console.log(c) // [1]
console.log(d) // [true, false, false, false, false]
console.log(e) // undefined
console.log(f) // 120
复制代码
var arr = [1, 2, 3, 4, 5]
var a = arr.find((item) => item > 3)
var b = arr.findIndex((item) => item < 2)
var c = arr.keys()
var d = arr.entries()
var e = arr.values()
console.log(a) // 4
console.log(b) // 0
console.log(...c) // 0 1 2 3 4
console.log(...d) // [0, 1] [1, 2] [2, 3] [3, 4] [4, 5]
console.log(...e) // 1 2 3 4 5
复制代码
forEach 、for … in、for … of 三者的区别
- 对数组的每一个元素执行一次提供的函数(不能使用return、break等中断循环),不改变原数组,无返回值undefined。
- 循环遍历的值都是数据结构的键值,for in也可以循环数组但是特别适合遍历对象
- for of 是ES6中新增加的语法,用来循环获取一对键值对中的值,一个数据结构只有部署了 Symbol.iterator 属性, 才具有 iterator接口可以使用 for of循环。例子中的obj对象没有Symbol.iterator属性 所以会报错。
哪些数据结构部署了 Symbol.iteratoer属性了呢?
- 数组 Array
- Map
- Set
- String
- arguments对象
- Nodelist对象, 就是获取的dom列表集合
数组扁平化
1.ES6的flat
const arr = [1, [2, 3, [4, 5]]]
arr.flat(Infinity)
复制代码
2.递归
const arr = [1, [2, 3, [4, 5]]]
const flat = (arr) => {
let result = []
for (let i = 0, len = arr.length; i < len; i++ ) {
Array.isArray(arr[i]) ? result = [...result, ...flat(arr[i])] : result.push(arr[i])
}
return result
}
flat(arr)
复制代码
3.reduce + 递归
const arr = [1, [2, 3, [4, 5]]]
const flat = (arr) => {
if (!Array.isArray(arr)) return
return arr.reduce((prev, curr) => prev.concat(Array.isArray(curr) ? flat(curr) : curr), [])
}
flat(arr)
复制代码
4.扩展运算符 + 迭代
const arr = [1, [2, 3, [4, 5]]]
const flat = (arr) => {
while(arr.some((item) => Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}
flat(arr)
复制代码
5.序列化 + 正则
const arr = [1, [2, 3, [4, 5]]]
const flat = (arr) => {
return JSON.parse(`[${JSON.stringify(arr).replace(/(\[|\])/g, '')}]`)
}
flat(arr)
复制代码
数组去重
1.ES6 Set
const arr = [1, 2, 1, 2, 3 ,4, 5]
const unique = (arr) => {
return Array.from(new Set(arr)) // return [...new Set(arr)]
}
unique(arr)
复制代码
2.利用indexOf、includes
const arr = [1, 2, 1, 2, 3 ,4, 5]
const unique = (arr) => {
let result = []
for (let i of arr) {
if (result.indexOf(i) === -1) { // if (!result.includes(i))
result.push(i)
}
}
return result
}
unique(arr)
复制代码
3.for 循环嵌套
const arr = [1, 2, 1, 2, 3 ,4, 5]
const unique = (arr) => {
for (let i = 0, len = arr.length; i < len; i++) {
for(let j = i + 1, len = arr.length; j < len; j++) {
if(arr[i] === arr[j]) {
arr.splice(i, 1)
j--
}
}
}
return arr
}
unique(arr)
复制代码
4. filter + indexOf
const arr = [1, 2, 1, 2, 3 ,4, 5]
const unique = (arr) => {
return arr.filter((item, index) => arr.indexOf(item) === index)
}
unique(arr)
复制代码
5.reduce + includes
const arr = [1, 2, 1, 2, 3 ,4, 5]
const unique = (arr) => {
return arr.reduce((prev, curr) => prev.includes(curr) ? prev : [...prev, curr], [])
}
unique(arr)
复制代码
6.sort
const arr = [1, 2, 1, 2, 3 ,4, 5]
const unique = (arr) => {
arr = arr.sort()
let result = [arr[0]]
for (let i = 1, len = arr.length; i < len; i++) {
if (arr[i] !== arr[i-1]) {
result.push(arr[i])
}
}
return result
}
unique(arr)
复制代码