假设下列数组
const arr = [1, [2, [3, [4, 5]]], 6];
// => [1, 2, 3, 4, 5, 6]
const res1 = arr.flat(Infinity);
const res2 = JSON.stringify(arr).replace(/\[|\]/g, '').split(',');
const res3 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']');
const flatten = arr => {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
}, []);
};
const res4 = flatten(arr);
const res5 = [];
const fn = arr => {
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
fn(arr[i]);
} else {
res5.push(arr[i]);
}
}
};
fn(arr);
const unique1 = arr => {
let len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
// 每删除一个树,j--保证j的值经过自加后不变。同时,len--,减少循环次数提升性能
len--;
j--;
}
}
}
return arr;
};
const unique2 = arr => {
const res = [];
for (let i = 0; i < arr.length; i++) {
if (res.indexOf(arr[i]) === -1) res.push(arr[i]);
}
return res;
};
const unique3 = arr => {
const res = [];
for (let i = 0; i < arr.length; i++) {
if (!res.includes(arr[i])) res.push(arr[i]);
}
return res;
};
const unique4 = arr => {
return arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
};
const unique5 = arr => {
const map = new Map();
const res = [];
for (let i = 0; i < arr.length; i++) {
if (!map.has(arr[i])) {
map.set(arr[i], true);
res.push(arr[i]);
}
}
return res;
};
const PENDING = 'PENDING'; // 进行中
const FULFILLED = 'FULFILLED'; // 已成功
const REJECTED = 'REJECTED'; // 已失败
class Promise {
constructor(exector) {
// 初始化状态
this.status = PENDING;
// 将成功、失败结果放在this上,便于then、catch访问
this.value = undefined;
this.reason = undefined;
// 成功态回调函数队列
this.onFulfilledCallbacks = [];
// 失败态回调函数队列
this.onRejectedCallbacks = [];
const resolve = value => {
// 只有进行中状态才能更改状态
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 成功态函数依次执行
this.onFulfilledCallbacks.forEach(fn => fn(this.value));
}
};
const reject = reason => {
// 只有进行中状态才能更改状态
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 失败态函数依次执行
this.onRejectedCallbacks.forEach(fn => fn(this.reason));
}
};
try {
// 立即执行executor
// 把内部的resolve和reject传入executor,用户可调用resolve和reject
exector(resolve, reject);
} catch (e) {
// executor执行出错,将错误内容reject抛出去
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected =
typeof onRejected === 'function'
? onRejected
: reason => {
throw new Error(reason instanceof Error ? reason.message : reason);
};
// 保存this
const self = this;
return new Promise((resolve, reject) => {
if (self.status === PENDING) {
self.onFulfilledCallbacks.push(() => {
// try捕获错误
try {
// 模拟微任务
setTimeout(() => {
const result = onFulfilled(self.value);
// 分两种情况:
// 1. 回调函数返回值是Promise,执行then操作
// 2. 如果不是Promise,调用新Promise的resolve函数
result instanceof Promise
? result.then(resolve, reject)
: resolve(result);
});
} catch (e) {
reject(e);
}
});
self.onRejectedCallbacks.push(() => {
// 以下同理
try {
setTimeout(() => {
const result = onRejected(self.reason);
// 不同点:此时是reject
result instanceof Promise
? result.then(resolve, reject)
: reject(result);
});
} catch (e) {
reject(e);
}
});
} else if (self.status === FULFILLED) {
try {
setTimeout(() => {
const result = onFulfilled(self.value);
result instanceof Promise
? result.then(resolve, reject)
: resolve(result);
});
} catch (e) {
reject(e);
}
} else if (self.status === REJECTED) {
try {
setTimeout(() => {
const result = onRejected(self.reason);
result instanceof Promise
? result.then(resolve, reject)
: reject(result);
});
} catch (e) {
reject(e);
}
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(value) {
if (value instanceof Promise) {
// 如果是Promise实例,直接返回
return value;
} else {
// 如果不是Promise实例,返回一个新的Promise对象,状态为FULFILLED
return new Promise((resolve, reject) => resolve(value));
}
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
}
window.addEventListener(
'scroll',
function () {
const clientHeight = document.documentElement.clientHeight;
const scrollTop = document.documentElement.scrollTop;
const scrollHeight = document.documentElement.scrollHeight;
if (clientHeight + scrollTop >= scrollHeight) {
// 检测到滚动至页面底部,进行后续操作
// ...
}
},
false
);
setTimeout(() => {
// 插入十万条数据
const total = 100000;
// 一次插入的数据
const once = 20;
// 插入数据需要的次数
const loopCount = Math.ceil(total / once);
let countOfRender = 0;
const ul = document.querySelector('ul');
// 添加数据的方法
function add() {
const fragment = document.createDocumentFragment();
for (let i = 0; i < once; i++) {
const li = document.createElement('li');
li.innerText = Math.floor(Math.random() * total);
fragment.appendChild(li);
}
ul.appendChild(fragment);
countOfRender += 1;
loop();
}
function loop() {
if (countOfRender < loopCount) {
window.requestAnimationFrame(add);
}
}
loop();
}, 0);
// vnode结构:
/* {
tag,
attrs,
children,
} */
//Virtual DOM => DOM
function render(vnode, container) {
container.appendChild(_render(vnode));
}
function _render(vnode) {
// 如果是数字类型转化为字符串
if (typeof vnode === 'number') {
vnode = String(vnode);
}
// 字符串类型直接就是文本节点
if (typeof vnode === 'string') {
return document.createTextNode(vnode);
}
// 普通DOM
const dom = document.createElement(vnode.tag);
if (vnode.attrs) {
// 遍历属性
Object.keys(vnode.attrs).forEach(key => {
const value = vnode.attrs[key];
dom.setAttribute(key, value);
});
}
// 子数组进行递归操作
vnode.children.forEach(child => render(child, dom));
return dom;
}
export function getFormData(object) {
const formData = new FormData();
Object.keys(object).forEach(key => {
const value = object[key];
if (Array.isArray(value)) {
value.forEach((subValue, i) => formData.append(key + `[${i}]`, subValue));
} else {
formData.append(key, object[key]);
}
});
return formData;
}
const copyTextToClipboard = async text => {
await navigator.clipboard.writeText(text);
};
const trueTypeOf = obj => {
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
};
// string
// console.log(trueTypeOf(''));
// number
// console.log(trueTypeOf(0));
// undefined
// console.log(trueTypeOf());
// null
// console.log(trueTypeOf(null));
// object
// console.log(trueTypeOf({}));
// array
// console.log(trueTypeOf([]))
// function
// console.log(trueTypeOf(() => {}))
// 是否Promise对象
export const isPromise = o => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Promise';
};
const truncateStringMiddle = (string, length, start, end) => {
return `${string.slice(0, start)}...${string.slice(string.length - end)}`;
};
// console.log(
// truncateStringMiddle(
// 'Alongstorygoes here but then eventually ends!', // string
// 25, // 需要的字符串大小
// 1, // 从原始字符串第几位开始截取
// 17, // 从原始字符串第几位停止截取
// ),
// )
export const isEmail = s => {
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(
s
);
};
export const isPhone = s => {
return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s);
};
export const isURL = s => {
return /^http[s]?:\/\/.*/.test(s);
};
const html = document.querySelector('html');
html.oncopy = () => false;
html.onpaste = () => false;
const fade = (el, type = 'in') {
el.style.opacity = (type === 'in' ? 0 : 1)
let last = +new Date()
const tick = () => {
const opacityValue = (type === 'in'
? (new Date() - last) / 400
: -(new Date() - last) / 400)
el.style.opacity = +el.style.opacity + opacityValue
last = +new Date()
if (type === 'in'
? (+el.style.opacity < 1)
: (+el.style.opacity > 0)) {
requestAnimationFrame(tick)
}
}
tick()
}
const dataType = obj =>
Object.prototype.toString
.call(obj)
.replace(/^\[object (.+)\]$/, '$1')
.toLowerCase();
const getOffset = el => {
const { top, left } = el.getBoundingClientRect();
const { scrollTop, scrollLeft } = document.body;
return {
top: top + scrollTop,
left: left + scrollLeft
};
};
previousSibling 返回列表项的 (前一个同胞节点)
const getIndex = el => {
if (!el) {
return -1;
}
let index = 0;
do {
index++;
} while ((el = el.previousElementSibling));
return index;
};
function convert(list) {
const res = [];
const map = list.reduce((a, v) => {
a[v.id] = v;
return a;
}, {});
console.log('map', map);
for (const item of list) {
if (item.parentId === 0) {
res.push(item);
continue;
}
if (item.parentId in map) {
const parent = map[item.parentId];
parent.children = parent.children || [];
parent.children.push(item);
}
}
return res;
}
let list = [
{ id: 1, name: '部门A', parentId: 0 },
{ id: 2, name: '部门B', parentId: 0 },
{ id: 3, name: '部门C', parentId: 1 },
{ id: 4, name: '部门D', parentId: 1 },
{ id: 5, name: '部门E', parentId: 2 },
{ id: 6, name: '部门F', parentId: 3 },
{ id: 7, name: '部门G', parentId: 2 },
{ id: 8, name: '部门H', parentId: 4 }
];
console.log(convert(list));