html&css
BFC
块级格式化上下文,是一个独立的渲染区域,让处于 BFC 内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。
应用:
- 阻止
margin重叠 - 可以包含浮动元素 —— 清除内部浮动(清除浮动的原理是两个
div都位于同一个 BFC 区域之中) - 自适应两栏布局
盒子模型
页面渲染时,dom 元素所采用的 布局模型。
W3C 标准盒模型,content,padding控制内容位置,margin控制盒子位置,border盒子的样式
flex布局
弹性布局,移动端使用广泛
原理:给父盒子加flex属性,来控制子盒子的位置和排列方式
布局分两个方向(主轴 x右 侧轴y下)
flex-direction设置主轴方向 项目排列方向
justify-content 主轴上子元素的排列方式
align-items align-content 对齐、排列
H5新特性
标签新增:语义化 音视频 注释
表单功能 表单控件属性 autocomplete
全局属性 darggable 元素是否可拖动
兼容性处理 兼容IE的条件注释
rem适配
JS
作用域与作用域链
函数里变量起作用的区域 作用:隔离开变量
多个嵌套的作用域形成的由内到外的结构 用于查找变量
闭包
是什么:内部函数引用外部函数的变量
产生:当调用外部函数时就产生了闭包
释放:让内部函数变成垃圾对象
作用:延长局部变量的生命周期
应用:举删除删除列表中的的某个商品的例子(带确定框)
函数中的this
this指向问题:通常情况,谁调用就指向谁。有new关键字,this指向new出来的对象。在事件中,this指向触发这个事件的对象
特殊情况,直接调用函数,严格模式下是undefined,非严格模式是window;另外情况:箭头函数是没有自己的this,他会沿着作用域链去外部作用域找;
改变this指向:
将任意指定为当前函数中的this:call、apply、bind;
将外部指定为当前:把外部this保存为变量,然后使用这个变量,或者箭头函数
原型与原型链
-
原型
- 每个函数都有一个显式原型属性:
prototype - 每个实例都有一个隐式原型属性:
__proto__ - 实例的
__proto__指向对应函数的prototype即原型对象 - 原型对象上有一个
constructor属性指向对应的构造函数
- 每个函数都有一个显式原型属性:
-
原型链
-
从对象的
__proto__开始, 连接的所有对象。也可称为“隐式原型链” -
原型链的作用:
- 在查找对象属性或调用对象方法时, 会先在对象自身上查找, 找不到就会沿着原型链查找
- 利用原型链可以实现继承
-
垃圾回收机制
是判断对象是否是垃圾对象的算法
以前:引用计数(内存地址引用指向的次数)
现在:标记清除(给使用中的进行标记,然后清除没有标记的)
JS的事件循环机制
js是单线程的,同一时间只能做一件事,效率很低,就出现了同步和异步任务(事件、资源加载、定时器)
JS执行机制:
1、先执行执行栈中的同步任务
2、异步任务(回调函数)放入任务队列中
3、一旦执行栈中的所有同步任务执行完毕,系统就会按顺序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
由于主线程不断的重复获得任务 执行任务 再获取再执行 所以这种机制就叫做事件循环
promise / async与await
promise
-
ES6推出的更好的异步编程解决方案(相对于纯回调的方式)
- 解决嵌套回调的回调地狱问题 ==> 通过promise.then的链式调用
- 指定读取结果数据的回调函数时机更灵活 ==> 请求后/请求前/请求完成后都可以
-
promise对象有3种状态
- pending
- resolved/fulfilled
- rejected
-
promise状态的2种变化
- pending --> resolved
- pending --> rejected
-
如何改变promise的状态
- 调用resolve()
- 调用reject()
- throw error
-
then指定成功和失败的回调, 用于得到成功/失败的结果数据
-
then()总是返回一个新的promise
async/await
-
async与await是异步编程的终极解决方案 => 消灭回调函数
-
作用: 简化promise对象的使用, 不用再使用then/catch来指定回调函数
-
使用
- await一般在结果为promise的表达式左侧
- async在await所在函数定义的左侧
-
注意:
- 调用async函数得到是一个promise, 其结果状态由async函数体执行的结果决定
- await的右侧也可以不是promise, 如果不是, 直接返回表达式的值
箭头函数的特点
- 编码简洁
- 没有自己的this, 使用外部作用域中的this, 不能通过bind来绑定this
- 不能通过new来创建实例对象
- 内部没有arguments, 可以通过rest参数来代替
跨域问题
-
同源: 协议, 域名, 端口, 三者都相同
-
同源策略
- ajax请求时, 浏览器要求当前网页和Server必须同源(安全), 否则会抛出跨域的错误
- 加载image/link/script不受同源策略限制
-
解决ajax跨域问题的办法
- JSONP: 利用script发跨域请求目标接口, 得到响应数据
- CORS: 浏览器直接请求跨域的目标接口, 服务器返回响应头告诉浏览器允许跨域
- Proxy: 浏览器发同源请求代理服务器, 代理服务器转发请求跨域的目标接口
axios的二次封装 => axios的整体执行流程
-
配置通用的基础路径和超时
-
显示请求进度条
- 显示进度条: 请求拦截器回调
- 结束进度条: 响应拦截器回调
-
成功返回的数据不再是response, 而直接是响应体数据response.data
-
统一处理请求错误, 具体请求也可以选择处理或不处理
-
每个请求自动携带userTempId的请求头: 在请求拦截器中实现
-
如果当前有token, 自动携带token的请求头
-
对token过期的错误进行处理
从输入url到渲染出页面的整个过程
- 得到服务器对应的IP地址 ==> DNS解析
- 通过IP连接上服务器: 3次握手
- 向服务器发请求, 接收服务器返回的响应
- 解析响应数据(html/css/js)显示页面
- 解析html => dom树 解析css => cssom树
- 解析js => 更新dom树/cssom树
- 生成渲染树 = dom树 + cssom树 布局 渲染
- 断开连接:4次挥手
函数节流与防抖
- 事件高频触发处理的问题 如果更新界面 => 界面更新卡顿 如果发送ajax请求 => 发送了很多没必要的请求
- 解决办法 函数节流 函数防抖
- 区别: 当事件高频发生很多次时, 防抖只执行最后一次, 而节流执行少量几次
- 应用场景 节流: 窗口调整(resize)/ 页面滚动(scroll)/ OM元素的拖拽功能实现(mousemove) 防抖: 输入搜索联想功能
vue
区别v-if和v-show
都为条件渲染
v-if
通过删除DOM元素实现元素的隐藏;
惰性:只有条件为真时, 才会加载元素到DOM;
v-show
通过设置元素的css样式 display:none 实现元素的隐藏, 不操作DOM;
非惰性:不管条件真与假, 都会加载元素到 DOM;
v-if适合条件不大可能改变;v-show适合频繁切换。
为什么v-for与v-if不适合一起使用
v-for的优先级比v-if更高
(v-if会分别重复运行在每个v-for中循环)
为什么data必须是一个函数
当复用组件时,由于数据都指向同一个data,当在一个组件中修改data时,其他重用的组件中的data会同时被修改。
computed与watch
computed是计算属性, 有两种用户,一种是仅读取,一种是读取+设置;依赖项改变时,会重新计算;重点是一个数据受多个数据影响; 需要return
watch是侦听器,重点在监听某个数据的变化,重点是一个数据影响多个数据,侧重点在监听; 不需要return
Vue组件的生命周期
vue2:
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- boforeDestory
- destoryed
-
缓存组件用到
- actived 组件激活时触发
- deactived 组件未激活时触发
vue3:
- setup
- onBeforeMount
- onMounted
- onBeforeUpdate
- onUpdated
- onBeforeUnmount
- onUnmounted
- onErrorCaptured (捕捉错误)
- onActived
- onDeactived
组件间通信
-
vue2
-
父->子
- props(非函数)
- v-model
$refs/$children- 作用域插槽
-
子->父
- props(函数)
- 自定义事件
- .sync
- v-model
- $parent
- 作用域插槽
-
爷孙组件通信
- provide/inject
$attr/$listeners
-
任意组件
- pubsub
- 事件总线
- vuex
-
-
vue3
- props
- 自定义事件
- v-model
- 作用域插槽
- pubsub (需要安装插件)
- pinia
history与hash路由的区别
-
hash模式
- 标签描点是浏览器地址
#后面的变化 , hashchange事件可以监听这个变化 - hash可以值的改变可以触发hashchange事件 ,兼容性更好
- 标签描点是浏览器地址
-
history模式
- 原理是用的H5新增的history API,允许更新浏览器的url地址
- url地址不带
#,比较美观, 但兼容性更差
new Vue的初始化流程
Vue模板编译流程
- 第一步: 解析模板字符串生成抽象语法树对象(ast)
- 第二步: 对AST进行优化(vue3会添加静态标记)
- 第三步: 根据ast生成用于生成VDOM的render函数代码
Vue内部的三种watcher
- computed watch
- user watcher
- render watcher
keep-alive的原理
keep-alive是Vue的内置组件,可以包裹动态组件/路由组件,在组件切换时,不会销毁组件,而且缓存暂时不显示的组件 ,防止重复渲染DOM,减少加载时间和性能消耗,提高用户体验
原理:
- 获取默认插槽组件的vnode
- 如果vnode已经有缓存了,那么会取出缓存的组件实例,保存到当前的vnode,就不会再创建新的组件实例
生命周期的变化
- 用到缓存组件的组件会执行actived和deactived钩子函数 (激活与未激活)
Vue响应式数据原理
- 通过数据劫持defineProperty + 发布订阅模式
- 当vue实例初始化时,observer通过defineProperty给data所有层级的属性添加getter/setter; getter用来读取属性值 , setter用来将最新设置的值保存到data对应的属性上 ,完成数据劫持,把每个数据变成响应式数据;
- 为每个属性创建对应的dep,用来收集对应的watcher.当读取数据时,执行对应的getter,收集依赖
- 当data的某个属性更新时,遍历内部所有的watcher去更新
$nextTick的原理
Vue在修改数据后,视图不会立即更新,而是等同一事件的事件循环中所有的数据都改变之后,再进行试图更新
- nextTick可以传两个参数: 回调函数和环境对象
- nextTick把传入的函数放入callbacks这个数组,并执行timeFunc函数
- timeFunc函数:检查当前环境是否支持原生Promise/原生MutatonObserver, 然后把回调函数放入微任务队列,如果不支持,则检查是否支持setImmediate, 如果不支持就用setTimeout,去执行flushCallbacks函数
- flushCallbacks函数:for循环执行callbacks队列
虚拟DOM与DOM Diff
虚拟DOM
-
比较虚拟DOM 和 真实DOM
- 虚拟DOM体量较轻, 真实DOM体量较大
- 初始化时, 会根据虚拟DOM生成真实DOM
- 更新阶段: 会进行新旧虚拟DOM的比较,选择性的更新真实DOM (内部根据的是Diff算法)
Diff算法:
- Diff算法会确定哪些真实DOM需要复用/哪些需要新建
- 为了提高效率,会尽可能的复用真实DOM
Key的作用
- key是虚拟DOM的唯一标识,只有找到相同key值的虚拟DOM,才会复用真实DOM,不然会新建虚拟DOM
- key一般用后台返回的唯一值id。 index会受到数组方法的执行而变化不稳定
说说你对TS的理解
typescript是强类型,声明变量时指定特定的类型,编码时也会有提示、报错、补全
TS不仅支持JS所有的语法,还扩展了新的类型: 接口、泛型等
-
接口
- 约束一个对象/函数的类型
- 关键字 interface
-
泛型
- 代表不确定的类型
- 泛型在定义函数(限制参数和返回值类型)、接口时
- 关键字 <>
说说Vue3的特点
- 组合式API和选项API 组合式API更加便于阅读, 方便维护
- 体积更小、将功能以多个函数提供出来,进行按需引入
- 性能更好、引入树摇,将无用的模块直接摇掉 不会打包
- 使用proxy代替defineProperty实现数据劫持
- diff算法优化:静态虚拟节点添加静态标记,不进行diff比较,直接复用真实DOM
- 静态提升:静态虚拟节点提升到 render函数外面,缓存起来,不创建新的
- 更好支持typescript
- vite打包 启动速度更快