1、万能数据生成器
const createValues = (creator, length = 10) => Array.from({length}, creator);
// 第一个参数控制随机数生成,第二个控制其数组长度
const createRandomValues = (len) => createValues(Math.random, len);
const values = createRandomValues();
console.log("values:", values.length, values);
// values: 10 (10) [0.06099062572439662, 0.7260316482664231, 0.8672116288251952, 0.5869499378000791, 0.3746038785427792, 0.7537553353798436, 0.13597413798455427, 0.7244819827882962, 0.0935049710518081, 0.7651495251208631]
2、序列生成器
const createValues = (creator, length = 10) => Array.from({length}, creator);
const createRange = (start, stop, step) => createValues((_, i) => start + i * step, (stop - start)/step + 1);
// 生成数组,里面元素是 1 ~ 100 以内每次从 1 开始每次递增 3 的数字
const values = createRange(1, 100, 3);
console.log("values:", values);
// (34) [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61, 64, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97, 100]
3、数据生成器
const createValues = (creator, length = 10) => Array.from({length}, creator);
function createUser(v, index) {
return {
name: `user-${index}`,
age: (Math.random() * 100) >> 0, // 取整
}
}
const users = createValues(createUser, 100);
console.log("users:", users);
4、清空数组
const arr = [1, 2, 3];
arr.splice(0);
console.log("splice:", arr); // []
const arr1 = [1, 2, 3];
arr1.length = 0;
console.log("length:", arr1); // []
5、数组去重
const arr = [
"apple",
"banana",
1,
1,
3,
3,
undefined,
undefined,
,
,
NaN,
NaN,
null,
null,
"true",
true,
{ a: 1 },
];
const arr1 = Array.from(new Set(arr)); // 正常去重
console.log("set:", arr1);
对于数组里面对象去重
function uniqueArray(arr) {
return Array.from(new Set(arr));
}
const arr = [{ a: 1 }, { a: 1 }];
console.log("set 不同引用:", uniqueArray(arr)); // [{ a: 1 }, { a: 1 }]
const obj1 = { a: 1 };
const arr2 = [obj1, obj1];
console.log("set 同一引用:", uniqueArray(arr2)); // [{ a: 1 }]
如果我们想认为两个对象里面的 a 属性的值相同就认为是同一数据的话,可以使用 filter
function uniqueArray(arr = [], key) {
const keyValues = new Set();
return arr.filter((item) => {
if (!keyValues.has(item[key]) {
keyValues.add(item[key]);
return true;
}
return false;
})
}
const arr = [{ a: 1 }, { a: 1 }, { a: 2 }];
console.log("filter 去重:", uniqueArray(arr, "a")); // filter 去重: [ { a: 1 }, { a: 2 } ]
6、 数组交集
- Array.prototype.filter + includes判断
- 但是会存在性能和引用类型相同判断的问题
const arr1 = [0, 1, 2];
const arr2 = [3, 2, 0];
function intersectSet(arr1, arr2) {
return arr1.filter((item) => arr2.includes(item));
}
const values = intersectSet(arr1, arr2);
console.log(values); // [ 0, 2 ]
可以修改成下面这种处理方式
// 引用类型
function intersect(arr1, arr2, key) {
const map = new Map();
arr1.forEach((val) => map.set(val[key]));
return arr2.filter((val) => map.has(val[key]));
}
const arr1 = [{ p: 0 }, { p: 1 }, { p: 2 }];
const arr2 = [{ p: 3 }, { p: 2 }, { p: 1 }];
const result = intersect(arr1, arr2, "p");
console.log("result:", result); // result: [ { p: 2 }, { p: 1 } ]
function intersectBase(arr1, arr2) {
const map = new Map();
arr1.forEach((val) => map.set(val));
return arr2.filter((val) => map.has(val));
}
const arr3 = [0, 1, 2];
const arr4 = [3, 2, 0];
const result1 = intersectBase(arr3, arr4);
console.log("result1:", result1); // result1: [ 2, 0 ]
7、数组差集
// 引用类型
function difference(arr1, arr2, key) {
const map = new Map();
arr1.forEach((val) => map.set(val[key]));
return arr2.filter((val) => !map.has(val[key]));
}
// 原始数据类型
function differenceBase(arr1, arr2) {
const map = new Map();
arr1.forEach((val) => map.set(val));
return arr2.filter((val) => !map.has(val));
}
const arr1 = [{ p: 0 }, { p: 1 }, { p: 2 }];
const arr2 = [{ p: 3 }, { p: 2 }, { p: 1 }];
const result = difference(arr1, arr2, "p");
console.log("result1:", result); // result1: [ { p: 3 } ]
const arr3 = [0, 1, 2];
const arr4 = [3, 2, 0];
const result1 = differenceBase(arr3, arr4);
console.log("result2:", result1); // result2: [ 3 ]
8、数组删除虚(假)值
const array = [false, 0, undefined, , "", NaN, 9, true, undefined, null, "test"];
const newArray = array.filter(Boolean);
console.log(newArray); // [ 9, true, 'test' ]
9、获取数组中最大值和最小值
const numArray = [1, 3, 8, 666, 22, 9982, 11, 0];
const max = Math.max.apply(Math, numArray);
const min = Math.min.apply(Math, numArray);
console.log("max:", max + ",min:" + min); // max: 9982,min:0
// 或者
console.log(Math.max(...numArray)); // 9982
console.log(Math.min(...numArray)); // 0
来看一个实际的例子,我们去获取用户对象中最大和最小的年龄:
const createValues = (creator, length = 10) => Array.from({ length }, creator);
function createUser(v, index) {
return {
name: `user-${index}`,
age: (Math.random() * 100) >> 0,
};
}
const users = createValues(createUser, 10);
const ages = users.map((u) => u.age);
const max = Math.max(...ages);
const min = Math.min(...ages);
console.log(ages);
console.log("max:", max + ",min:" + min);
// (10) [40, 90, 39, 8, 59, 52, 45, 94, 8, 5]
// max: 94,min:5
reduce高级用法
querystring
- 作用∶页面传递参数
- 规律∶地址url问号(?)拼接的键值对
const urlObj = location.search
.slice(1)
.split("&")
.filter(Boolean)
.reduce((obj, cur) => {
const arr = cur.split("=");
if (arr.length != 2) {
return obj;
}
obj[decodeURIComponent(arr[0])] = decodeURIComponent(arr[1]);
return obj;
}, {});
function getQueryString(key) {
return urlObj[key];
}
console.log("words:", getQueryString("words"));
console.log("wordss:", getQueryString("wordss"));
折上折
- 优惠1:9折
- 优惠2:200减50
function compose(...funcs) {
if (funcs.length === 0) {
return (arg) => arg;
}
return funcs.reduce(
(a, b) =>
(...args) =>
a(b(...args))
);
}
function discount(x) {
console.log("discount");
return x * 0.9;
}
function reduce(x) {
console.log("reduce");
return x > 200 ? x - 50 : x;
}
function discountPlus(x) {
console.log("discountPlus");
return x * 0.95;
}
// 从后往前执行传入的函数
const getPrice = compose(discountPlus, reduce, discount);
const print = console.log;
print(getPrice(200));
print(getPrice(250));
promise顺序执行
function runPromises(promiseCreators, initData) {
return promiseCreators.reduce(function (promise, next) {
return promise.then((data) => next(data));
}, Promise.resolve(initData));
}
function login(data) {
console.log("login: data", data);
return new Promise((resolve) => {
setTimeout(() => {
return resolve({
token: "token",
});
}, 500);
});
}
function getUserInfo(data) {
console.log("getUserInfo: data", data);
return new Promise((resolve) => {
setTimeout(() => {
return resolve({
name: "user-1",
id: 988,
});
}, 300);
});
}
function getOrders(data) {
console.log("getOrders: data", data);
return new Promise((resolve) => {
setTimeout(() => {
return resolve([
{
orderId: 1,
productId: 100,
price: 100,
},
]);
}, 100);
});
}
const initData = { name: "name", pwd: "pwd" };
Promise.resolve(initData)
.then((data) => login(data))
.then((data) => getUserInfo(data))
.then((data) => getOrders(data))
.then((data) => console.log("orders", data));
// 使用 reduce 封装的 runPromises 方法,确保返回 Promise 且执行结果是下一个函数的入参
runPromises([login, getUserInfo, getOrders], initData).then((res) => {
console.log("res", res);
});
数组分组
const hasOwn = Object.prototype.hasOwnProperty;
function group(arr, fn) {
// 不是数组
if (!Array.isArray(arr)) {
return arr;
}
// 不是函数
if (typeof fn !== "function") {
throw new TypeError("fn必须是一个函数");
}
let v;
return arr.reduce((obj, cur, index) => {
v = fn(cur, index);
if (!hasOwn.call(obj, v)) {
obj[v] = [];
}
obj[v].push(cur);
return obj;
}, {});
}
// 按照长度分组
let result = group(["apple", "pear", "orange", "peach"], (v) => v.length);
console.log(result);
// 按照份数分组
result = group(
[
{
name: "tom",
score: 60,
},
{
name: "Jim",
score: 40,
},
{
name: "Nick",
score: 88,
},
],
(v) => v.score >= 60
);
console.log(result);
打印结果如下: