执行上下文
执行上下文就是js运行的抽象环境。分为:
全局执行上下文,函数执行上下文,和eval执行上下文。
js执行分为两个阶段,创建阶段和执行阶段
创建阶段:
1. 创建全局上下文,压入执行栈,this指向的是window
2. 全局声明的变量会是undefined,函数也是被暂存在一边没有被执行执行阶段
3. 提升变量和函数声明,函数声明置顶比变量声明置顶更优先
执行阶段:
1. 当执行函数的时候就会生成函数上下文,并压入执行栈,this指向被调用的方式,创建并初始化arguments对象
2. 每个函数执行完成就移出执行栈,遵循后进先出
作用域链
当查找变量时,会在离自己最近的地方向外层寻找值,直到找到值。
父对象的所有变量,对子对象都是可见的,反之则不成立。
离自己最近的地寻找,这是因为js采用的是静态作用域,函数创建的时候就会保存父级变量到自己的上下文中
隐式转换
隐式转换中主要涉及到三种转换:
1、将值转为原始值,ToPrimitive()。
2、将值转为数字,ToNumber()。
3、将值转为字符串,ToString()。
属性:调用顺序为: valueOf >>> toString
闭包
闭包就是可以访问作用域外的内部函数,即使外部函数已经被销毁
理论上所有的js函数都是闭包,因为在window内
闭包的作用
能够访问函数定义时所在的词法作用域(阻止其被回收)。
私有化变量
this指向
在全局上下文中,this指向window,严格模式下是undefined
在函数上下文中取决于被调用的方式
直接调用:window
bind,call,apply:指向第一个参数
New :指向构造的对象
作为对象的一个方法:指向当前类
箭头函数指向最近的外层
实现bind new apply call
//new 实现
funtion _new(){
let target = {} // 创建一个新对象
let [constructor, ...args] = [...arguments] //获取参数
target.__proto__= constructor.prototype //原型连接
let result = constructor.apply(target,args) //执行构造函数,将剩余参数都添加到空对象上
if(result && (typef(result)==='object' || typef(result)==='function')){
return result
} //如果执行结果是对象就返回这个对象
return target
}
原型,原型链
原型就是所有对象(除了null)都会在创建的时候就会与之关联的另一个对象
函数对象都有prototype属性,protoype指向了调用该构造函数而创建的实例的原型
所有对象(除了null)__proto__属性,指向对象的原型,
每个原型都有一个 constructor 属性指向关联的构造函数。
原型是指为其它对象提供共享属性访问的对象。在创建对象时,每个对象都指向它的原型对象或者 null。
通过__proto__组成的相互关联的链状结构就是原型链,当查询一个属性或者方法是实际是向上查询整个原型链上的属性或者方法。
原型继承
有两种方式。一种是通过 Object.create 或者 Object.setPrototypeOf 显式继承另一个对象,将它设置为原型。
另一种是通过 constructor 构造函数,在使用 new 关键字实例化时,会自动继承 constructor 的 prototype 对象,作为实例的原型。
在 ES2015 中提供了 class 的风格,背后跟 constructor 工作方式一样,写起来更内聚一些。
js继承的几种方式
1.
Promise
(1) promise 对象初始化状态为 pending。
(2) 当调用resolve(成功),会由pending => fulfilled。
(3) 当调用reject(失败),会由pending => rejected。
promise解决的是回调过多过少或者回调时间错误的问题
实现Promise,promise.all, promise.race, async await实现
//promise.all 一个失败,则返回第一个失败的返回结果
事件冒泡 事件捕获 事件委托
事件捕获是从目标元素到外层元素的过程
事件冒泡是从外层元素到目标元素的过程
事件委托就是利用了事件冒泡或者事件捕获来优化事件
事件循环/event loop
js会在主执行栈上同步执行代码,遇到异步代码,则将异步代码推入事件队列中,
js主执行栈执行完毕后,访问事件队列队首,注意,事件队列又分为了宏任务和微任务,
macro-task包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver。
微任务在本次循环中总是优先于宏任务执行,执行完微任务后执行宏任务,执行完毕后再次访问事件队列,如此反复
setTimeout(() => {
console.log(1)
}, 0);
new Promise((resolve,rej)=>{
console.log(2)
resolve()
console.log(3)
}).then(()=>{
console.log(4)
setTimeout(() => {
console.log(10)
}, 0);
}).then(()=>{
console.log(5)
})
new Promise((resolve,rej)=>{
console.log(6)
resolve()
}).then(()=>{
console.log(7)
}).then(()=>{
console.log(8)
}).then(()=>{
console.log(9)
setTimeout(() => {
console.log(11)
new Promise((resolve,rej)=>{
resolve()
}).then(()=>{
console.log(12)
})
}, 0);
})
//结果:2,3,6,4,7,5,8,13,9,1,10,11,12
函数式编程
serviceworker/ pwa
webworker
其他JS基础
排序
数组扁平化
数组去重
深拷贝实现
-
JSON.stringify/parse的方法,
undefined、function、symbol会在转换过程中被忽略 -
function deepclone(source){ const targetObj = Arrary.isArrary(source) ? [] : {} //判断拷贝的数组还是对象 for(let key in source){ if(source.hasOwnProperty(key)){ if(source[key] && typeof(source[key])==='object'){ targetObj[key] = Arrary.isArrary(targetObj[key]) ? [] : {} targetObj[key] = deepClone(source[key]); }else{ targetObj[key] = source[key] } } } }
CSS
BFC
Box 是 CSS 布局的对象和基本单位,页面是由若干个Box组成的。
元素的类型 和 display 属性,决定了这个 Box 的类型。不同类型的 Box 会参与不同的 Formatting Context。
Formatting Context Formatting Context 是页面的一块渲染区域,并且有一套渲染规则,决定了其子元素将如何定位,以及和其它元素的关系和相互作用。
BFC布局规则
BFC内,盒子依次垂直排列。
BFC内,两个盒子的垂直距离由 margin 属性决定。属于同一个BFC的两个相邻Box的margin会发生重叠【符合合并原则的margin合并后是使用大的margin】
BFC内,每个盒子的左外边缘接触内部盒子的左边缘(对于从右到左的格式,右边缘接触)。即使在存在浮动的情况下也是如此。除非创建新的BFC。
BFC的区域不会与float box重叠。
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
计算BFC的高度时,浮动元素也参与计算
如何创建BFC
浮动元素(float 属性不为 none)
position 为 absolute 或 fixed
overflow 不为 visible 的块元素
display 为 inline-block, table-cell, table-caption
BFC 的应用
防止 margin 重叠 (同一个BFC内的两个两个相邻Box的 margin 会发生重叠,触发生成两个BFC,即不会重叠)
清除内部浮动 (创建一个新的 BFC,因为根据 BFC 的规则,计算 BFC 的高度时,浮动元素也参与计算)
自适应多栏布局 (BFC的区域不会与float box重叠。因此,可以触发生成一个新的BFC)
Flex
什么是flex,flex布局
Vue
mvvm原理:
$nextTick原理:
vue-router原理:
vue生命周期原理:
vuex原理:
vue组件间通信:
虚拟dom:
diff:
Vue 计算属性 VS 侦听属性:
React
React hooks:
高阶组件 函数组件:
fiber:
React vue 区别:
工程化
webpack原理:
webpack loader的原理和实现
webpack plugin的原理和实现
webpack webpack打包优化
webpack Tree-shaking
webpack Code-split
webpack 热更新原理
babel
发布流程
weeks/rn
前端监控
性能优化
网络
http和http2的区别
https的用法
前端如何判断https证书有效
httponly
前端如何跨域,如何跨域携带cookie
三次握手四次挥手的具体区别(http传输过程)
设计模式
发布订阅模式
// 发布订阅模式
//发布订阅模式相比观察者模式多了个事件通道,事件通道作为调度中心,管理事件的订阅和发布工作,
//彻底隔绝了订阅者和发布者的依赖关系。即订阅者在订阅事件的时候,
//只关注事件本身,而不关心谁会发布这个事件;发布者在发布事件的时候,只关注事件本身,而不关心谁订阅了这个事件。
class PubSub{
constructor(){
this.subscribers = []
}
subscribe(topic,callback){
let callbacks = this.subscribers[topic]
if(!callbacks){
this.subscribers[topic] = [callback]
}else{
callbacks.push(callback)
}
}
publish(topic, ...args){
let callbacks = this.subscribers[topic]
callbacks.forEach(callback=>{
callback(...args)
})
}
}
//注册事件调度中心
let pubsub= new PubSub()
// 订阅了一个sayhi的事件
pubsub.subscribe('sayhi',(msg)=>{
console.log(msg)
})
// 发布了一个sayhi的事件
pubsub.publish('sayhi','hi')
观察者模式
//观察者模式是一个一对多的关系
//一方面,观察者要想订阅目标事件,由于没有事件通道,因此必须将自己添加到目标(Subject) 中进行管理;
//另一方面,目标在触发事件的时候,也无法将通知操作(notify) 委托给事件通道,因此只能亲自去通知所有的观察者。
class Subject {
constructor(){
this.observers = []
}
add(observer){
this.observers.push(observer)
}
notify(...args){
this.observers.forEach(observer=>{
observer.update(...args)
})
}
}
class Observer{
update(...args){
console.log(...args)
}
}
//创建被观察者
let subject = new Subject
//创建观察者a
let a = new Observer()
let b = new Observer()
//将目标和观察者关联起来
subject.add(a)
subject.add(b)
subject.notify('hi')