跳到主要内容

数组实践与手写

如何给数组去重?​

[...new Set(arr)]; // 利用 Set 唯一性
Array.from(new Set(arr));

for (const item of arr) {
if (!newArr.includes(item)) newArr.push(item);
}

arr.filter((item, index) => arr.indexOf(item, 0) === index); // 保留首次出现

常用数组方法如何手写实现?​

Array.prototype.myMap = function (callback) {
const result = [];
for (let i = 0; i < this.length; i++) result.push(callback(this[i], i, this));
return result;
};

Array.prototype.myFilter = function (callback) {
const result = [];
for (let i = 0; i < this.length; i++) if (callback(this[i], i, this)) result.push(this[i]);
return result;
};

Array.prototype.myReduce = function (callback, initialValue) {
let accumulator = initialValue;
for (let i = 0; i < this.length; i++) {
accumulator = accumulator === undefined ? this[i] : callback(accumulator, this[i], i, this);
}
return accumulator;
};

Array.prototype.myFlat = function (depth = 1) {
const result = [];
const flatten = (arr, d) => {
arr.forEach((item) => {
if (Array.isArray(item) && d > 0) flatten(item, d - 1);
else result.push(item);
});
};
flatten(this, depth);
return result;
};
  • forEach、some、every、find 的手写只需替换终止条件: some 命中返回 true, every 失败返回 false, find 命中返回元素, 否则返回 undefined;

forEach 为什么不能跳出循环?​

  • 原因: forEach 回调构成函数作用域, 回调内 return 只结束本次回调, 不会结束遍历;
  • 替代: 需要提前结束时用 some 或 every, 或改用 for...of;
arr.forEach((item) => {
if (item > 2) return; // 只跳过本次, 循环继续
});

arr.some((item) => item > 2); // 遇到即返回 true 并停止
arr.every((item) => item <= 2); // 出现不满足即返回 false 并停止

如何把树与扁平数组互相转换?​

// 树 → 扁平数组
const flattenTree = (tree) => {
if (!tree.children?.length) return [tree];
let res = [tree];
for (const child of tree.children) res = res.concat(flattenTree(child));
delete tree.children;
return res;
};

// 扁平数组 → 树
const buildTree = (array, parentId = null) =>
array.reduce((tree, cur) => {
if (cur.parentId === parentId) {
const children = buildTree(array, cur.id);
if (children.length > 0) cur.children = children;
tree.push(cur);
}
return tree;
}, []);