其它
fetch promise all
let id = 1990000,
urls = [],
audios = [];
for (let i = 0; i < 500; i++) {
id++;
let url = `url${id}`;
urls.push(url);
}
Promise.all(
urls.map((request) => {
return fetch(request)
.then((response) => {
return response.json();
})
.then((data) => {
return data;
});
})
)
.then((values) => {
for (let val of values) {
let data = val.data;
let songs = data.songs;
if (songs && songs.length) {
console.log(songs);
for (let item of songs) {
audios.push(item.store_path);
}
}
}
for (let item of audios) {
let audio = document.createElement("audio");
audio.src = item;
audio.controls = true
audio.width = '400px'
audio.height = '100px'
document.body.append(audio);
}
})
.catch(console.error.bind(console));
拷贝
- 深拷贝:完全拷贝,互不影响,JSON.stringfy(obj)
- 浅拷贝:拷贝的是引用地址,
for in
,Object.assing({},obj)
,{...obj}
实现一个深拷贝
基本版本
function myDeepclone(target = {}){
if(target === null || typeof target !== 'object'){
return target
}
let res = target instanceof Array ? [] : {}
for(let key in target){
if(target.hasOwnProperty(key)){
res[key] = myDeepclone(target[key])
}
}
return res
}
// test case
let obj = {
age: 1,
getAge: function(){
return this.age
},
pros: {
num: {
max:1
}
}
}
let arr = [1, 'name', function name(){}, {age: 1}]
myDeepclone(obj)
myDeepclone(arr)
进阶版本
function cloneDeep(obj, map = new WeakMap()) {
if (!(obj instanceof Object)) return obj; // 基本数据
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
if (map.get(obj)) return map.get(obj); // 解决循环引用
if (obj instanceof Function) { // 解决函数
return function () {
return obj.apply(this, [...arguments]);
};
}
const res = new obj.constructor(); // 下面是数组/普通对象/Set/Map 的处理
obj instanceof Object && map.set(obj, res);
if (obj instanceof Map) {
obj.forEach((item, index) => {
res.set(cloneDeep(index, map), cloneDeep(item, map));
});
}
if (obj instanceof Set) {
obj.forEach((item) => {
res.add(cloneDeep(item, map));
});
}
Object.keys(obj).forEach((key) => {
if (obj[key] instanceof Object) {
res[key] = cloneDeep(obj[key], map);
} else {
res[key] = obj[key];
}
});
return res;
}
function deepclone(obj, map = new WeakMap()){
// basic data
if(! (obj instanceof Object)) return obj
// date
if(obj instanceof Date) return new Date(obj)
// reg
if(obj instanceof RegExp) return new RegExp(obj.source, obj.flags)
// cache
if(map.get(obj)) return map.get(obj)
// function
if(obj instanceof Function){
return function(){
return obj.apply(this, [...arguments])
}
}
// constructor
const results = new obj.constructor()
console.log(results)
if(obj instanceof Object) {
map.set(obj, results)
}
// Map
if(obj instanceof Map){
obj.forEach((item, index) => {
map.set(deepclone(index, map), deepclone(item, map))
})
}
// Set
if(obj instanceof Set){
obj.forEach((item) => {
map.add(deepclone(item,map))
})
}
// all
Object.keys(obj).forEach((key) => {
if(obj[key] instanceof Object){
results[key] = deepclone(obj[key], map)
} else {
results[key] = obj[key]
}
})
return results
}
// test case
const map = new Map();
map.set({ a: 1 }, "1");
const source = {
name: "Jack",
meta: {
age: 12,
birth: new Date("1997-10-10"),
ary: [1, 2, { a: 1 }],
say() {
console.log("Hello");
},
map
},
};
source.source = source;
const newObj = cloneDeep(source);
console.log(newObj.meta.ary[2] === source.meta.ary[2]); // false
console.log(newObj.meta.birth === source.meta.birth); // false
console.log(newObj);
::: 注意 JSON.stringfy(obj)
的不足
- obj 里有 date 对象无法被序列化和反序列化,而是转为 date 字符串
- obj 里有 RegExp 对象,Error 对象序列化结果是空对象
- obj 里有 function,undefined 会被丢失
- obj 里有 NaN,Infinity,-Infinity 序列化结果会变成 null
promise
实现一个 delay 函数
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
async function test() {
console.log('start timer');
await delay(1000);
console.log('after 1 second');
}
test();
函数
箭头函数的难点
- 函数体内的 this 是定义时所在的对象决定的
- 不可当作构造函数,因此箭头函数不可使用 new 命令
- 不可使用 yield 命令,因此箭头函数不能用作 Generator 函数
- 不可使用 Arguments 对象,此对象在函数体内不存在 (可以使用...args)
- 返回对象时必须在对象外面加上括号
去重字符串:[...new Set(str)].join("")
去重数组:[...new Set(arr)]或Array.from(new Set(arr))
集合数组
声明:const a = new Set(arr1)、const b = new Set(arr2)
并集:new Set([...a, ...b])
交集:new Set([...a].filter(v => b.has(v)))
差集:new Set([...a].filter(v => !b.has(v)))
数组降维
function flat(arr){
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flat(cur) : cur)
},[])
}
// test case
let arr = [1,2,[1,2,3,[1,2,3,4,45]]]
flat(arr) // [1, 2, 1, 2, 3, 1, 2, 3, 4, 45]
定时器场景
写一个 mySetInterVal(fn, a, b)
,每次间隔 a,a+b,a+2b
的时间,然后写一个 myClear
,停止上面的 mySetInterVal
function mySetInterVal(fn,a,b){
this.a = a
this.b = b
this.time = 0
this.handle = -1
this.start = () => {
this.handle = setTimeout(() => {
fn()
this.time++
this.start()
console.log( this.a + this.time * this.b);
}, this.a + this.b * this.time)
}
this.stop = () => {
clearTimeout(this.handle)
this.time = 0
}
}
// test case
let a = new mySetInterVal(() => {console.log('123')},1000, 2000 );
a.start();
a.stop();
数组转为树
let list = [
{ id: 1, name: '部门A', 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 }
];
function convert(list){
let map = list.reduce((pre, cur) => {
pre[cur.id] = cur
return pre
},[])
let results = []
for(let key in map){
let ele = map[key]
if(ele.parentId === 0) {
results.push(ele)
} else {
let parent = map[ele.parentId]
if(parent) {
parent.children = parent.children ?? []
parent.children.push(ele)
}
}
}
return results
}
console.log(convert(list))
const input = [
{
value: 110000,
label: '北京市',
parent: null,
children: [
110001,
110002
]
},
{
value: 110001,
label: '东城区',
parent: 110000,
children: []
},
{
value: 110002,
label: '西城区',
parent: 110000,
children: []
},
{
value: 130000,
label: '河北省',
parent: null,
children: [
130100
]
},
{
value: 130100,
label: '石家庄市',
parent: 130000,
children: [
130102,
130104
]
},
{
value: 130102,
label: '长安区',
parent: 130100,
children: []
},
{
value: 130104,
label: '桥西区',
parent: 130100,
children: []
},
];
const output = [
{
value: 110000,
label: '北京市',
parent: null,
children: [
{
value: 110001,
label: '东城区',
parent: 110000,
children: []
},
{
value: 110002,
label: '西城区',
parent: 110000,
children: []
}
]
},
{
value: 130000,
label: '河北省',
parent: null,
children: [
{
value: 130100,
label: '石家庄市',
parent: 130000,
children: [
{
value: 130102,
label: '长安区',
parent: 130100,
children: []
},
{
value: 130104,
label: '桥西区',
parent: 130100,
children: []
}
]
},
]
},
];
function createTree(input) {
input.forEach(item => {
item.children = item.children.length ? [] : item.children
})
let maps = input.reduce((pre, cur) => {
pre[cur.value] = cur
return pre
},[])
let results = []
for(let key in maps){
let ele = maps[key]
if(ele.parent === null){
results.push(ele)
} else {
let parent = maps[ele.parent]
if(parent){
parent.children.push(ele)
}
}
}
return maps
}
输出一个随机的 16 进制颜色
let color = '#'+ Math.random().toString(16).substr(-6);
document.body.style.backgroundColor = color;
trim
Function.prototype.trim = function(){
return this.replace(/^\s+/,'').replace(/\s+$/,'')
}
随机
let a = []
for(let i=0;i<100;i++){
a[i] = i+1
}
a.sort(()=>0.5-Math.random())
console.log(a)
字符串排序
let s = "kadfjkajfkhgofqnmvc";
console.log(Array.from(s).sort().join(""))
随机字符串
function randomString(length) {
let str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
let result = '';
for (let i = length; i > 0; --i)
result += str[Math.floor(Math.random() * str.length)];
return result;
}
在页面插入 10000 个元素,如何进行优化
let container = document.getElementById('container')
let fragment = document.createDocumentFragment()
for(let i = 0; i < 10000; i++){
let li = document.createElement('li')
li.innerHTML = 'hello world'
// 所有构造的节点加入文档片段
fragment.appendChild(li)
}
// 节点构造完成,将文档对象添加到页面中
container.appendChild(fragment);
Object.is 和 === 的区别
Object 在严格等于的基础上修复了一些特殊情况下的失误,具体来说就是 +0 和 -0,NaN 和 NaN。
function is(x, y) {
if (x === y) {
//运行到1/x === 1/y的时候x和y都为0,但是1/+0 = +Infinity, 1/-0 = -Infinity, 是不一样的
return x !== 0 || y !== 0 || 1 / x === 1 / y;
} else {
//NaN===NaN是false,这是不对的,我们在这里做一个拦截,x !== x,那么一定是 NaN, y 同理
//两个都是NaN的时候返回true
return x !== x && y !== y;
}