js 数组一些高级操作
参考地址:
JS 面试之数组的几个不 low 操作
本文主要从应用来讲数组 api 的一些操作,例如一行代码扁平化n 维数组、数组去重、求数组最大值、数组求和、排序、对象之间的转化等。
记录一:扁平化 n 维数组
[1, [2, 3]].flat(2); // [1, 2, 3]
[1, [2, 3, [4, 5]]].flat(3); // [1, 2, 3, 4, 5]
Array.flat(n) 是 ES10 扁平化数组的 api, n 表示维度, n 值为 Infiniti 时维度为无限大。
js 实现:利用递归和数组合并方法 concat 实现扁平。
function flatten(arr) {
while(arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
flatten([1, [2, 3]]); // [1, 2, 3]
记录二:去重
Array.from(new Set([1, 2, 3, 2, 4])); // [1, 2, 3, 4]
[...new Set([1, 2, 3, 3, 4, 4])]; // [1, 2, 3, 4]
- Set 是 ES6 新出来的一种定义不重复数组的数据类型。
- Array.from 是将类数组转化为数组。
- … 是扩展运算符,将 set 里面的值转化为字符串。
js 实现:可以根据双层循环过滤掉重复项。
Array.prototype.distinct = function() {
var arr = this,
result = [],
i,
j,
len = arr.length;
for(i = 0; i < len; i++) {
for(j = i + 1; j < len; j++) {
if(arr[i] === arr[j]) {
j = ++ i;
}
}
result.push(arr[i]);
}
return result;
};
[1, 2, 2, 3].distinct(); // [1, 2, 3];
记录三:排序
[1, 2, 3, 4].sort(); // [1, 2, 3, 4] 默认是升序
[1, 2, 3, 4].sort((a, b) => b - a); // [4, 3, 2, 1]
sort 是 js 内置的排序方法,参数为一个函数
js 实现:冒泡排序
Array.prototype.bubleSort = function() {
let arr = this,
len = arr.length;
for(let i=0; i<len; i++){
for(let j=i+1; j<len; j++){
if(arr[j-1] > arr[j]){
[arr[j-1], arr[j]] = [arr[j], arr[j-1]]
}
}
}
return arr;
}
[2, 1, 3].bubleSort(); // [1, 2, 3]
js 实现:选择排序
Array.prototype.selectSort = function() {
let arr = this,
len = arr.length;
for (let i = 0; i < len; i ++) {
for (let j = i; j < len; j ++) {
if (arr[i] > arr[j]) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
}
return arr;
}
[1, 3, 2, 4].selectSort(); // [1, 2, 3, 4]
记录四:最大值
Math.max(...[1, 2, 3, 4]); // 4
Math.max.apply(this, [1, 2, 3, 4]); // 4
[1, 2, 3, 4].reduce((prev, cur, curIndex, arr) => {
return Math.max(prev, cur);
}); // 4
记录五:求和
[1, 2, 3, 4].reduce((prev, cur, curIndex, arr) => {
return prev + cur;
}, 0); // 10
记录六:合并
var a = [1, 2, 3, 4];
var b = [5, 6];
a.concat(b); // [1, 2, 3, 4, 5, 6]
[...a, ...b]; // [1, 2, 3, 4, 5, 6]
[].push.apply(a, b); // [1, 2, 3, 4, 5, 6]
b.map(item => {
a.push(item);
}); // [1, 2, 3, 4, 5, 6]
记录七:判断是否包含
[1, 2, 3].includes(4); // false
[1, 2, 3].indexOf(4); // -1 表示没有
[1, 2, 3].find(item => item === 3); // 3 如果没有返回 undefined
[1, 2, 3].findIndex(item => item === 3); // 2 如果没有则返回 -1
includes(), find(), findIndex() 是 ES6 的 api。
记录八:类数组转换
类数组:表示有 length 属性,但是不具备数组的方法。
Array.prototype.slice.call(arguments); // arguments 是类数组(伪数组)
Array.prototype.slice.apply(arguments);
Array.from(arguments);
[...arguments];
// 可运行示例
function a () {
return [...arguments];
}
a(1, 2); // array
Array.from({ length: 9 }, () => 0); // [0, 0, 0, 0, 0, 0, 0, 0, 0]
// document.querySelectorAll('.color'); 返回的也是类数组
var targets = document.querySelectorAll('.color');
[].forEach.apply(targets, function(item){
// do something.
});
// slice 实现
Array.prototype.slice = function(start, end) {
var result = new Array();
start = start || 0;
end = end || this.length;
for(var i = start; i < end; i ++){
result.push(this[i]);
}
return result;
}
- call、apply:改变 slice 里面的 this 指向 arguments, 所以 arguments 也可以调用数组的方法。
- Array.from: 将类数组或可迭代对象创建为数组。
- … 将数组扩展为字符串,再定义为数组。
记录九:每项设置值
[1, 2, 3].fill(false); // [false, false, false]
Array.from({ length: 9 }, () => 0); // [0, 0, 0, 0, 0, 0, 0, 0, 0]
fill 是 ES6 的方法。
记录十:单项处理
// every 每项都满足返回 true
[1, 2, 3].every(item => { return item > 2 }); // false
// 有一项满足返回 true
[1, 2, 3].some(item => { return item > 2 }); // true
// 数组过滤
[1, 2, 3].filter(item => { return item > 2 }); // [3]
some、every、filter 是 ES5 的 api。
记录十一:对象、数组转化
Object.keys({name: 'zhangsan', age: 14}); // ["name", "age"]
Object.values({name: 'zhangsan', age: 14}); // ["zhangsan", 14]
Object.entries(["zhangsan", 14]); // [["name", "zhangsan"], ["age", 14]]
Object.fromEntries(["name", "zhangsan"], ["age", 14]); // ES10 的 api,Chrome 不支持,firebox 输出 { "name": "张三", "age": 14 }
(后续待整合之前写的一篇 array 博文)
JavaScript 高级程序设计----Array类型
至此,结束。