面试题总结

108 阅读10分钟

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的整体执行流程

  1. 配置通用的基础路径和超时

  2. 显示请求进度条

    1. 显示进度条: 请求拦截器回调
    2. 结束进度条: 响应拦截器回调
  3. 成功返回的数据不再是response, 而直接是响应体数据response.data

  4. 统一处理请求错误, 具体请求也可以选择处理或不处理

  5. 每个请求自动携带userTempId的请求头: 在请求拦截器中实现

  6. 如果当前有token, 自动携带token的请求头

  7. 对token过期的错误进行处理

从输入url到渲染出页面的整个过程

  • 得到服务器对应的IP地址 ==> DNS解析
  • 通过IP连接上服务器: 3次握手
  • 向服务器发请求, 接收服务器返回的响应
  • 解析响应数据(html/css/js)显示页面
    • 解析html => dom树 解析css => cssom树
    • 解析js => 更新dom树/cssom树
    • 生成渲染树 = dom树 + cssom树 布局 渲染
  • 断开连接:4次挥手

函数节流与防抖

  1. 事件高频触发处理的问题 如果更新界面 => 界面更新卡顿 如果发送ajax请求 => 发送了很多没必要的请求
  2. 解决办法 函数节流 函数防抖
  3. 区别: 当事件高频发生很多次时, 防抖只执行最后一次, 而节流执行少量几次
  4. 应用场景 节流: 窗口调整(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打包 启动速度更快

子组件的data如何与接收的props数据同步