数组的高级用法

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、 数组交集

  1. Array.prototype.filter + includes判断
  2. 但是会存在性能和引用类型相同判断的问题
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);

打印结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值