undefined和null
- undefined是未指定值的变量的默认值
- null是一个值,赋值给变量表示这个变量不代表任何值。
Vue2和Vue3响应式对比
vue2
- 深度监听,需要递归到底,一次计算量大
- 无法监听新增属性、删除属性(使用Vue.set、Vue.delete可以)
- 无法监听原生数组,需要重写数组原型
vue3
- 深度监听,性能更好(获取到哪一层才触发响应式get,不是一次性递归)
- 可监听新增/删除属性
- 可监听数组变化
BFC
块级格式化上下文。BFC元素不会影响到其它环境中的布局。
触发BFC的条件
- 根元素或其它包含它的元素
- 浮动元素 (元素的 float 不是 none)
- 绝对定位元素 (元素具有 position 为 absolute 或 fixed)
- 内联块 (元素具有 display: inline-block)
- 表格单元格 (元素具有 display: table-cell,HTML表格单元格默认属性)
- 表格标题 (元素具有 display: table-caption, HTML表格标题默认属性)
- 具有overflow 且值不是 visible 的块元素
- 弹性盒(flex或inline-flex)
- display: flow-root
- column-span: all
BFC元素特性
- 内部的盒会在垂直方向一个接一个排列(可以看作BFC中有一个的常规流)
- 处于同一个BFC中的元素相互影响,可能会发生外边距重叠
- 每个元素的margin box的左边,与容器块border box的左边相接触(对于从左往右的格式化,否则相反),即使存- 在浮动也是如此
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然
- 计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算
- 浮动盒区域不叠加到BFC上
BFC解决的问题
- 垂直外边距重叠问题
- 去除浮动(BFC元素会计算内部浮动子元素高度)
- 自适用两列布局(float + overflow)
盒模型
W3C盒模型
元素大小=margin+border+padding+width(内容)
IE盒模型
元素大小=margin+width(border+padding+内容·)
闭包
作用域链
由多个执行上下文的变量对象构成的链表就叫做作用域链。
Event Loop
Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制。JS中有两种任务类型:微任务(microtask)和宏任务(macrotask)(在ES6中,microtask称为 jobs,macrotask称为 task)。js主线程在运行时会产生执行栈,先运行script宏任务,遇到微任务或宏任务就先添加进任务队列,等script宏任务执行完毕会去检查任务队列有没有微任务。有则执行完全部的微任务然后会渲染页面(不是每次都调用),再执行下一个宏任务;如果没有微任务则继续执行下一个宏任务,这样循环直到任务队列清空。
MVVM
MVVM是一种项目架构模式。分成三个部分,Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据
SPA单页面
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转,而是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
优点
- 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染
- SPA 相对对服务器压力小
缺点
- 首屏加载耗时多
- 所有的内容都在一个页面中动态替换显示,SEO难度较大
- 不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理,消耗内存
webpack
webpack打包流程
- 初始化参数:从配置文件和 Shell 语句中读取并合并参数,得出最终的配置参数。
- 开始编译:从上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译。
- 确定入口:根据配置中的 entry 找出所有的入口文件。
- 编译模块:从入口文件出发,调用所有配置的 loader 对模块进行翻译,再找出该模块依赖的模块,这个步骤是递归执行的,直至所有入口依赖的模块文件都经过本步骤的处理。
- 完成模块编译:经过第 4 步使用 loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系。
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 chunk,再把每个 chunk 转换成一个单独的文件加入到输出列表,这一步是可以修改输出内容的最后机会。
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
loader
loader就是模块转化,不同的文件,需要不同的loader来处理。让模块中的内容转化成webpack或其它laoder可以识别的内容。
Plugin
Plugin是插件,可以参与到整个webpack打包的流程中。在编译的整个生命周期中,Webpack 会触发许多事件钩子,Plugin 可以监听这些事件,根据需求在相应的时间点对打包内容进行定向的修改。
事件机制
W3C的标准是先捕获再冒泡, addEventListener的第三个参数决定把事件注册在捕获(true)还是冒泡(false)。
原型/原型链
__proto__是对象独有的;prototype属性是函数独有的;constructor属性是prototype原型独有的。
原型
用于实现对象的继承。每个JavaScript对象中都包含一个__proto__(非标准)的属性指向该对象的原型prototype。
原型链
原型链是由原型对象组成,每个对象都有 proto 属性,指向了创建该对象的构造函数的原型,proto 将对象连接起来组成了原型链。
Object.create
Object.create会清空Child.prototype对象,然后对象的隐藏属性__proto__指向第一个参数Parent.prototype。第二个参数会为Child.prototype对象添加自身属性。
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
},
})
new操作符
执行过程
- 创建一个新对象
- 对象的原型指向连接到构造函数原型上,并绑定 this(this 指向新对象)
- 执行构造函数代码(为这个新对象添加属性)
- 返回新对象
实现一个new
function myNew (constructor, ...args) {
const newObj = Object.create(constructor.prototype)
const res = constructor.apply(newObj, args)
return typeof res === 'object' ? res : newObj
}
继承
寄生组合继承
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this.val)
}
// 静态方法
Parent.say = function (){}
function Child(value) {
// 继承父类属性和方法
Parent.call(this, value)
}
// 继承父类原型属性和方法
// 1、使用Object.create改变Child.prototype的__proto__指向Parent.prototype,并添加constructor自身属性,
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
}
})
// 2、使用setPrototypeOf继承父类原型属性和方法
// Object.setPrototypeOf(Child.prototype, Parent.prototype)
// 继承父类静态方法
Object.setPrototypeOf(Child, Parent)
const child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
Class 继承
class Parent {
constructor(value) {
this.val = value
}
getValue() {
console.log(this.val)
}
}
class Child extends Parent {
constructor(value) {
super(value)
this.val = value
}
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
防抖/节流
防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
防抖
// func是用户传入需要防抖的函数
// wait是等待时间
const debounce = (func, wait = 50) => {
// 缓存一个定时器id
let timer = 0
// 这里返回的函数是每次用户实际调用的防抖函数
// 如果已经设定过定时器了就清空上一次的定时器
// 开始一个新的定时器,延迟执行用户传入的方法
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
节流
const throttle = (func, wait = 50) => {
// 上一次执行该函数的时间
let lastTime = 0
return function(...args) {
// 当前时间
let now = +new Date()
// 将当前时间和上一次执行函数时间对比
// 如果差值大于设置的等待时间就执行函数
if (now - lastTime > wait) {
lastTime = now
func.apply(this, args)
}
}
}