JS
-
事件循环机制是什么?为什么这么设计
事件循环机制是js运行时处理异步任务的核心机制,它确保了异步任务能够以非阻塞的方式运行。整个事件循环机制可以看成由三部份组成:调用栈,Web Api, 任务队列。事件循环的工作就是当调用栈清空之后,从任务队列中不断取出回调函数推入调用栈执行。
任务队列又可以分为宏任务队列和微任务队列,常见的宏任务有setTimeout, setInterval, io, ui渲染操作,常见的微任务有promise的回掉.then, await 之后的代码,MutationObserver。完整的事件循环机制周期就是从宏任务队列里取一个宏任务,例如我们的脚本的同步代码,然后执行完成之后检查微任务队列并执行和清空,然后如果有需要则会渲染页面,然后开始下一个循环。
这其中有几个特殊的存在,requestIdleCallback,requestAnimationFrame,和UI渲染。UI渲染本身可以看作一个宏任务,但是它有自己的位置,通常在清空宏任务和微任务队列,下一个宏任务执行前。在ui渲染前,我们会执行requestAnimationFrame函数,而在这些执行完之后下一次循环开始前,浏览器会检查是否空闲来执行requestIdleCallback
为什么这么设计:js设计之处为了简化开发,避免多线程的资源竞争和死锁等问题设计成了单线程,但是单线程最大的缺点就是会阻塞
-
深拷贝
1
2
3
4
5
6
7
8
9
10const getType = (obj) => {
return Object.prototype.toString.call(obj)
}
const getInit = (target) => {
const c = target.constructor
return new c
}
const deepClone = (obj, map = new WeakMap()) => {
if (!isObject())
}- 不同的类型
- 循环引用 weakmap
- 继承:Object.create()但是要注意map/set
- 函数最好不处理,涉及curry function
-
继承
- 原型链继承(直接修改构造函数的prototype),作为原型的 Super 实例本身没有 constructor 属性,并不是它上面有个错误的属性才导致 Sub 的 constructor 错误的
1
2
3
4
5
6
7
8
9
10
11
12
13
14function Super (){
this.superValue = 1
}
Super.prototype.getSuperValue = function(){
console.log(this.superValue)
}
function Sub(){
this.subValue = 0
}
Sub.prototype = new Super()
// 手动修正构造函数指针
Sub.prototype.constructor = Sub
const instance = new Sub()
instance.getSuperValue() // 1- 借用构造函数继承, 无法继承父类原型上的属性或方法,父类的构造函数并不是被new调用而是被当作普通函数调用
1
2
3
4
5
6
7
8
9
10
11
12
13function Super (){
this.colors = ['red', 'blue', 'yellow']
}
Super.prototype.count = 1
function Sub(){
Super.call(this)
}
const instance1 = new Sub()
const instance2 = new Sub()
instance1.colors.push('black')
console.log(instance1.count) // undefined
console.log(instance1.colors) // ['red', 'blue', 'yellow','black']
console.log(instance2.colors) // ['red', 'blue', 'yellow']- 组合继承
1
// 结合上面两种 当时这样父类要被调用两次
- 原型式继承
1
2
3
4
5
6
7
8function object(obj){
function F(){}
F.prototype = obj;
return new F();
}
// 其实就是 Object.create 的简易实现,以现有对象为原型
Object.create会创建一个新的空对象让后将该对象的 __proto__指向传入的参数- 寄生继承
1
2
3
4
5
6
7
8function createAnother(original){
var clone = Object.create(original); // 通过调用 object() 函数创建一个新对象
clone.sayHi = function(){ // 以某种方式来增强对象
alert("hi");
};
return clone; // 返回这个对象
}
// 相当于在 clone 这个实例上增加属性和方法- 寄生组合继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22function SubType(name, age) {
SuperType.call(this, name)
this.age = age
}
SuperType.prototype.sayName = function(){
alert(this.name)
}
function SuperType(name) {
this.name = name
}
inheritPrototype(SubType, SuperType)
function inheritPrototype(subType, superType){
var prototype = Object.create(superType.prototype);
// prototype: { __proto__: { sayName } }
prototype.constructor = subType;
// prototype: { __proto__: { sayName }, constructor: subType }
subType.prototype = prototype;
}- class extends 关键字
1
super()
-
设计模式
-
策略模式。代替冗长的if-else,常见角色权限判断
-
发布订阅模式。
1
2
3
4
5
6
7
8
9
10
11class EventEmitter(){
this.events = {}
on(e, listener){}
emit(e, ...args){}
}
class Publisher() {
EventEmitter.trigger(e)
}
class Subscriber(){
EventEmitter.on(e, () => {})
}
-
-
观察者模式。
1
2
3
4
5
6
7
8
9class Observer() {
this.observerList = []
notify(){
this.observerList.forEach((i) => i.update())
}
}
class Subject() {
update(){}
} -
装饰器模式。增强
-
适配器模式
-
代理模式,vue proxy
-
责任链模式,分步表单,中间件,异常处理
-
工厂模式
-
单例模式
-
作用域
-
new 关键字
- 创建新的空对象
- 将空对象
__proto__
连接到构造函数prototype - 绑定this函数执行构造函数
- 返回新对象,除非构造函数显示返回了非原始值
-
箭头函数和 function的区别
- 箭头函数没有 this,内部的 this 指向外层作用域的this,不能作为构造函数,也不能bind。function的this是动态的
- 箭头函数没有arguments对象,访问参数用…rest;function有arguments对象
-
link标签的preload和prefetch的区别
- preload的资源优先级高,浏览器会立即下载,等待被使用
- prefetch是预先加载未来可能需要的资源,优先级低
-
装饰器是什么
- 装饰器本质是一个高阶函数,它接收一个函数/类作为参数,返回一个新的函数/类
- 多个装饰器是从下到上,从右到左执行
