前言 JavaScript 中的数组是一个很特别的存在,他不像Java ,专门搞了 List 这样的一整套的东西,JS终端数组完全可以当作栈或队列来使用,数组的四大操作:pop、push、shift、unshift。
我今天写这篇博客,主要是写一篇总结,以备以后查看。
对于数组方法,我们应该关心的只有两个问题,返回值是什么,会不会修改原数组, 典型的例子就是 splice() 和 slice() 这两个方法。
接下来,带着这两个问题,我会相对详细的总结一下我们数组原型(数组实例) 里面所拥有的方法和属性,另外,常用的方法,我会加上一个常用的例子(应用场景)
ps: 文中有些和数组方法不是太相关的知识,仅供了解,这里就不展开了(实际上也是我太垃圾了0 0,不懂) 具体我会在文末放上相关链接
下面将不再重复这些方法的 callbak 的参数
(find、findIndex、some、filter、every、map,forEach,flatMap)的callback 被调用时会传入三个参数:当前元素值,元素的索引,原数组。这些方法都不会改变元素组,但是,如果你操作第三个参数,那就不一样了。
数组的属性 length length 是Array的实例属性。返回或设置一个数组中的元素个数。该值是一个无符号 32-bit 整数,并且总是大于数组最高项的下标。
let arr = [1 ,2 ,3 ]console .log(arr.length)
length 属性的值是一个 0 到 232-1 的整数。
let arr1 = new Array (4294967296 ) console .log(arr1)let arr2 = new Array (-100 ) console .log(arr1)
你还可以通过 length 来截断数组
let arr = [1 ,2 ,3 ,4 ]arr.length = 2 console .log(arr)
Array.length 属性的属性特性 属性 值 writable true enumerable false configurable false
Writable :如果设置为false,该属性值将不能被修改。 Configurable :如果设置为false,删除或更改任何属性都将会失败。 Enumerable :如果设置为 true ,属性可以通过迭代器for或for…in进行迭代。 看到这里,估计有人想问,既然 length 属性是可以修改的,那么我们可不可以重定义数组对象的 length 属性呢?答案是可以的,但是会受到一般的重定义限制。并且并不是所有浏览器都允许 Array.length 的重定义。这里就不展开了,如有兴趣请看文末的链接
数组的静态方法 Array.isArray() 在这个方法没出来之前,很多早期类库是通过下列代码来判断的(鸭子判断),文末送上玉伯大佬的链接,希望大家都去了解一下
function isArray (object ) { return object != null && typeof object === "object" && 'splice' in object && 'join' in object }
直到后来有神人出山,写出了一段神码,此代码一出,天下震惊,引各路类库竞折腰。这代码,不不仅仅解决了数组的问题,而是解决了 isXxx 一类问题。
function isArray (obj ) { return Object .prototype.toString.call(obj) === "[object Array]" }
对现代浏览器来说,上面的写法,依旧让各大浏览器引擎的实现者觉得很难受,于是直接有了Array.isArray方法
Array .isArray([]) Array .isArray(Array .prototype)
Array.from() Array.from() 方法从一个类似数组或可迭代对象中创建一个新的数组实例
console .log(Array .from('foo' )) console .log(Array .from([1 , 2 , 3 ], x => x + x)) Array .from([1 ],function (x ) { console .log(this ) return x },{a :1 })
实际上,通过 Array.from 我们就可以做一些很常见的事了,比如我们的数组去重合并
const combine = (...arg )=> { let arr = [].concat.apply([], arg); return Array .from(new Set (arr)); } let m = [1 , 2 , 2 ], n = [2 ,3 ,3 ,4 ]; console .log(combine(m,n))
Array.of() Array.of() 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。
Array.of() 和 Array 构造函数之间的区别在于处理整数参数:Array.of(7) 创建一个具有单个元素 7 的数组,而 Array(7) 创建一个长度为7的空数组(注意:这是指一个有7个空位的数组,而不是由7个undefined组成的数组)。
Array .of(7 ); Array .of(1 , 2 , 3 ); Array (7 ); Array (1 , 2 , 3 );
拷贝填充相关 concat concat() 方法用于合并两个或多个数组。此方法不会更改原数组 ,而是返回一个新数组。
有个降维的例子会在 reduce() ,这里就不过讲解了,避免重复
let arr1 = [1 ,2 ,3 ]let arr2 = [4 ,5 ,6 ]console .log(arr1.concat(arr2)) console .log(arr1) console .log(arr2)
实际应用中,我们可以用 concat 和 reduce 搭配,实现扁平化数组(降维)
const flatten = (arr, shallow ) => { if (shallow) { var arr = arr.reduce((arr, val ) => arr.concat(val), []) } else { var arr = arr.reduce((arr, val ) => arr.concat(Array .isArray(val) ? flatten(val) : val), []) } return arr } const arr = [1 ,[2 ,[3 ,4 ]],5 ]console .log(flatten(arr,true )) console .log(flatten(arr))
copyWithin copyWithin() 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,而不修改其大小。此方法会更改现有数组
ps:参数target,start和end 必须为整数。如果start为负,则其指定的索引位置等同于length+start,length为数组的长度。end也是如此。(copyWithin,fill等方法的start、end参数同理)
let arr = [1 ,2 ,3 ,4 ,5 ]console .log(arr.copyWithin(0 , 3 , 4 )) console .log(arr) console .log([1 , 2 , 3 , 4 , 5 ].copyWithin(-2 )) console .log([1 , 2 , 3 , 4 , 5 ].copyWithin(0 , 3 )) console .log([1 , 2 , 3 , 4 , 5 ].copyWithin(-2 , -3 , -1 ))
fill fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引 。此方法会更改现有数组
let arr = [1 ,2 ,3 ,4 ]console .log(arr.fill(0 , 2 , 4 )) console .log([1 , 2 , 3 ].fill(4 )) console .log([1 , 2 , 3 ].fill(4 ,1 )) console .log([1 , 2 , 3 ].fill(4 ,-1 )) console .log([1 , 2 , 3 ].fill(4 ,-2 ,-1 ))
搜索查找相关 find find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
const arr = [1 ,2 ,3 ,4 ]console .log(arr.find(item => item>2 )) console .log(arr.find(item => item>6 ))
实际应用场景中,我们可以用对象的属性查找数组里的对象
const people = [{ name:'gating' , age:18 },{ name:'blue' , age:15 },{ name:'family' , age:18 }] const findName = (arr ) => arr.name === 'gating' ;console .log(people.find(findName))
findIndex findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。
const arr = [1 ,2 ,3 ,4 ]console .log(arr.findIndex(item => item>2 )) console .log(arr.findIndex(item => item>6 ))
实际应用场景同 find() ,这里就不重复了
indexOf indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
indexOf 和 lastIndexOf 都是使用 === 来进行判断
const arr = ['a' ,'b' ,'c' ,'a' ]console .log(arr.indexOf('a' )) console .log(arr.indexOf('a' ,-1 )) console .log(arr.indexOf('d' ))
实际应用场景中,我们不可能之只找出一个同名元素的索引值,我们可能需要找出同名的元素的所有位置,于是乎
const indices = [];const arr = ['a' ,'b' ,'c' ,'a' ]const searchElement = 'a' let idx = arr.indexOf(searchElement);while (idx != -1 ) { indices.push(idx); idx = arr.indexOf(searchElement, idx + 1 ); } console .log(indices)
lastIndexOf lastIndexOf() 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。
const arr = ['a' ,'b' ,'c' ,'a' ]console .log(arr.lastIndexOf('a' )) console .log(arr.lastIndexOf('a' ,-1 )) console .log(arr.lastIndexOf('d' ))
实例:查找所有元素
const indices = []const array = ['a' , 'b' , 'a' , 'c' , 'a' , 'd' ]const element = 'a' let idx = array.lastIndexOf(element)while (idx != -1 ) { indices.push(idx); idx = (idx > 0 ? array.lastIndexOf(element, idx - 1 ) : -1 ); } console .log(indices)
注意,我们要单独处理idx==0时的情况,因为如果是第一个元素,忽略了fromIndex参数则第一个元素总会被查找。这不同于indexOf方法
includes includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
如果fromIndex 大于等于数组长度 ,则返回 false 。该数组不会被搜索
如果 fromIndex 为负值,计算出的索引将作为开始搜索searchElement的位置。如果计算出的索引小于 0,则整个数组都会被搜索。
const arr = [1 ,2 ,3 ,NaN ]console .log(arr.includes(1 , -100 )) console .log(arr.includes(1 , 5 ))
实际的应用场景,通过可以解决我们找出两个数组的 数组交集 和 数组差集
const intersection = (arr1, arr2 ) => arr1.filter(v => arr2.includes(v))const difference = (arr1, arr2 ) => [...arr1, ...arr2].filter(v => !arr1.includes(v) || !arr2.includes(v))const arr1 = [1 ,2 ,3 ]const arr2 = [2 ,3 ,4 ]console .log(intersection(arr1,arr2)) console .log(difference(arr1,arr2))
操作相关 slice slice() 方法返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝。此方法不会更改原数组 。
const arr = [1 ,2 ,3 ,4 ,5 ]console .log(arr.slice()) console .log(arr.slice(2 )) console .log(arr.slice(2 , 4 )) console .log(arr.slice(-1 )) console .log(arr.slice(-2 ,-1 ))
实际应用中,slice 就可以做很多事情啦,比如说,我们的数组切割或者生成二维数组
const chunk = (arr, subArrayNum ) => { const result = []; for (let i = 0 ; i < arr.length; i += subArrayNum) { result.push(arr.slice(i, i + subArrayNum)); } return result; } console .log(chunk([1 ,2 ,3 ,4 ],2 )) const take = (arr, n ) => arr.slice(0 , n ? n : 1 )console .log(take([1 ,2 ,3 ,4 ],2 ))
splice splice()方法通过删除现有元素和/或添加新元素来修改数组,并以数组返回原数组中被修改的内容。此方法会更改现有数组 。
const arr = [1 ,3 ]const res = arr.splice(1 , 0 , 2 )console .log(arr) console .log(res) const result = arr.splice(2 , 1 )console .log(arr) console .log(result) arr.splice(-1 , 1 ) console .log(arr) const fruits = ['apple' ,'banana' ,'orange' ,'pear' ]const res1 = fruits.splice(2 )console .log(fruits) console .log(res1)
因为 js 中只有 splice 这个方法删除数组元素,并且会修改数组长度,所以他的实际应用场景还挺多的0 0,但是我没有太好的例子可以距离
push push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。 此方法会更改现有数组 。
const arr = [1 ,2 ,3 ]console .log(arr.push(4 )) console .log(arr)
push、pop、shift、unshift 方法有意具有通用性。该方法和 call() 或 apply() 一起使用时,可应用在类似数组的对象上。这个比较有意义,所以单独在这里送上MDN的链接 ,当然例子也是MDN的O(∩_∩)O
像数组一样使用对象这个例子 push、pop、shift、unshift 四个方法写法很类似,这里就重复写了
var vegetables = ['parsnip' , 'potato' ]var moreVegs = ['celery' , 'beetroot' ]Array .prototype.push.apply(vegetables, moreVegs)console .log(vegetables) var obj = { length: 0 , addElem: function addElem (elem ) { [].push.call(this , elem); }, popElem: function addElem ( ) { return [].pop.call(this ); } } obj.addElem({}) obj.addElem({a :1 }) console .log(obj.length) console .log(obj.popElem()) console .log(obj.length)
pop pop()方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。此方法会更改现有数组 。
如果你在一个空数组上调用 pop(),它返回 undefined。
const arr = [1 ,2 ,3 ]console .log(arr.pop()) console .log(arr)
shift shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。此方法会更改现有数组 。
const arr = [1 ,2 ,3 ]console .log(arr.shift()) console .log(arr)
unshift unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度。此方法会更改现有数组 。
const arr = [3 ,4 ,5 ]console .log(arr.unshift(1 ,2 )) console .log(arr)
但实际上,我们不建议用 unshift 方法往前面添加元素,为什么呢?从原理就可以知道,unshift()的效率是较低的。原因是,它每添加一个元素,都要把现有元素往下移一个位置。
下面我们简单测试一下,unshift 和 push 的性能区别
console .time('unshift所用时间' )const unshift = []for (let i = 0 ; i < 10000 ; i++) { unshift.unshift(i) } console .timeEnd('unshift所用时间' )console .time('push所用时间' )const push = []for (let i = 0 ; i < 10000 ; i++) { push.push(i) } console .timeEnd('push所用时间' )console .time('reverse所用时间' )push.reverse(); console .timeEnd('reverse所用时间' )
大家可是复制一下这段代码,在我们数据量不是特别大的时候,他们的效率差别几十倍,因此,平时还是要慎用unshift(),特别是对大数组。此方法会更改现有数组 。
但是我们可以通过 reverse 和 push 的方法实现我们 unshift ,比如
const arr = [3 ,4 ,5 ]console .log(arr.unshift(1 ,2 )) console .log(arr) const arr2 = [3 ,4 ,5 ]arr2.reverse().push(2 ,1 ) arr2.reverse() console .log(arr2)
sort sort() 方法用原地算法对数组的元素进行排序,并返回数组。排序算法现在是稳定的。默认排序顺序是根据字符串Unicode码点。此方法会更改现有数组 。
const months = ['March' , 'Jan' , 'Feb' , 'Dec' ];months.sort() console .log(months)
如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。例如 “Banana” 会被排列到 “cherry” 之前。当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 compareFunction),比较的数字会先被转换为字符串,所以在Unicode顺序上 “80” 要比 “9” 要靠前。
所以我们怎么解决这个问题了,当然要使用我们的比较函数啦,而且通过我们的比较函数,可以实现很多我们需要的效果
const arr = ["1" ,2 ,"11" ,3 ,"21" ]console .log(arr.sort()) console .log(arr.sort((a,b )=> a-b)) const people = [{name :'gating' ,age :18 },{name :'family' ,age :16 },{name :'blue' ,age :21 }]people.sort((a,b )=> a.age - b.age) const numbers = [1 ,2 ,3 ]numbers.sort(() =>Math .random()-0.5 )
关于数组乱序,正确的解法应该是 Fisher–Yates Shuffle,复杂度 O(n)。其实它的思想非常的简单,遍历数组元素,将其与之前的任意元素交换。因为遍历有从前向后和从后往前两种方式,所以该算法大致也有两个版本的实现。
这里送上两个方法,具体的请参考文末的数组乱序文章
const shuffle = (array ) => { var _array = array.concat(); for (var i = _array.length; i--;) { var j = Math .floor(Math .random() * (i + 1 )); var temp = _array[i]; _array[i] = _array[j]; _array[j] = temp; } return _array; } const shuffle = (a ) => { var length = a.length; var shuffled = Array (length); for (var index = 0 , rand; index < length; index++) { rand = ~~(Math .random() * (index + 1 )); if (rand !== index) shuffled[index] = shuffled[rand]; shuffled[rand] = a[index]; } return shuffled; }
reverse reverse() 方法将数组中元素的位置颠倒。第一个数组元素成为最后一个数组元素,最后一个数组元素成为第一个。此方法会更改现有数组 。
const months = ['March' , 'Jan' , 'Feb' , 'Dec' ];months.reverse() console .log(months)
join join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。此方法不会更改原数组 。
const arr = [1 ,2 ,3 ]console .log(arr.join()) console .log(arr.join('-' ))
迭代(循环遍历)相关 every every() 方法测试数组的所有元素是否都通过了指定函数的测试。此方法不会更改原数组 。
const arr = [1 ,2 ,4 ,2 ,4 ,56 ]console .log(arr.every(item => item<10 ))
some some() 方法测试数组中的某些元素是否通过由提供的函数实现的测试。此方法不会更改原数组 。
some() 和 every() 的区别在于every是数组所有元素都需要通过测试才返回true,而some只需要有一个通过测试就返回true
对于放在空数组上的任何条件,此方法返回false。
const arr = [1 ,2 ,4 ,2 ,4 ,56 ]console .log(arr.some(item => item<10 ))
实际的应用场景,可以实现类似于 includes 的功能 (这里或许你会问,为啥实现类似 includes 的功能,直接用不就好了吗?
因为 includes 的兼容性太差了,IE是不兼容的,但是 some 在IE9下却可以使用,所以,你懂的
var fruits = ['apple' , 'banana' , 'mango' , 'guava' ];function checkAvailability (arr, val ) { return arr.some(arrVal => val === arrVal); } checkAvailability(fruits, 'kela' ); checkAvailability(fruits, 'banana' );
forEach forEach() 方法对数组的每个元素执行一次提供的函数。
for 和 forEach 的区别,forEach中已删除或者未初始化的项将被跳过(例如在稀疏数组上),而 for 不会
注意: 没有办法中止或者跳出 forEach 循环,除了抛出一个异常。
const arr1 = [1 ,2 ,3 ]arr1.forEach(item => { console .log(item) }) const arr2 = [1 ,2 ,,4 ]for (let index = 0 ; index < arr2.length; index++) { console .log(arr2[index]) } arr2.forEach(item => { console .log(item) })
实际的应用场景,我们可以通过 forEach 实现对对象的复制,当然,这只是对象复制的其中一种方式
const copy = obj => { const copy = Object .create(Object .getPrototypeOf(obj)) const propNames = Object .getOwnPropertyNames(obj) propNames.forEach(function (name ) { const desc = Object .getOwnPropertyDescriptor(obj, name); Object .defineProperty(copy, name, desc); }) return copy; } const obj1 = {name :'gating' }const obj2 = copy(obj1)console .log(obj2)
map map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。此方法不会更改原数组 。
const arr = [1 ,2 ,3 ]console .log(arr.map(item => item*2 ))
map 的应用场景很多,比如我想给数组增加一个id的属性,再比如可以重新格式化我们的数组
const arr = [{name :'gating' },{name :'family' }]const res = arr.map((item,index )=> { item.id = index return item }) console .log(res)
由一条面试题引发的思考 通常情况下,map 方法中的 callback 函数只需要接受一个参数,就是正在被遍历的数组元素本身。但这并不意味着 map 只给 callback 传了一个参数。
["1" , "2" , "3" ].map(parseInt ); function returnInt (element ) { return parseInt (element, 10 ); } ['1' , '2' , '3' ].map(returnInt); ['1' , '2' , '3' ].map( str => parseInt (str) ); ['1' , '2' , '3' ].map(Number ); ['1.1' , '2.2e2' , '3e300' ].map(Number );
filter filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。此方法不会更改原数组 。
const arr = [{sex :'male' ,name :'gating' },{sex :'female' ,name :'blue' },{sex :'male' ,name :'family' }]console .log(arr.filter(item => item.sex==='female' ))
实际的应用场景,通过可以 filter 过滤掉我们不需要的值
const delListRep = (arr, key ) => { var keys = [] for (let i = 0 ; i < arr.length; i++) { keys.push(arr[i][key]) } return arr.filter((ele, i, arr ) => keys.indexOf(ele[key]) == i) } const arr = [{sex :'male' ,name :'gating' },{sex :'female' ,name :'blue' },{sex :'male' ,name :'gating' }]console .log(delListRep(arr,'sex' ))
reduce reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。不会更改原数组 。
如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
const arr = [1 , 2 , 3 , 4 ];const reducer = arr.reduce((accumulator, currentValue ) => accumulator + currentValue)console .log(reducer) console .log(arr) const res = arr.reduce((accumulator, currentValue ) => accumulator + currentValue,5 )console .log(res) arr.reduce((accumulator, currentValue, index ) => { console .log(index) }) arr.reduce((accumulator, currentValue, index ) => { console .log(index) },5 )
看到了 reduce 的用法,实际上也可以想到,reduce 的参数这么丰富,是不是可以做很多我们想要的事,我想说,是的,在实际应用中,reduce 能做到的事,比我们想象中的还要多
比如,数组扁平化、数组去重、统计数组中每个元素出现的次数、根据属性对Object分类等等等等这种很cool的事,接下来,我们就一一用 reduce 实现吧
reduce 很重要,请务必掌握这个方法 ps:字符串的 replace 也很重要哦!!!也要掌握
function groupBy (arr, key ) { return arr.reduce(function (newObj, obj ) { if (!newObj[obj[key]]) { newObj[obj[key]] = []; newObj[obj[key]].push(obj); } else { newObj[obj[key]].push(obj); } return newObj; }, {}); } const people = [ { name : 'gating' , age : 18 }, { name : 'family' , age : 16 }, { name : 'blue' , age : 20 } ]; const groupedPeople = groupBy(people, 'age' ) const names = ['gating' , 'family' , 'gating' , 'blue' , 'family' ]const countNum1 = (arr ) => arr.reduce((m, x )=> m.set(x, (m.get(x) || 0 ) + 1 ), new Map ())const allName = countNum1(names) let arr = [1 ,2 ,1 ,2 ,3 ,5 ,4 ,5 ,3 ,4 ,4 ,4 ,4 ];let result = arr.sort().reduce((init, current )=> { if (init.length===0 || init[init.length-1 ]!==current){ init.push(current); } return init; }, []); console .log(result);
其实 reduce 还可以做很多更牛逼的事,看到这里,你是不是也想用 reduce 做更多强大的事呢?那就赶紧把 reduce 学会
reduceRight reduceRight() 方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。不会更改原数组 。
const arr = [[0 , 1 ], [2 , 3 ], [4 , 5 ]].reduceRight( (accumulator, currentValue) => accumulator.concat(currentValue) ) console .log(arr)
reduce 与 reduceRight 之间的区别
const arr = ['1' , '2' , '3' , '4' , '5' ]; const left = arr.reduce((prev, cur )=> prev + cur); const right = arr.reduce((prev, cur )=> prev + cur); console .log(left); console .log(right);
由于 reduceRight 和 reduce 区别不是很大,这里的例子就参考 reduce 就行了
迭代相关(生成一个迭代器) 暂时没有太多的应用场景,不详细讲解
entries entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
const arr1 = [1 ,2 ,3 ]const iterator1 = arr1.entries();for (let number of iterator1) { console .log(number) } const arr2 = [1 ,2 ,3 ]const iterator2 = arr2.entries();console .log(iterator2.next().value); console .log(iterator2.next().value); console .log(iterator2.next().value); console .log(iterator2.next().value);
keys keys() 方法返回一个包含数组中每个索引键的Array Iterator对象。
const arr = ['a' ,'b' ,'c' ]const iterator = arr.keys(); for (let key of iterator) { console .log(key); }
values values() 方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值
const arr = ['a' ,'b' ,'c' ]const iterator = arr.values()for (let value of iterator) { console .log(key) }
不知名的两个方法 toString toString() 返回一个字符串,表示指定的数组及其元素
const arr = ['a' ,'b' ,'c' ]console .log(arr.toString())
toLocaleString toLocaleString() 返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 “,”)隔开。
var array1 = [1 , 'a' , new Date ('21 Dec 1997 14:12:00 UTC' )]var localeString = array1.toLocaleString('en' , {timeZone : "UTC" })console .log(localeString) var prices = ['¥7' , 500 , 8123 , 12 ] prices.toLocaleString('ja-JP' , { style : 'currency' , currency : 'JPY' })
这个方法我用的真不多,所以这里还是直接放上MDN的地址 供大家了解,或许以后就用到了呢?
扁平化数组 本来这个我写这篇博客的时候,看到MDN
写着這是一個實驗中的功能
,所以我就没有记录下来,不过最近再看一眼,发现那个waring
已经去掉了,所以就写一下这两个方法
flat flat() 方法返回一个包含将数组与子数组中所有元素的新数组。不会更改原数组 。
var arr1 = [1 ,[2 ],3 ]console .log(arr1.flat()) var arr2 = [1 ,[2 ,[3 ]]]console .log(arr2.flat()) console .log(arr2.flat(2 )) var arr3 = [1 , 2 , [3 , 4 , [5 , 6 , [7 , 8 , [9 , 10 ]]]]]console .log(arr3.flat(Infinity )) var arr4 = [1 , 2 , , 4 , 5 ]console .log(arr3.flat())
看到这里,你也许会发现,这个不就是我们上边通过reduce
实现的扁平化方法吗?没错,es6之后默认给我们自带了这个方法(👍)
flatMap 顾名思义啦,从名字我们就可以知道,这个方法就是即执行 map
又执行 flat
,对此官方的说法是,首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map
连着深度值为1的 flat
几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。
var arr = [1 ,2 ,3 ]console .log(arr.flatMap(x => [x*2 ])) console .log(arr.map(x => [x*2 ]).flat())var people = [{name :"gating" ,age :18 },{name :"family" ,age :20 },{name :"blue" ,age :60 }]console .log(people.flatMap(i => i.age>=60 ?[]:[i]))
通过过滤那个例子,我们就可以看出, 输出的列表长度可以不同于输入的列表长度。这也许也是 flatMap
可玩之处(🤤)
文中某些知识点参考链接 重定义数组对象的 length 属性
MDN地址,文中很多例子都采用于MDN,推荐
数组类型判断,玉伯大佬博客,推荐
JavaScript 数组乱序
数组的完全随机排列
鉴于 reduce 和 reduceRight 太过好用(太过牛逼),这里提供他们两个的MDN地址
reduce
reduceRight
总结 针对于我们一开始关心的两个问题,我在这里做一个小小的总结
ps: 对于测试性的方法,这里就不做展开了,因为用不上= =
方法名 返回值 是否修改原数组 concat 返回合并后的 Array
实例 否 copyWithin 改变了的数组 是 entries 一个新的 Array
迭代器对象( [key,value]) 否 every 布尔值,表示数组中所有元素是否通过 every 测试 否 fill 修改后的数组 是 filter 一个新的通过测试的元素的集合的数组,如果没有通过测试则返回空数组 否 find 当某个元素通过 callback
的测试时,返回数组中的一个值,否则返回 undefined
。 否 findIndex 返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。 否 forEach undefined
否 includes 布尔值, 判断一个数组是否包含一个指定的值 否 indexOf 首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1 否 join 一个所有数组元素连接的字符串。如果 arr.length
为0,则返回空字符串 否 keys 一个新的 Array
迭代器对象( [key]) 否 lastIndexOf 数组中最后一个元素的索引,如未找到返回-1 否 map 一个新数组,每个元素都是回调函数的结果 否 pop 从数组中删除的元素(当数组为空时返回undefined
) 是 push 当调用该方法时,新的 length
属性值将被返回。 是 reduce 函数累计处理的结果 否 reduceRight 执行之后的返回值 否 reverse 返回颠倒后的 Array
是 shift 返回被删除元素的值 是 slice 一个含有提取元素的新数组 否 some 布尔值,表示数组中至少有一个元素是否通过 every 测试 否 sort 排序后的数组 是 splice 由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组 是 toLocaleString 表示数组元素的字符串 否 toString 个表示指定的数组及其元素的字符串 否 unshift 返回其 length
属性值 是 values 一个新的 Array
迭代器对象( [value]) 否 flat 一个包含将数组与子数组中所有元素的新数组 否 flatMap 一个新的数组,其中每个元素都是回调函数的结果,并且结构深度 depth 值为1 否
最后,感谢各位观众老爷观看啦O(∩_∩)O