- 深拷贝
// 小细节 -> 需要考虑一下循环引用的情况 -> WeakMap
function deepCopy(obj){
let result;
if(typeof obj == "object"){
//复杂数据类型
result = obj.constructor == Array ? [] : {};
for(let i in obj){
result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
}
}else {
result = obj;
}
return result;
}
function deepCopy2(target, weakMaps = new WeakMap()) {
if (typeof target !== "object" || target === null) {
return target;
}
if (weakMaps.has(target)) return weakMaps.get(target);
const res = Array.isArray(target) ? [] : {};
weakMaps.set(target, res);
for (let key in target) {
res[key] = deepCopy(target[key], weakMaps);
}
return res;
}
21.浏览器进程与线程
https://imweb.io/topic/58e3bfa845e5c13468f567d5
22.设计一个简单的任务队列,要求分别在 1,3,4 秒后打印出”1“,”2“,”3“
/**
* 题目
*/
new Quene()
.task(1000, () => {
console.log(1);
})
.task(2000, () => {
console.log(2);
})
.task(1000, () => {
console.log(3);
})
.start();
function Quene() { ... }
/**
* 解题1 promise
*/
class Quene {
constructor() {
this.tasks = [];
}
task(wait, fn) {
this.tasks.push({
wait,
fn,
});
return this;
}
async start() {
for (let task of this.tasks) {
const { wait, fn } = task;
await new Promise((res, rej) => {
setTimeout(() => {
fn();
res();
}, wait);
});
}
}
}
/**
* 解题2 递归
*/
class Quene {
constructor() {
this.tasks = [];
}
task(wait, fn) {
this.tasks.push({ wait, fn });
return this;
}
start() {
const firstTask = this.tasks.shift();
if (firstTask) {
setTimeout(() => {
firstTask.fn();
this.start();
}, firstTask.wait);
}
}
}
/**
* 解题3 闭包
*/
class Queue {
constructor() {
this.tasks = [];
}
task(wait, fn) {
this.tasks.push({
wait,
fn,
});
return this;
}
start() {
let int = 0;
this.tasks.forEach(({ wait, fn }) => {
setTimeout(() => {
fn();
}, (int += wait));
});
}
}
- 用 setTimeout 实现 setInterval,阐述实现的效果与 setInterval 的差异
function mySetInterval(fn, wait) {
mySetInterval.timer = setTimeout(() => {
fn();
mySetInterval(fn, wait);
}, wait)
}
mySetInterval.clear = function() {
clearTimeout(mySetInterval.timer)
}
mySetInterval(() => {
console.log(11111)
}, 1000)
setTimeout(() => {
// 5s 后清理
mySetInterval.clear()
}, 5000)
- vue3 中的数据侦测
const rawToReactive = new WeakMap();
const reactiveToRaw = new WeakMap();
/**
* utils
* */
function isObject(val) {
return typeof val === "object";
}
function hasOwn(val, key) {
const hasOwnProperty = Object.prototype.hasOwnProperty;
return hasOwnProperty.call(val, key);
}
/**
* traps
* */
// get
function createGetter() {
return function(target,key,receiver) {
const res = Reflect.get(target,key,receiver);
console.log('get', key);
return isObject(res) ? reactive(res) : res;
}
}
// set
function set(target,key,value,receiver) {
const hadKey = hasOwn(target, key);
const oldValue = target[key];
value = reactiveToRaw.get(value) || value;
const res = Reflect.set(target, key, value, receiver)
if(!hadKey || value !== oldValue) {
console.log('tigger...');
}
return res;
}
// handle
const mutableHandlers = {
get: createGetter(),
set: set
};
// create reactive object
function createReactiveObject(target, toProxy, toRaw, baseHandlers) {
let observed = toProxy.get(target);
// target 生成过 observed,返回 observed
if(observed !== void 0) {
return observed;
};
// target 是 observed, 返回 target
if(toRaw.has(target)) {
return target;
}
observed = new Proxy(target, baseHandlers);
toProxy.set(target, observed);
toRaw.set(observed, target);
return observed;
}
// enter
function reactive(target) {
return createReactiveObject(target, rawToReactive, reactiveToRaw, mutableHandlers)
}
- Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?
优缺点
- Object.defineProperty 无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
- Object.defineProperty 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy 可以劫持整个对象,并返回一个新的对象。
- Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
- 实现 async await
function co(genFun) {
return new Promise((resolve, reject) => {
const gen = genFun();
function next(...params){
const {value, done} = gen.next(...params);
if(done){
return resolve(value)
} else {
value.then((...args)=>next(...args));
}
};
next();
})
};
// test
const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000));
function* testG() {
// await被编译成了yield
const data = yield getData()
console.log('data: ', data);
const data2 = yield getData()
console.log('data2: ', data2);
return 'success'
}
co(testG).then(res=>{console.log('res', res)});
// logs
data: data
data2: data
res success
- LazyMan
// 实现LazyMan
LazyMan('jack').sleep(3000).eat('篮球').eat('rap').eat('唱、跳')
// hi,I'm jack
// 阻塞3s
// 篮球
// rap
// 唱、跳
LazyMan('x1').eat('高').sleep(5000).eat('富').eat('帅')
// hi,I'm x1
// 高
// 阻塞5s
// 富
// 帅
LazyMan('lurenjia').sleepFirst(3000).eat('吹').eat('牛')
// 阻塞3s
// hi,I'm lurenjia
// 吹
// 牛
class CraeteLazyMan {
constructor(name) {
this.queue = [];
const nameTask = () => {
console.log(`ADI-LOG => name`, name);
this.task();
};
this.queue.push(nameTask);
setTimeout(() => {
this.task();
}, 0);
}
task() {
const fun = this.queue.shift();
fun && fun();
}
sleep(time) {
const _task = () => {
setTimeout(() => {
this.task();
}, time);
};
this.queue.push(_task);
return this;
}
sleepFirst(time) {
const _task = () => {
setTimeout(() => {
this.task();
}, time);
};
this.queue.unshift(_task);
return this;
}
eat(str) {
const _task = () => {
console.log(`ADI-LOG => eat`, str);
this.task();
};
this.queue.push(_task);
return this;
}
}
function LazyMan(name = "") {
return new CraeteLazyMan(name);
}
- JS实现一个带并发控制的异步调度器,保证同时运动的任务最多有两个,完善下面代码
// https://github.com/Yuanyuanyuanc/aYuan-learning-notes/issues/2
class Scheduler {
constructor(limt = 2) {
this.limt = limt;
this.queue = [];
this.count = 0;
}
add(promiseCreator) {
let resolve;
const p = new Promise((res) => {
resolve = res;
});
this.queue.push(() => promiseCreator().then(resolve));
this.run();
return p;
}
run() {
if (this.count < this.limt && this.queue.length) {
this.count++;
const f = this.queue.shift();
f().then(() => {
this.count--;
this.run();
});
}
}
}
var timeout = (time) =>
new Promise((resolve) =>
setTimeout(() => {
resolve();
console.log(`ADI-LOG => time`, time);
}, time)
);
var scheduler = new Scheduler();
var addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => console.log(order));
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
// 2314
addTask(0, 1);
addTask(2000, 2);
addTask(0, 3);
addTask(3000, 4);
addTask(0, 5);
// 13254