前端面试

143 阅读24分钟

css部分

1 标准盒子模型与低版本ie盒子模型的不同

标准盒子模型:宽度=内容的宽度(content)+border+padding+margin

低版本ie盒子模型:宽度=内容宽度(content+border+padding)+margin

2 box-sizing属性

用来控制元素的盒子模型的解析模式,默认为content-box

content-box:w3c的标准盒子模型,设置元素的height/width属性指的是content部分的宽高

border-box:ie传统盒子模型,设置元素的height/width属性指的是border+padding+content部分宽高

3 重排(reflow)和重绘(repaint)的理解

  • 重排:无论通过什么方式影响了元素的几何信息(元素在视口的位置和尺寸大小),浏览器需要重新计算在视口内的几何属性,这个过程叫重排
  • 重绘:通过构造渲染树和重排(回流)阶段,我们知道了那些节点是可见的,以及可见节点的样式和具体的几何信息(元素在视口内的位置和尺寸大小),接下来就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘。

如何减少重排和重绘

  • 减少重排和重绘,比如样式集中改变,使用添加新样式类名.class或cssText
  • 批量操作DOM,比如读取某个元素offsetWidth属性存到一个临时变量,再去使用,而不是频繁使用这个计算属性;又比如利用document.createDocumentFragment()来添加要添加的节点,处理完之后再插入到实际DOM中
  • 使**absolute**或者**fixed**使元素脱离文档流,这再制作复杂的动画时对性能的影响比较明显

4 BFC的理解

BFC即块级格式化上下文,根据盒模型可知,每个元素都被定义为一个矩形盒子,然而盒子的布局会受到尺寸,定位,盒子的子元素或兄弟元素,视口的尺寸等因素决定,所以这里有一个浏览器计算的过程,计算的规则就是由一个叫做视觉格式化模型的东西定义,BFC就是来自这个概念,他是css视觉渲染的一部分,用于决定块级盒的布局及浮动相互影响范围的一个区域

BFC的特性

  1. 块级元素会再垂直方向一个接一个的排列,和文档流的排列方式一致
  2. 在BFC中上下相邻的两个容器的margin会重叠,创建新的BFC可以避免外边距重叠
  3. 计算BFC的高度时,需要计算浮动元素的高度
  4. BFC区域不会与浮动的容器发生重叠
  5. BFC是独立的容器,容器内部元素不会影响外部元素
  6. 每个元素的左margin值和容器的左border相接触

利用这些特性,我们可以解决以下问题:

  • 利用4和6,我们可以实现三栏(或两栏)自适应布局
  • 利用2,我们可以避免margin重叠问题
  • 利用3,我们可以避免高度崩塌问题

创建BFC的方法

  • 绝对定位元素(position为fixed或absolute)
  • 行内元素,即display为inline-block
  • overflow的值不为visible

5 实现两栏布局

现在有以下DOM结构

<div class="outer">
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
  1. 利用浮动,左边元素宽度固定,设置向左浮动,将右边元素的margin-left设置为固定宽度。注意,因为右边元素的width默认为auto,所以会自动撑满父元素。

    .outer{
      height:100px;
    }
    .left{
      float:left;
      width:200px;
      height:100%;
      background:lightcoral;
    }
    .right{
      margin-left:200px;
      height:100%;
      background:lightseagreen;
    }
    
  2. 同样利用浮动,左边元素宽度固定,设置向左浮动。右侧元素设置overflow:hidden;这样右边就触发BFC,BFC的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠

    .outer{
      height:100px;
    }
    .left{
      float:left;
      width:200px;
      height:100%;
      background:lightcoral;
    }
    .right{
      overflow:hidden;
      height:100%;
      background:lightseagreen;
    }
    
  3. 利用flex布局,左边元素固定宽度,右边的元素设置flex:1

    .outer{
      display:flex;
      height:100px;
    }
    .left{
      width:200px;
      height:100%;
      background:lightcoral;
    }
    .right{
      flex:1;
      height:100%;
      background:lightseagreen;
    }
    
  4. 利用绝对定位,父元素设为相对定位。左边元素absolute定位,宽度固定,右边元素的margin-left的值设为左边元素的宽度值

    .outer{
      position:relative;
      height:100px;
    }
    .left{
      position:absolute;
      width:200px;
      height:100%;
      background:lightcoral;
    }
    .right{
      margin-left:200px;
      height:100%;
      background:lightseagreen;
    }
    
  5. 利用绝对定位,父元素设为相对定位,左边元素宽度固定,右边元素absolute定位,left为宽度大小,其余方向定位为0

    .outer{
      position:relative;
      height:100px;
    }
    .left{
      width:200px;
      height:100%;
      background:lightcoral;
    }
    .right{
      position:absolute;
      left:200px;
      top:0px;
      right:0px;
      bottom:0px;
      height:100%;
      background:lightseagreen;
    }
    

6 水平垂直居中多种实现方式

  1. 利用绝对定位,设置left:50%和top:50% 现将子元素左上角移到父元素中心位置,然后再通过translate来调整子元素的中心点到父元素中心,该方法可以不定宽高

    .father{
      position:relative;
    }
    .son{
      position:absolute;
      left:50%;
      right:50%;
      transform:translate(-50%,-50%)
    }
    
  2. 利用绝对定位,子元素所有方向都设置为0,将margin设置auto,由于宽高固定,对应方向实现平分,该方法必须盒子有宽高

    .father{
      position:relative;
    }
    .son{
      position:absolute;
      top:0;
      left:0;
      right:0;
      bottom:0px;
      margin:auto;
      height:100px;
      width:100px;
    }
    
  3. 利用绝对定位,设置left:50%和top:50% 现将子元素左上角移到父元素中心位置,然后再通过margin-left和margin-top以子元素自己的一半宽高进行负值赋值,该方法必须定宽高

    .father{
      position:relative;
    }
    .son{
      position:absolute;
      left:50%;
      top:50%;
      width:200px;
      height:200px;
      margin-left:-100px;
      margin-top:-100px;
    }
    
  4. 利用flex

    .father{
      display:flex;
      justify-content:center;
      align-items:center;
    }
    

js基础

1 基本数据类型介绍,及值类型和引用类型的理解

在js中共有8种基础的数据类型,分别为:undefined,null,boolean,number,string,object,symbol,bigint

其中SymbolBigInt是es6新增的数据类型

  • Symbol代表独一无二的值,最大的用法是用来定义对象的唯一属性名
  • BigInt可以表示任意大小的整数

值类型的赋值变动过程

let a=100
let b=a
a=200
console.log(b) //100

引用类型的赋值变动过程如下

let a={age:20}
let b=a
b.age=30
console.log(a.age)  //30

2 数据类型的判断

  • typeof:能判断所有值类型,函数。不可对null、对象、数组进行精确判断,因为都返回object

    console.log(typeof undefined)  //undefined
    console.log(typeof 2)    //number
    console.log(typeof true)  //boolean
    console.log(typeof 'str')  //string
    console.log(typeof Symbol('foo'))  //Symbol
    console.log(typeof 12134434n)  //bigint
    console.log(typeof function(){}) //function
    //不能判断
    console.log(typeof []) //object
    console.log(typeof {}) //object
    console.log(typeof null) //object
    
  • instanceof:能判断对象类型,不能判断基本类型,其内部运行机制是判断在其原型链中能否找到该类型的原型

    Array.isArray(arr) //true
    arr._proto_===Array.prototype //true
    arr instanceof Array  //true
    

3 深拷贝

/**
 *深拷贝
 * @param {Object} obj 要拷贝的对象
 * @param {Map} map 用于存储循环引用对象的地址
*/
function deepClone(obj={},map=new Map()){
  if(typeof obj!=="object"){
    return obj
  }
  if(map.get(obj)){
    return map.get(obj)
  }
  
  let rusult={}
  //初始化返回结果
  if(obj instanceof Array ||Object.prototype.toString(obj)==="[object Array]"){
    result=[]
  }
  // 防止循环引用
  map.set(obj,result)
  for(let key in obj){
    //保证key不是原型属性
    if(obj.hasOwnProperty(key)){
      result[key]=deepClone(obj[key],map)
    }
  }
  //返回结果
  return result
}

4 原型和原型链

  • 原型:每一个javaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型’‘继承’‘属性,其实就是prototype对象
  • 原型链:由相互关联的原型组成的链式结构就是原型链

5 作用域与作用域链

  • 作用域:规定了如何查找变量,也就是确认当前执行代码对变量的访问权限。换句话说,作用域决定了代码区块中变量和其他资源的可见性。(全局作用域,函数作用域,块级作用域)
  • 作用域链:从当前作用域开始一层层往上找某个变量,如果找到全局作用域还没找到,就放弃寻找。这种层级关系就是作用域链。

6 执行上下文

总结:当JavaScript代码执行一段可执行代码时,会创建对应的执行上下文,对于每个执行上下文,都有三个重要属性:

7 闭包

根据MDN中文的定义

在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,可以在一个内层函数中访问到其外层函数的作用域

也可以这样说

闭包是指那些能够访问自由变量的函数,自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。闭包=函数+函数能够访问的自由变量

在某个内部函数的执行上下文创建时,会将父级函数的活动对象加到内部函数的[[scope]]中,形成作用域链,所以即使父级函数的执行上下文销毁(即执行上下文栈弹出父级函数的执行上下文),但是因为其活动对象还是实际存储在内存中可被内部函数访问到的,从而实现了闭包

闭包应用:函数作为参数被传递

function print(fn){
  const a=200;
  fn();
}

const a=100;
function fn(){
  console.log(a)
}
print(fn)  //100

函数作为返回值被返回:

function create(){
  const a=100;
  return function(){
    console.log(a)
  }
}

const fn=create()
const a=200;
fn(); //100

闭包:自由变量的查找,是在函数定义的地方,向上级作用域查找。不是在执行的地方

应用实例:比如缓存工具,隐藏数据,只提供API

function createCache(){
  const data={}  //闭包中被隐藏的数据,不被外界访问
  return {
    set:function(key,val){
      data[key]=val
    },
    get:function(key){
      return data[key]
    }
  }
}

const c=createCache()
c.set("a",100)
console.log(c.get("a"))  //100

8 call,apply,bind实现

call

call()方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法

var obj={
  value:'vortesnail'
}

function fn(){
  console.log(this.value)
}
fn.call(obj)  //vortesnail

通过call方法我们可以做到以下两点:

  • call改变了this的指向,指向到obj
  • fn函数执行了
var obj={
  value:'vortesnail',
  fn:function(){
    console.log(this.value)
  }
}
obj.fn()  //vartesnail

这时候this就指向了obj,但是这样做我们手动给obj添加了一个fn属性,这显然是不行的,不用担心,我们执行完再使用队形属性的删除方法(delete)不就行了

obj.fn=fn
obj.fn()
delete.obj.fn;

根据这个思路

Function.prototype.myCall=function(context){
  //判读调用对象
  if(typeof this!=='function'){
    throw new Error('Type error')
  }
  //首先获取参数
  let args=[...arguments].slice(1)
  let result=null
  //判断context是否传入,如果没有传入就设置为window
  context=context||window
  //将被调用的方法设置为context的属性
  //this 即为我们要调用的方法
  context.fn=this
  //执行要调用的方法
  result=context.fn(...args)
  //删除手动增加的属性方法
  delete context.fn
  //将执行结果返回
  return result
}

apply

apply相对call,没有什么区别,只是传参的方式不同

Function.prototype.myApply=function(context){
  if(typeof this!=='function'){
    throw new Error('Type error')
  }
  let result=null
  context=context||window
  //与上面代码相比,我们使用Symbol来保证属性唯一
  //也就是保证不会重写用户自己原来定义在context中的同名属性
  const fnSymbol=Symbol()
  context[fnSymbol]=this
  //执行要被调用的方法
  if(arguments[1]){
    result=context[fnSymbol](...arguments[1])
  }else{
    result=context[fnSymbol]()
  }
  delete context[fnSymbol]
  return result
}

bind

bind返回的是一个函数

Function.prototype.myBind=function(context){
  //判断调用对象是否为函数
  if(typeof this!=='function'){
    throw new Error('Type error')
  }
  //获取参数
  const args=[...arguments].silce(1)
  const fn=this
  return function Fn(){
    return fn.apply(this instanceof Fn?this:context,args.concat(...arguments))
  }
}

9 new 实现

  1. 首先创一个新的空对象

  2. 根据原型链,设置空对象的_proto_为构造函数的prototype

  3. 构造函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)

  4. 判断函数的返回值类型,如果是引用类型,就返回这个引用类型的对象

    function myNew(context){
      const obj=new Object()
      obj._proto_=context.prototype
      const res=context.apply(obj,[...arguments].slice(1))
      return typeof res==='object'?res:obj
    }
    

10 async/await和Promise的关系

  • async/await是消灭异步回调的终极武器
  • 但和Promise并不互斥,反而相辅相成
  • 执行async函数,返回的一定是Promise对象
  • await相当于Promise的then
  • try...catch可以捕获异常,替代了Promise的catch

11 浏览器的垃圾回收机制

  • 标记清除:标记阶段即为所有活动对象做上标记,清除阶段则把没有标记销毁
  • 引用计数:它把对象师傅不再需要简化定义为对象有没有其他对象引用到它,如果没有引用指向该对象(引用计数为0),对象将被垃圾回收机制回收

12 web存储

  1. cookie。

    • 本身用于浏览器和server通信

    • 被’借用‘到本地存储来的

    • 可用document。cookie=’...‘来修改

    • 其缺点:

      • 存储大小限制为4kb
      • http请求时需要发送到服务端,增加请求数量
      • 只能用document.cookie=’...‘来修改,太过简陋
  2. localStorage和sessionStorage

    • HTML5专门为存储来设计的,最大可存5M
    • API简单易用,setItem getItem
    • 不会随着http请求被发送到服务器

    他们的区别:

      • localStorage数据会永久存储,除非代码删除或手动删除
      • sessionStorage数据只会在于当前会话,浏览器关闭则清空
      • 一般用于localStorage会多一些

13 http

1.1状态码分类

  • 1xx - 服务器收到请求
  • 2xx - 请求成功 如200
  • 3xx - 重定向 如302
  • 4xx - 客户端错误 如 404
  • 5xx - 服务器错误,如500

1.2常见状态码

  • 200 - 成功
  • 301 - 永久重定向
  • 302 - 临时重定向
  • 304 -资源未被修改
  • 403 - 没权限
  • 404 - 资源未找到
  • 500 - 服务器错误
  • 504 - 网关超时

14 性能优化

代码层面

  • 防抖和节流
  • 减少回流和重绘
  • 事件委托
  • 减少DOM操作
  • 按需加载

构建方面

  • 压缩代码文件
  • 开启gzip压缩
  • 常用的第三方库使用CDN服务

15 EventLoop

JS是单线程的,为了防止一个函数执行时间过长阻塞后面的代码,所以会先将同步代码压入执行栈中,依次执行,将异步代码推入异步队列,异步队列又分为宏任务队列和微任务队列,因为宏任务队列的执行时间较长,所以微任务队列要优于宏任务队列。微任务队列代表Promise.then,宏任务队列代表setTimeout,setInterval

16 原生ajax

ajax是一种异步通信的方法,从服务端获取数据,达到局部刷新页面的效果

  1. 创建XMLHttpRequest对象
  2. 调用open方法传入三个参数,请求方式(GET/POST)、url、同步异步(true/false)
  3. 监听onreadystatechange事件,当readystate等于4时返回responseText
  4. 调用send方法传递参数

17 ES6新增

  1. 新增symbol类型 代表独一无二的值,用来定义独一无二的对象属性名
  2. const/let 都是用来声明变量,不可重复声明,具有块级作用域。存在暂时性死区,也就是不存在变量提升(const一般用于声明常量)
  3. 变量的解构复制(包含数组,对象,字符串,数字及布尔值,函数参数)
  4. 模板字符串
  5. 扩展运算符(数组,对象)
  6. Set和Map数据结构
  7. Proxy/Reflect
  8. Promise
  9. async函数
  10. Class
  11. Module语法(import/export)

18 防抖

//定义:触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间
//搜索框搜索输入。只需要用户最后一次输入完,再发送请求
//手机号、邮箱验证输入检测onchange oninput事件
//窗口大小Resize,只需窗口调整完成后,计算窗口大小。防止重新渲染
const debounce=(fn,wait,immediate)=>{
    let timer=null
    return function(...args){
        if(timer) clearTimout(timer)
        if(immediate&&!timer){
            fn.call(this,args)
        }
        timer=setTimeout(()=>{
            fn.call(this,args)
        },awit)
    }
}

19 节流

//定义:当持续触发事件时,保证隔间时间触发一次事件
//1.懒加载、滚动加载、加载更多或监听滚动条位置
//2.百度搜索框、搜索联想功能
//3.防止高频点击提交,防止表单重复提交
function throttle(fn,awit){
    let pre=0
    reutrn function(...args){
        let now=Date.now()
        if(now-pre>=awit){
            fn.apply(this,args)
            pre=now
        }
    }
}

20 数组去重,数组对象去重

//数组
const arr=[2,7,5,7,2,8,9]
console.log([...new Set(arr)])
//对象
const list=[{age:18,name:'张三'},{age:18,name:'李四'},{age:18,name:'王五'}]
let hash={}
const newArr=arr.reduce((item,next)=>{
    hash[next.age]?'':hash[next.age]=true&&item.push(next)
    return item
},[])
console.log(list)

21 es6里的set和map

  • Map对象保存键值对,任何值(对象或者原始值)都可以作为一个键或一个值。构造函数Map可以接受一个数组作为参数
  • Set对象允许你存储任何类型的值,无论是原始值或者是对象引用,它类似于数组,但是成员的值都是唯一的,没有重复的值

22 普通函数和箭头函数的区别

  1. 箭头函数是匿名函数,不能作为构造函数,不能使用new
  2. 箭头函数不能绑定arguments,取而代之用rest参数。。。解决
  3. 箭头函数不能绑定this,会

Vue

1 MVVM简述

MVVM是Model-view-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据

2 vue生命周期的理解

每个vue实例在创建时都会经过一系列的初始化过程,vue的生命周期钩子:

  • create阶段:vue实例被创建beforeCreate:创建前,此时data和methods中的数据都还没有初始化。create:创建完毕,data,methods中的数据能被访问,未挂载DOM上
  • mount阶段:vue实例被挂载到真实DOM节点beforeMount:可以发起服务端请求,去数据,mounted:此时可以操作DOM
  • update阶段:当vue实例里面的data数据变化时,触发组件的重新渲染beforeUpdate,updated
  • destroy阶段:vue实例被销毁beforeDestroy:实例被销毁前,此时可以手动销毁一些方法destroyed

3 computed与watch

watch属性监听是一个对象,键是需要观察的属性,值是对应回调函数,主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,监听属性的变化,需要在数据变化时执行异步或开销比较大的操作时使用

computed计算属性属性的结果会被缓存,当computed中的函数所依赖的属性没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取,除非依赖的响应式属性变化时才会重新计算,主要当做属性来使用computed中的函数必须用return返回最终结果

使用场景:computed:当一个属性受到多个属性影响的时候使用,例如:购物车商品结算功能,watch:当一条数据影响多条数据的时候使用,例如搜索数据

4 v-for中key的作用

  1. key的作用主要是为了更高效的对比虚拟DOM中每个节点是否是相同节点
  2. Vue在patch过程中判断两个节点是否是相同节点,key是一个必要条件,渲染一组列表时,key往往是唯一标识。影响性能
  3. Vue判断两个节点是否相同时主要判断两者的key和元素类型等,如果不设置key,他的值就是undefined,则可能永远认为这是两个相同的节点,只能去做更新操作,这样造成大量给dom更新操作

5 vue组件的通信方式

父子组件通信

父->子 props,子->父$on、$emit获取父子组件实例 parent、children Ref获取实例的方式调用组件的属性或者方法 Provide、inject 官方不推荐使用,但是写组件库时很常用

兄弟组件通信

Event Bus实现跨组件通信 Vue.prototype.$bus=new Vue() Vuex

跨组件通信

$attrs,$listeners , Provide,inject

6 双向绑定实现原理

当一个Vue实例创建时,Vue会遍历data选项的属性,用Object.defineProperty将他们转为getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的watcher程序实例,它会s在组件渲染的过程中把属性记录为依赖,之后当依赖香的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新

7 v-model的实现以及它的实现原理

  1. vue中双向绑定是一个指令v-model,可以绑定一个动态值到视图,同时视图中变化能改变该值。v-model是语法糖,默认情况下相于:value和@input
  2. 使用v-model可以减少大量繁杂的事件处理代码,提高开发效率,代码可读性也更好。
  3. 通常在表单项上使用v-model
  4. 原生的表单项可以直接使用v-moel,自定义组件上如果要使用它需要在组件内绑定value并处理输入事件

8 nextTick的实现

  1. nextTick是vue提供的一个全局api,是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用$nextTick,则可以在回调中获取更新后的DOM
  2. vue在更新DOM时是异步执行的,只是侦听到数据变化,vue将开启1个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去掉重复数据对于避免不必要的计算和DOM操作是非常重要的,nextTick方法会在队列中加入一个回调函数,确保该函数在前面的dom操作完成后才调用

9 vnode的理解,compiler和patch的过程

vnode 虚拟DOM节点创建
export function Vnode(){
    return {
        tag:'div',
        children:'span',
        attr:'',
        text:'你好'
    }
}

10 new Vue后整个的流程

  • initProxy:作用域代理,拦截组件内访问其它组件的数据
  • initialLifefecycle:建立父子组件关系,在当前组件实例上添加一些属性和生命周期标识。
  • initEvents:对父组件传入的事件添加监听,事件是谁创建谁监听,子组件创建事件子组件监听
  • initRender:声明slots和createElement
  • initInjections:注入数据,初始化inject,一般用于组件更深层次之间的通信
  • initState:数据响应式:初始化状态。
  • initProvide:提供数据注入

11 keep-alive的实现

作用:实现组件缓存

钩子函数

activated 组件渲染后调用
deactivated 组件销毁后调用

原理:vue.js内部将DOM节点抽象成为一个个的VNode节点,keep-alive组件的缓存也是基于VNode节点的,而不是直接存储DOM结构,它将满足条件的组件在cache对象中缓存起来,需要重新渲染时再将VNode节点从cache对象中取出来并渲染

配置属性

include:字符串或正则表达式。只有名称匹配的组件会被缓存

exclude:字符串或正则表达式,任何名称匹配的组件都不会被缓存

max 数字、最多可以缓存多少组件实例

12 vuex,vue-router实现原理

vuex是一个专门为vue.js应用程序开发的状态管理库。核心概念:

  • state(单一状态树)getter/Mutation显示提交更改state
  • Action类似Mutation,提交Mutation,可以包含任意异步操作
  • module()当应用变得庞大复杂,拆分store为具体的module模块

13 vue的性能优化

编码阶段
尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
v-if和v-for不能连用
如果需要使用v-for给每项元素绑定事件时使用事件代理
SPA页面采用keep-alive缓存组件
在更多的情况下,使用v-if替代v-show
key保证唯一
使用路由懒加载、异步组件
防抖、节流
第三方模块按需导入
长列表滚动到可视区域动态加载
图片懒加载
SEO优化
预渲染
服务器渲染SSR
打包优化
压缩代码
使用cdn加载第三方模块
服务器开启gzip压缩

14 vue3的新特性,优缺点

  • 性能提升

更小巧、更快捷支持自定义渲染器 支持摇树优化:一种在打包时去除无用代码

的优化手段 支持Fragments和跨组件渲染

  • API变动

模板语法99%保持不变 原生支持基于class的组件,并且无需借助任何编译及各种stage阶段的特性 在设计时也考虑typescript的类型推断特性重新虚拟DOM。

  • 不兼容ie11

检查机制更见全面、精准、高效,更具可调试式的响应式跟踪

15 实现双向绑定Proxy与Object.definePropperty相比优缺点

  1. Object.defineProperty的作用是劫持一个对象的属性,劫持属性的getter和setter方法,在对象的属性发生变化时特定的操作。而Proxy劫持的是整个对象
  2. Proxy会返回一个代理对象,我们只需要操作新对象即可,而Object.defineProperty只能遍历对象属性直接修改
  3. Object.defineProperty不支持数组,更准确的说是不支持数组的各种API,因为如果仅仅考虑arr[i]=value这种情况,是可以劫持的,但是这种劫持意义不大。而Proxy可以支持数组的各种API
  4. 尽管Object.defineProperty有居多缺陷,但是兼容性要好于Proxy

网络安全、http协议

1 TCP UDP区别

1.TCP’向上层提供面向连接的可靠服务,‘UDP’向上层提供无连接不可靠服务
2 虽然‘UDP’并没有‘TCP’传输来的准确,但是也能在很多实时性要求高的地方有所作为
3.对数据准确性要求高,速度可以相对较慢的,可以选用‘TCP

2 http 和https区别

1.‘http’的URL 以http:// 开头,而https 的URL 以 https:// 开头
2.‘http’是不安全的,而https是安全的
3.‘http’标准端口是80,而https的标准端口是443
4.‘在OSI’网络模型中,HTTP工作于应用层,而HTTPS的安全传输机制工作在传输层
5.‘HTTP’无法加密,而‘HTTPS’对传输的数据进行加密
6.‘HTTP’无需证书,而‘HTTPS’需要CA机构wosgin的颁发的SSL证书

3 GET和POST区别

  1. GET在浏览器回退不会再次请求,POST会再次提交请求
  2. GET请求会被浏览器主动缓存,POST不会,要手动设置
  3. GET请求参数会被完整保留在浏览器历史记录里,POST中的参数不会
  4. GET请求在URL中传递的参数是有长度限制的,而POST没有限制
  5. GET参数通过URL传递,POST放在Request body中
  6. GET参数暴露在地址栏不安全,POST放在报文内部更加安全
  7. GET一般用于查询信息,POST一般用于信息的提交操作

4 输入url后http请求的完整过程

建立TCP连接 ->发送请求行 - > 发送请求头 ->(到达服务器)发送状态行 -> 发送响应头 ->发送响应数据 ->断开TCP连接

5 前端性能优化的几种方法

1.浏览器缓存
2.防抖、节流
3.资源懒加载、预加载
4。开启Nginx gzip压缩
一、webapck优化与开gzip压缩
	1.babel-loader用include或exclude来帮我们避免不必要的转义
	2.文件采用按需加载
	3.图片优化,采用svg图片或字体图标
	4.浏览器缓存机制,它分为强缓存和协商缓存
二、代码优化
	1.事件代理
	2.事件的节流和防抖
	3.页面的回流和重绘
	4.Eventloop事件循环机制

6 跨域通信的方法

  1. jsonp(利用script标签没有跨域限制的漏洞实现。缺点:只支持GET请求)
  2. CORS(设置Access-Control-Allow-Origin:指定可访问资源的域名)
  3. postMessage(message,targetOrigin,[transfer])(HTML5新增API用于多窗口消息、页面内嵌iframe消息传递),通过onmessage监听传递过来的数据
  4. websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案
  5. Node中间件代理
  6. Nginx反向代理