乐趣区

关于前端:2022前端面试复习

一个在教育行业苦干两年的前端菜鸟,到职后就在筹备温习面试,记录一下这次前端温习过程。前端常识是在是太多,继续更新中 … 心愿对真正找工作的你有所帮忙,文末我整顿了一下面试文章,感兴趣的能够看看,尤其是 2022 高频前端面试题汇总 系列,帮忙很大。文章有所有余的中央还指明。

2022 前端面试温习

HTML5、CSS3

HTML5

HTML5 新增个性
  • 语义化标签:headernavfootersection...
  • 媒体标签:audio音频、video 视频
  • 表单类型属性:emailnumber工夫控件color 色彩拾取器placeholderautofocus 主动获取焦点...
  • cavas 绘图
  • web 存储:localStoragesessionStorage
行内元素、块级元素有哪些

行内元素:aspanimginput...

块级元素:divullioldtdhliph1-6

iframe 的优缺点

长处

  • 一成不变的吧嵌入网页展现进去
  • 减少代码的可重用
  • 用来加载速度较慢的内容

毛病

  • iframe 阻塞 onload 事件加载
  • 网页内容无奈被搜索引擎辨认,对 SEO 不敌对
  • 会产生很多页面,不利于治理
canvas 和 SVG 的区别

canvas:通过 javaScript 来绘制 2D 图形,是逐像素进行渲染

  • 依赖分辨率
  • 不反对事件处理
  • 可能以.png 或.jpg 的格局进行保留
  • 适宜做游戏

SVG:基于 XML 形容的 2D 图形语言,是矢量图

  • 不依赖分辨率
  • 反对事件处理
  • 适宜做大型区域渲染
回流重绘

回流 当 DOM 变动影响了元素,比方元素的尺寸、布局、显示暗藏等扭转了,须要重写构建。每个页面至多须要一次回流,就是在页面第一次加载的时候,这个时候肯定会产生回流。

重绘 当一个元素的外观发生变化,然而没有扭转布局,从新渲染元素的外观。比方background-colorcolor

回流必将引起重绘,而重绘不肯定会引起回流

如何防止回流重绘:

  • 防止应用 table 布局
  • 尽可能在 DOM 树的最末端扭转class
  • 防止设置多层内联款式
  • 开启 GPU 减速
  • 将动画成果利用到 position 属性为 absolute 或者 fixed 的元素上
src 和 href 的区别

srcsrc 指向内部资源的地位,将指向的内容嵌入到文档中以后标签所在的地位,如 js 脚本、img图片、iframe

href用于在以后文档和援用资源之间确立分割,个别是用在 linka 等元素

CSS3

CSS3 新增个性
  • 新增 CSS 选择器、伪类
  • 特效:text-shadowbox-shadow
  • 突变:gradient
  • 旋转适度:transformtranstion
  • 动画:animation
盒模型

盒模型都是有四局部组成:contentpaddingbordermargin

规范盒模型和 IE 盒模型的区别在于设置 widthheight时,对应的范畴不同

  • 规范盒模型的 widthheight 只蕴含了content
  • IE 盒模型的 widthheight 蕴含了bordermarginpadding

通过批改元素的 box-sizing 属性来扭转元素的盒模型

  • box-sizeing: content-box示意规范盒模型(默认值)
  • box-sizeing: border-box示意 IE 盒模型(怪异盒模型)
trastion 和 aniamtion 的区别

transtion:属于适度属性,强调适度,须要一个事件进行触发(如鼠标进入、来到)相似 flash 的补间动画,设置一个开始帧和完结帧

aniamtion:属于动画属性,它的实现不须要触发事件,设定好后可主动执行,且能够循环播放。也是相似补间动画,然而能够设置多个关键帧

元素程度垂直居中
  • 相对定位:先将元素的左上角通过 top:50%left:50%定位到页面的核心,而后再通过 translate 来调整元素的中心点到页面的核心。

    .parent {position: relative;} 
    .child {    
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%,-50%);
    }
  • 相对定位:设置四个方向的值都为 0,并将 margin 设置为auto,因为宽高固定,因而对应方向实现平分,能够实现程度和垂直方向上的居中。

    .parent {position: relative;}
     
    .child {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        margin: auto;
    }
  • 应用 flex 弹性盒子布局,通过 align-items:centerjustify-content:center设置容器的垂直和程度方向上为居中对齐,而后它的子元素也能够实现垂直和程度的居中。

    .parent {
        display: flex;
        justify-content:center;
        align-items:center;
    }
p、em、rem 的区别
  • px 固定像素单位,不能随其它元素的变动而变动
  • em是绝对于父元素的单位,会随着父元素变动而变动
  • rem是绝对于根元素html,它会随着 html 元素变动而变动

rem罕用在挪动端我的项目,设置根元素的 fong-size,其它元素会随着根元素的变动而变动,从而达到不同手机屏幕的自适应大小。通常会配合postcss-pxtorem 插件进行应用

如何解决 1px 问题
  • 间接写0.5px
  • 利用伪元素,先放大再放大
  • 应用 viewport 缩放来解决
什么是 BFC 布局,如何创立 BFC 布局?

BFC 布局为 块格式化上下文(Block Formatting Context,BFC),是 CSS 布局的一个概念,外面的元素不会影响到里面的元素。

创立 BFC

  • 元素设置浮动:float有值并不为空
  • 元素设置相对定位: position(absolute、fixed)
  • overfilow值为:hiddenautoscroll
  • display值为:inline-blocktable-celltable-captionflex

BFC 作用

  • 解决 margin 重叠问题:因为 BFC 是一个独立的区域,外部元素和内部元素互不影响,将两个元素变为 BFC,就解决了 margin 重叠问题
  • 创立自适应两栏布局:能够用来创立自适应两栏布局,右边宽高固定,左边宽度自适应。
  • 解决高度塌陷问题:在子元素设置浮动后,父元素会产生高度的塌陷,也就是父元素的高度为 0 解决这个问题,只须要将父元素变成一个 BFC。
link 和 @import 的区别
  • link是 HTML 提供的标签,不仅能够加载 CSS 文件,还能够定义 RSS、rel 连贯属性等
  • @import是 CSS 提供等语法规定,只有导入样式表带作用。
  • link标签引入的 CSS 被同时加载,而 @import 引入的 CSS 将在页面 加载结束 后被加载
  • @import是 CSS2.1 才有的语法,存在兼容性,而 link 作为 HTML 标签不存在兼容性问题
CSS 选择器优先级
  • @important
  • 内联款式
  • ID 选择器
  • 类选择器 / 属性选择器 / 伪类选择器
  • 元素选择器 / 伪元素选择器
  • 关系选择器 / 通配符选择器

JS 根底

根底数据类型

stringnumberbooleanobjectfunctionundefinednullsymbol

nullundefined 的区别:null示意对是一个空的对象 (object)、undefined 是申明了但没赋值,在应用 typeo f 检测类型时,nul l 为objectundefinedundefined

null == undefined // true

null === undefined //false

值类型(根本数据类型):stringnumberbooleanundefinednullsymbol

援用类型:objectfunctionarray

值类型和援用类型区别:

  • 值类型保留在 中,占用空间固定,当一个办法执行时,每个办法都会创立本人的内存栈,办法中定义的变量会寄存在这个内存栈中。当办法执行完结时,这个内存栈也会被销毁。所以,栈中存储的是根底变量。而援用变量存储在栈中是指向堆中的数组或对象的援用地址。这也就是为何批改援用类型总会影响到其它指向这个地址的援用变量。
  • 值类型能够应用 typeof 进行数据类型检测
  • 援用类型保留在 中,占用空间不固定。创建对象会保留到堆内存中,这个内存不回随着办法完结而销毁,因为这个对象还可能被另外一个变量所援用,只有当一个对象没有被任何变量援用时,零碎的垃圾回收机制会将它回收。
  • 援用类型应用 instanceof 检测数据类型
  • 应用 new()办法结构进去的对象是援用类型
闭包

闭包就是可能读取到其它函数外部变量的函数,创立一个最简略的闭包,就是在一个函数外部创立另外一个函数,创立的函数能够拜访到以后函数的局部变量。

闭包长处:

  • 创立全局公有变量,防止变量全局净化
  • 能够实现封装、缓存等

闭包毛病:

  • 创立的变量不能被回收,容易耗费内存,使用不当会导致内存溢出
变量晋升、作用域、作用域链
变量晋升

js 代码在解析的时候,会将所有的变量函数,晋升到代码的最下面。变量晋升,晋升的只是变量申明,并不会吧变量赋值晋升上来

console.log(i) // 4
var i = 4
作用域

作用域是一个变量或函数的可拜访范畴,作用域管制着变量或函数的可见性和生命周期

  1. 全局作用域:能够全局拜访

    • 最外层函数和最外层定义的变量领有全局作用域
    • window 上的对象属性办法领有全局作用域
    • 为定义间接复制的变量主动申明领有全局作用域
    • 过多的全局作用域变量会导致变量全局净化,命名抵触
  2. 函数作用域:只能在函数中拜访应用哦

    • 在函数中定义的变量,都只能在外部应用,内部无法访问
    • 内层作用域能够拜访外层,外层不能拜访内存作用域
  3. ES6 中的块级作用域:只在代码块中拜访应用

    • 应用 ES6 中新增的 letconst 什么的变量,具备块级作用域,块级作用域能够在函数中创立(由 {} 包裹的代码都是块级作用域)
    • letconst申明的变量不会变量晋升,const也不能反复申明
    • 块级作用域次要用来解决由变量晋升导致的变量笼罩问题

      var i = 3
      function fnc() {console.log(i);
        var i = 6;
      }
      fnc() // undefined
作用域链

变量在指定的作用域中没有找到,会顺次向上一层作用域进行查找,直到全局作用域。这个查找的过程被称为作用域链。

call、apply、bind 区别
  • 都能够用作扭转 this 指向
  • callapply 的区别在于传参,callbind都是传入对象。apply传入一个数组。
  • callapply扭转 this 指向后会立刻执行函数,bind在扭转 this 后返回一个函数,不会立刻执行函数,须要手动调用。
new 操作符干了什么操作
  1. 创立一个空对象
  2. 设置原型,将对象的原型设置到函数的 prototype 对象上
  3. 扭转 this 指向,将 this 指向该对象,并执行构造函数。
  4. 判断函数的返回类型,如果是值类型,返回创立的对象。如果是援用类型,返回这个援用类型的对象。
原型、原型链
  • 原型: 每个对象在外部初始化的时候,都会初始化一个 prototype 原型属性,而对象的 _proto_属性,指向它的原型对象。
  • 原型链: 当咱们拜访英国对象属性时,如果这个属性不存在,那么就会去它的原型对象上进行查找,而这个原型对象又会有本人的原型,会这样始终查找,晓得找到顶级对象 object 为止。这个查找的过程被称为原型对象。
继承
原型链继承

利用对象的原型链,将子类 Son.prototype 指向父类的构造函数创立进去的实例对象new Person()

🌰

function Person() {...};
  
function Son() {....};

// 要害代码
Son.prototype = new Person();

长处:

  • 子类能够继承父类构造函数、原型上的属性办法

毛病:

  • 父类援用类型的实例对象被共享,容易造成批改的凌乱。
  • 创立子类的时候不能向父类传参
构造函数继承

利用 .call() 或者 .apply() 办法,在子类中借用父类的构造函数,初始化父类构造函数。

🌰

function Person(name) {...};
  
function Son(name) {
    // 要害代码  
  Person.call(this, name)
  ...
}

长处:

  • 子类在继承父类时,能够向父类构造函数中传参。
  • 不会造成子类权势之间援用属性共享。

毛病:

  • 只能继承父类构造函数中的属性办法,无法访问原型上的办法。
  • 每个子类都会创立一个父类正本
组合继承

组合继承,将原型链继承和构造函数继承交融在一起。

🌰

function Person(name) {...};
  
function Son(name) {
  // 借用构造函数继承要害代码
    Person.call(this, name);
};

// 原型链式继承要害代码
Son.prototype = new Person();
// 将子类的构造函数指向本人
Son.prototype.constructon = Son;

长处:

  • 联合后面两种继承形式的长处,子类的实例能够拜访到父类原型上的属性办法
  • 子类的实例之间不会被共享

毛病:

  • 调用了两次父类构造函数
原型式继承

用函数包装一个对象,返回这个函数的调用(也就是 ES5 的 Object.create 的模仿实现),将传入的对象作为创建对象的原型

🌰

function create(obj) {
  // 创立一个空的的构造函数
    function F() {};
  
  // 将空的构造函数原型指向传递进来的对象
  F.prototype = obj;
  
  // 返回一个实例对象
  return new F();}


const obj = {
  name: 'zs',
  ...
};

const newObj1 = create(obj);
const newObj2 = create(obj);

优缺点和原型链式继承一样,援用类型还是会被共享。

寄生式继承

在原型式继承根底上,在函数外部来做加强函数,返回对象。

🌰

function createObj(obj){
  // 获取继承的子类对象,也就是下面的 create 办法实现
  const newObj = Object.create(obj);
  
  // 函数加强
  newObj.say = function() {...}
    
  // 返回对象
  return newObj;
}

相似原型式继承,但在原有的根底上能够自定义属性办法,仍旧没有解决援用值被共享问题。(跟借用构造函数模式一样,每次创建对象都会创立一遍办法。)

寄生组合式继承

联合寄生继承和组合式继承优缺点,组合式继承毛病为调用了两次父类构造函数,长处为解决了援用值被共享问题。而寄生式继承毛病为没有解决援用值被共享问题,只有将两者联合就失去完满的继承形式。

🌰

function createObj(son, parent) {
  // 寄生式继承,利用父类构造函数的原型对象创立出一个新的对象,解决组合式继承创立两个父类问题
  const newObj = Objcet.create(parent.prototype);// 将新对象的 constructor 构造函数执行子类
    newObj.constructor = son;
  
  // 将子类构造函数的原型指向心的  原型式继承
  son.protoytype = newObj; 
  
}

function Person(name) {...};

function Son(name) {
  // 构造函数继承
  Person.call(this, name);
  ...
};
  
  
// 实现继承
createObj(Son, Person)
// 更简洁的形式  在组合式继承的根底上  间接将 son 的原型通过 API 指向 person 的原型
Son.prototype = Object.create(Person.prototype);

const obj1 = new Son('zx');
const obj2 = new Son('lw');
深拷贝、浅拷贝
浅拷贝

浅拷贝只是复制对象的值类型,通过 Object.assign 或者扩大运算符即可实现

深拷贝

通过递归实现

function deepClone(obj) {
  // 判断是否为对象
  if (!obj || typeof obj !=='object') return obj;
  
  // 依据 obj 类型创立数组还是对象
  let newObj = obj instanceof Object ? {} : [];
  
    // 循环遍历 obj,解决子元素为对象,递归拷贝
  for (key in obj) {if (obj.hasOwnProperty(key)) {newOb[key] = deepClone(obj[key])
    };
  };
  
  return newObj;
};
事件循环机制 EventLoop(浏览器)
栈、队列了解
  • 栈(Stack)中的工作 后进先出,js 中的执行栈是一个存储函数的栈构造,栈中的工作执行遵循先进后出的准则顺次执行。
  • 队列(Queue)中的工作 先进先出,js 运行时创立一个工作队列,用来解决列表(事件)和待执行的回调函数
宏观工作、宏观工作

js 中的工作分为两种:宏观工作 (MacroTask|Task) 宏观工作(MicorTask)

  • 宏工作:script 全副代码setTimeoutsetIntervalI/OUI Rendering
  • 微工作:Promise.thenProcess.nexTick(Node 独有)MutationObserver
同步工作、异步工作

js 有一个 主线程 和一个 执行栈(调用栈),所有的工作都会放到执行栈中期待被主线程执行。

js 代码在执行时,所有函数都会压入 执行栈 中。同步工作会依照 后进先出 准则顺次执行,直到执行栈清空。异步工作会在异步工作有了后果后,将注册的回掉函数放入异步工作队列中,期待主线程闲暇后(执行栈中的同步工作执行结束)

异步队列中的工作又分为 宏观工作 宏观工作,当以后执行栈清空后,解决异步队列中的工作时,首先会判断是否有宏观工作可执行,如果有就将宏观工作压入执行栈中执行。当宏观队列中的工作在执行栈被执行结束,再来异步队列中将宏观工作放入执行栈。

简略的来说:

  1. 执行同步代码,这属于宏观工作
  2. 所有代码执行结束,执行栈清空,执行异步队列中工作
  3. 异步队列中,先执行宏观工作
  4. 宏观工作执行结束,再执行宏观工作
节流防抖

节流(throttle):在 n 秒内只容许执行一次,

防抖(debounce):在 n 秒内屡次触发但不执行,而是在 n 秒后执行,如果 n 秒内触发则从新计算。

事件冒泡、事件委托

事件产生的三个阶段:捕捉阶段 指标阶段 冒泡阶段

  • 事件冒泡:在一个对象上触发某类事件,如果此对象绑定了事件,就会触发事件,如果没有,就会向这个对象的父级对象流传,最终父级对象触发事件。

    • 如何阻止:

      • 一般浏览器:event.stopPropagation()
      • IE 浏览器:event.cancelBubble = true;
  • 事件委托:利用浏览器事件冒泡机制。事件在冒泡的过程中会传到父节点,并且父节点能够通过事件对象获取到指标节点,能够吧子节点的监听函数定义在父节点上,由父节点的监听函数对立解决多个子元素的事件

    • 事件委托能够不必要为每一个子节点都绑定监听事件,缩小内存上的耗费。
    • 应用事件委托还能够实现事件的动静绑定,比方新增一个子节点,并不需要为此独自减少一个监听事件,能够由父元素中的监听函数来解决。
对 DOM 元素进行增删改查
 document.createElement()
element.removeAttribute()
element.removeChild()
element.innerHTML()
element.setAttribute()
getElementById()
getElementsByClassName()
getElementsByTagName()
querySelector()
querySelectorAll()
ajax、axios、fetch 区别

ajax

  • 基于原生的 XHR 开发
  • 自身针对 MVC 编程,不合乎当初前端 MVVM 潮流

axios

  • 从浏览器中创立XMLHttpRequest
  • 反对promise
  • 反对申请拦击和响应拦挡
  • 从 node.js 创立 http 申请
  • 客服端反对避免CSRF/XSRF

fetch

  • 浏览器原生实现的申请形式,ajax 的替代品
  • 只对网络申请报错,对 400、500 都当做胜利的申请,须要封装
  • fetch 默认不会带 cookie,须要增加配置项
  • fetch 不反对 abort,不反对超时管制,应用 setTimeout 及 Promise.reject 的实现的超时管制并不能阻止申请过程持续在后盾运行,造成了量的节约
  • fetch 没有方法原生监测申请的进度,而 XHR 能够

ES6

var、let、const 区别

  • var申明变量能够反复申明,而 let 不能够
  • var是不受限于块级作用域,而 let 受限
  • var存在变量晋升,letconst 不存在变量晋升
  • cons t 申明的变量不可变
  • const申明之后必须赋值,否则会报错

Promise

Promise是异步编程的一种解决方案,将异步操作以同步操作的流程表达出来,防止了层层嵌套的回调函数。

它有三种状态

  • pending初始状态
  • fulfilled操作胜利
  • rejected操作失败。

Promise状态扭转只有两种可能

  • pending——>fulfilled
  • pending——>rejected

Promise构造函数接管一个参数和一个带有 resolvereject参数的回调函数。

  • resolve的作用是将 Promise 状态从 pending 变为fulfilled,在异步操作胜利时调用,并将异步后果返回,作为参数传递进来
  • reject的作用是将 Promise 状态从 pending 变为rejected,在异步操作失败后,将异步操作谬误的后果,作为参数传递进来

Promise实例办法

  • promise.then() 对应 resolve 胜利的解决
  • promise.catch()对应 reject 失败的解决
  • promise.call()将多个 Promise 实例,包装成一个新的 Promise 实例,返回的实例就是一般的 Promise。有一个失败,代表该Primise 失败。当所有的子 Promise 实现,返回值时全副值的数组
  • promise.race()相似promise.all(),区别在于有任意一个实现就算实现(例如:将异步和定时器放在一起,设置申请超时)

箭头函数和一般函数的区别

  • 箭头函数时 匿名函数,不能作为构造函数,不能应用new
  • 箭头函数不绑定arguments
  • 箭头函数没有本人的 this,将所在的上下文的this 作为本人的 this
  • 没有prototype
  • call()applay()bind()办法不能扭转箭头函数中的 this 指向

forEach 和 map 的区别

  • forEach返回值是undefined,不能够链式调用
  • map()返回一个新的数组,不扭转原数组。forEach扭转原数组。

Set、Map 的区别

Set
  • 创立: new Set([1, 1, 2, 3, 3, 4, 2])
  • add(value):增加某个值,返回 Set 构造自身。
  • delete(value):删除某个值,返回一个布尔值,示意删除是否胜利。
  • has(value):返回一个布尔值,示意该值是否为 Set 的成员。
  • clear():革除所有成员,没有返回值。
Map
  • set(key, val):Map 中增加新元素
  • get(key): 通过键值查找特定的数值并返回
  • has(key): 判断 Map 对象中是否有 Key 所对应的值,有返回true, 否则返回false
  • delete(key): 通过键值从 Map 中移除对应的数据
  • clear(): 将这个 Map 中的所有元素删除
区别
  • Map是一种键值对的汇合,和对象不同的是,键能够是任意值
  • Map能够遍历,能够和各种数据格式转换
  • Set是相似数组的一种的数据结构,但在 Set 中没有反复的值

谈谈你对 ES6 对了解

  • 解构赋值
  • 扩大运算符
  • 模版字符串
  • 箭头函数
  • async/await
  • Class
  • 引入 Moldule 语法
  • class

Vue

基础知识

MVVM

MVVM是一种软件架构模式,在 vue 中 M 代表 model 层(数据模型),负责数据模型。V 代表 View 层(视图层),VM 代表 ViewModel(视图模型),它是ModelView之间的桥梁,数据会绑定到 viewModel 层,并主动将数据渲染到页面层,视图变动时会告诉 viewModel 更新数据

Vue 生命周期

创立前后:

  • beforeCreated(创立前): 数据观测和初始化事件还未开始,不能拜访 datacomputedwatchmethods 上的数据办法。
  • created(创立后):实例创立实现,能够拜访 datacomputedwatchmethods 上的数据办法,但此时渲染节点还未挂在到 DOM 上,所以不能拜访。

挂载前后:

  • beforeMounted(挂载前): Vue 实例还未挂在到页面 html 上,此时能够发动服务器申请
  • mounted(挂载后):Vue 实例曾经挂在结束,能够操作 DOM

更新前后:

  • beforeUpdate(更新前): 数据更新之前调用,还未渲染页面
  • updated(更新后):DOM 从新渲染,此时数据和界面都是新的。

销毁前后:

  • beforeDestoryed(销毁前):实例销毁前调用,这时候可能获取到this
  • destoryed(销毁后):实例销毁后调用,实例齐全被销毁。
watch 和 computed 的区别

watch:监听属性,用来监听数据的变动,没有缓存,当监听到的数据发生变化时都会执行毁掉函数

computed:计算属性,被监听的值有缓存,只有它依赖的属性值发生变化后,下一次获取 computed 的值时才会从新计算 computed 的值。(只有依赖发生变化后才会从新计算)

v-for 中 key 的作用

key 是为了更高效的比照虚构 DOM 中的每个节点是否雷同,防止页面更新时反复更新节点

v-if 和 v -show 的区别

v-if元素不可见 删除 dom 元素

v-show元素可见 通过设置元素的 display:none 款式属性

组件中的 data 为什么是一个函数

因为对象是一个援用类型,如果 data 时一个对象的状况下会造成多个组件共用一个 data,data 为一个函数,每个组件都会有本人的公有数据空间,不会烦扰其余组件的运行。

Vue 组件通信
父子组件

父传子

  • props
  • $children
  • $refs

子传父

  • $emit
  • $parent
兄弟组件
  • provied
  • inject
  • eventBus
  • Vuex
Vuex 的根本应用

Vuex 用于 vue 中的数据状态治理,有五种属性:

  1. stateVuex的根本数据,用于存储变量
  2. getter:从 state 派生进去的数据,当相遇 state 的计算属性,在这里能够对 state 数据进行过滤、筛选等操作
  3. mutation:提交更新 state 数据的办法
  4. action:和 mutation 性能类似,都是用来提交更新,但 action 提交的是 mutation,而不是间接变更数据,并且action 能够蕴含异步操作
  5. module:模块化 Vuex,每个模块都有本人的statemutationactoiongetter
mutation 和 action 的区别
  • mutation更专一于批改state,必须是同步执行。
  • action提交的是mutation,而不是间接更新数据,能够是异步的。
  • action能够整合多个mutation
Vuex 和 localstory 的区别
  • Vuex存储在内存中,页面敞开刷新就会隐没。而 localstorage 存储在本地,读取内存比读取硬盘速度要快
  • Vuex利用于组件之间的传值,localstorage次要用于不同页面之间的传递
  • Vuex是响应式的,localstorage须要刷新
路由守卫
  • 全局前置钩子:beforeEachbeforeResolveafterEach
  • 路由独享守卫:beforeEnter
  • 组件内钩子:beforeRouterEnterbeforeRouterUpdatebeforeRouterLeave
hash 和 history 的区别
hash

hash 模式是 vue 开发中的默认模式,地址栏 URL 携带 ## 后为路由。

原理是通过 onhashchange() 事件监听路由 hash 的变动,这个益处就是当 hash 值发生变化,不须要向后端发动申请,window就能够监听事件的扭转,并依照规定加载项对应的代码。除此之外,hash值的变动对应的 URL 都会被浏览器记录下来,这样就能实现浏览器历史页面的后退后退。

history

vue 还提供 history 模式,在 history 模式下 URL 中没有#,相比 hash 模式更加难看。然而须要后盾配置反对。

history的原理是利用 HTML5 中 hostory 提供的 pushStatereplaceState 这两个 API,这两个 API 记录了浏览器历史栈,并且当在批改 URL 时不会触发页面刷新和后盾申请。

动静路由
定义形式
  • params 传参

    • 路由配置:/index/:id
    • 路由跳转:this.$router.push({name: 'index', params: {id: "zs"}});
    • 路由参数获取:this.params.id
    • 最初造成的路由:/index/zs
  • query 传参

    • 路由配置:/index失常的路由配置
    • 路由跳转:this.$rouetr.push({path: 'index', query:{id: "zs"}});
    • 路由参数获取:this.query.id
    • 最初造成的路由:/index?id=zs
$router 和 $route
  • $router是指整个路由对象,能够应用 this.$router.push({name: ;index'}) 进行页面跳转
  • $route时指以后页面的路由对象,能够应用 this.$route.parmas.id 来获取以后路由对象传递进来的参数
Vue 性能优化

原理常识

双向绑定原理

data 在初始化的时候,会实例化一个 Observe 类,在它会将 data 数据进行递归遍历,并且通过 definereactive 办法,这个办法通过 Object.defineProperty 办法,给每个值增加上一个 getter 和一个 setter。在数据读取的时候会触发 getter 进行依赖(Watcher)收集,当数据扭转时,会触发setter,对刚刚收集的依赖进行触发,并且更新watcher 告诉视图进行渲染。

依赖收集

依赖收集产生在 defineReactive() 办法中,在办法内 new Dep() 实例化一个 Dep() 实例,而后在 getter 中通过 dep.depend() 办法对数据依赖进行收集,而后在 settter 中通过 dep.notify() 告诉更新。整个 Dep 其实就是一个观察者,吧收集的依赖存储起来,在须要的时候进行调用。在收集数据依赖的时候,会为数据创立一个 Watcher,当数据产生扭转告诉每个Watcher,由Wathcer 进行更新渲染。

Object.defineProperty()数据劫持缺点

该办法只能监听到数据的批改,监听不到数据的新增和删除。vue2 中会对数组的新增删除办法 push、pop、shift、unshift、splice、sort、reserve 通过重写的模式,在拦挡外面进行手动收集触发依赖更新。

在 vue2 中,须要数据里增加或删除时,应用 vue.$set/vue.$delete 进行操作。

在 Vue3 中,改用 proxy 对对象进行代理,返回一个代理对象,只须要操作新对象就能够。

双向绑定原理

Vue 双向绑定是一个指令 v-model,能够将数据动静绑定到视图上,同时视图中变动也能够扭转改值。他的实质是 v-bindv-on 的语法糖。在 ⼀个组件上使⽤ v-model ,默认会为组件绑定名为 value 的 prop 和名为 input 的事件。

nextTick 的实现

vue 中的 nextTick 是浏览器 eventLoop 是利用。nextTick是将回调函数放到一个异步队列中,保障在异步更新 DOM 的 watcher 前面,从而获取到更新后的 DOM。

Vue 在更新 DOM 时是异步执行的。只有侦听到数据变动,Vue将开启 1 个队列,并缓冲在同一事件循环中产生的所有数据变更。如果同一个 watcher 被屡次触发,只会被推入到队列中一次。这种在缓冲时去除反复数据对于防止不必要的计算和 DOM 操作是十分重要的。nextTick办法会在队列中退出一个回调函数,确保该函数在后面的 dom 操作实现后才调用;

怎么了解 vue 中的虚构 DOM

虚构 DOM,就是用一个 JS 对象来形容一个 DOM 节点。Vue是数据驱动视图的,数据发生变化视图就要随之更新,在更新视图的时候不免要操作 DOM, 而操作实在DOM 又是十分消耗性能的,这是因为浏览器的规范就把 DOM 设计的非常复杂,所以一个真正的 DOM 元素是十分宏大的。VNode类中蕴含了形容一个实在 DOM 节点所须要的一系列属性,tag示意节点的标签名,text示意节点中蕴含的文本,children示意该节点蕴含的子节点等。

模版编译原理

模版编译次要过程:template ---> ast ---> render,别离对象三个办法

  • parse 函数解析 template
  • optimize 函数优化动态内容
  • generate 函数创立 render 函数字符串

调用 parse 办法,将 template 转化为 AST(形象语法树),AST 定义了三种类型,一种 html 标签,一种文本,一种插值表达式,并且通过 children 这个字段层层嵌套造成了树状的构造。

optimize办法对 AST 树进行动态内容优化,剖析出哪些是动态节点,给其打一个标记,为后续更新渲染能够间接跳过动态节点做优化。

generateAST 形象语法树编译成 render字符串,最初通过 new Function(render) 生成可执行的 render 函数

diff 算法逻辑

diff算法产生在视图更新阶段,也就是当数据发生变化的时候,diff会对新就虚构 DOM 进行比照,只渲染有变动的局部。

当数据发生变化的时候,依赖对应的 watcher 会告诉更新,生成一个新的 vnode,新的vnode 会去和旧的 vnode 进行比照更新。

整个更新的过程就是调用 path 函数,次要做了三件事:

  • 创立节点:新的 vnode 中有而旧的 vnode 中的节点,在旧 vnode 中进行创立
  • 删除节点:新的 vnode 中没有二旧的 vnode 中有,在旧的 vnode 中删除
  • 更新节点:新的 vnode 和旧的 vnode 中都有,以新的 vnode 位主,更新旧的vnode
new Vue 的流程

合并配置,调用一些初始化函数,触发生命周期钩子函数,调用 $mount 开启下一个阶段。

keep-live 原理

keep-alive是 Vue.js 的一个内置组件。它可能将不流动的组件实例保留在内存中,而不是间接将其销毁,它是一个形象组件,不会被渲染到实在 DOM 中,也不会呈现在父组件链中。

通过 include、exclude 来匹配和排除缓存,max定义缓存的下限。

keep-alive外部其实是一个函数式组件,没有 template 标签。在 render 中通过获取组件的 nameinclude、exclude进行匹配。匹配不胜利,则不须要进行缓存,间接返回该组件的 Vnode。

匹配胜利就进行缓存,获取组件的 keythis.cache中进行查找,如果存在就间接将缓存的组件实例笼罩到以后的 Vnode 上,而后将以后组件的 keykeys中进行删除,而后在 push(key) 增加到尾部,这样做是为了扭转 key 以后的地位,也就实现了 max 性能。

不存在的话,就须要对组件进行缓存。将以后组件 push(key) 增加到尾部,而后再判断以后缓存的 max 是否超出指定个数,如果超出间接将第一个组件销毁(缓存淘汰策略 LRU)。

LRU(Least recently used,最近起码应用)算法依据数据的历史拜访记录来进行淘汰数据,其核心思想是“如果数据最近被拜访过,那么未来被拜访的几率也更高”。

性能优化

网站优化

  • 应用浏览器缓存机制
  • 资源懒加载、预加载
  • 骨架屏
  • 正当应用雪碧图、字体图标、

代码优化

  • 缩小回流重绘
  • 缩小 DOM 的操作
  • 节流防抖
  • 应用事件委托
  • 将 CSS 文件放在头部、js 文件放在底部

申请优化

  • 应用 CDN 减速
  • 开启 nginx,Gzip 压缩
  • 应用强缓存、协商缓存
  • 缩小、合并申请

webpack 优化

  • 按需加载
  • 代码打包体积压缩
  • 移除 console
  • 压缩图片、字体等本地资源
  • 拆散 css 文件,独自进行打包

浏览器相干

跨域

浏览器的同源策略会导致跨域问题

同源策略

同源指的是:协定 端口号 域名 必须统一。

同源策略的目标次要是为了保障用户的信息安全,它只是对 js 脚本的一种限度,并不是对浏览器的限度,对于个别的 img、或者 script 脚本申请都不会有跨域的限度,这是因为这些操作都不会通过响应后果来进行可能呈现平安问题的操作

解决跨域问题
  • CORS:服务器开启跨域资源共享
  • JSONP:利用 JavaScript 标签不存在跨域限度,只反对 GET 申请
  • Nginx:反向代理

本地存储

Cookie
  • 存储小,只有 4k
  • 不同域之间不能共享
  • 不平安,容易被拦挡
SessionStorage
  • 存储在内存中,体积绝对较大
  • 页面敞开,数据会删除
  • 绝对 Cookie 平安
LocalStorage
  • 体积大,能够存储更多内容
  • 生命周期长,须要手动删除
  • 存储在硬盘,不会像 cookie 一样被申请携带

从输出一个 URL 地址到浏览器实现渲染的整个过程

  1. 浏览器输出 URL 并回车
  2. 浏览器查找以后是否有缓存
  3. DNS解析 URL 失去IP

    1. 浏览器 DNS 缓存
    2. host文件缓存
  4. 建设 TCP 连贯(三次握手)
  5. 发送 HTTP 申请
  6. 服务器解决申请,浏览器失去响应数据
  7. 浏览器解析渲染页面

    1. 解析 DOM 生成 DOM
    2. 解析 CSS 生成 CSS
    3. 合并 DOM 树和 CSS 树,生成渲染树
    4. 浏览器开始渲染页面(回流重绘产生在这个阶段)
  8. TCP连贯敞开(四次挥手)

网络协议、平安相干

TCP、UDP 协定

TCPUDP 都是在传输层定义的两种传输协定。基于 UDP 协定传输不能保证数据准确无误的送达,但 UDP 不仅能够反对一对一的传输方式,还能够反对一对一、一对多等模式。也不须要像 TCP 一样建设连贯,所以传输速度快。

TCP的目标是提供牢靠的数据,并且须要在传输前建设连贯(三次握手)。只反对一对一进行传输。

区别:

  • TCP协定牢靠,UDP协定不牢靠
  • TCP面向连贯,UDP采纳无连贯
  • TCP能够保证数据程序,UDP不能
  • TCP一对一传输,UDP能够一对多、多对一等模式

HTTP 和 HTTPS 区别

  • HTTP是明文传输,不平安。HTTPS基于 SSL 进行加密传输,比拟平安。
  • HTTPS须要 CA 证书,HTTP不须要。
  • HTTP端口为 80HTTPS 端口为443

HTTP 状态码

  • 1XX: 申请正在解决
  • 2XX:失常状态码

    • 200:申请解决胜利
    • 201:申请胜利并且服务器创立了新资源
    • 202:服务器曾经接管申请,但尚未解决
  • 3XXX:重定向状态

    • 301:申请重定向
    • 302: 长期重定向
    • 303: 长期重定向,应用 get 申请新的 url
    • 304:浏览器缓存相干
  • 4XX:谬误状态码

    • 400: 服务器无奈了解申请格局,须要批改申请内容后再次发动申请
    • 401: 申请未受权
    • 403: 禁止拜访
    • 404: 服务器上无奈找到申请资源
  • 5XX:服务器谬误

    • 500: 服务端谬误
    • 503: 服务器临时无奈解决申请

HTTP 三次握手、四次挥手

三次握手

三次握手是在建设 TCP 连贯时,客户端和服务端总共发送三个包。进行三次握手的次要目标就是为了确认单方的承受能力和发送能力都是失常的,为前面传输牢靠数据做筹备。

报文:

  • 序号:示意发送的数据字节流,确保 TCP 传输有序,对每个字节编号
  • 确认序号:发送方期待接管的下一序列号,接管胜利后的数据字节序列号加 1。只有 ACK=1 时才无效。
  • ACK:确认序号的标记,ACK=1示意确认号无效,ACK=0示意报文不含确认序号信息
  • SYN:连贯申请序号标记,用于建设连贯,SYN=1示意申请连贯
  • FIN:完结标记,用于开释连贯,FIN=1示意敞开本方数据流

三次握手:

  1. 第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN,此时客户端处于 SYN_SEND 状态。
  2. 务器收到客户端的 SYN 报文之后,会以本人的 SYN 报文作为应答,并且也是指定了本人的初始化序列号 ISN。同时会把客户端的 ISN + 1 作为 ACK 的值,示意本人曾经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。
  3. 客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,示意曾经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状 态,此时,单方已建设起了连贯。
四次挥手
  1. 客户端会发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。
  2. 服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明曾经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。
  3. 如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
  4. 客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为本人 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。须要过一阵子以确保服务端收到本人的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于敞开连贯了,处于 CLOSED 状态。
为什么须要四次挥手

因为当服务端收到客户端的 SYN 连贯申请报文后,能够间接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN报文是用来同步的。然而敞开连贯时,当服务端收到 FIN 报文时,很可能并不会立刻敞开 SOCKET,所以只能先回复一个ACK 报文,通知客户端,“你发的 FIN 报文我收到了”。只有等到我服务端所有的报文都发送完了,我能力发送 FIN 报文,因而不能一起发送。故须要四次挥手。

HTTP 缓存

强缓存

应用强制缓存策略,如果缓存资源无效,就间接应用缓存资源,不须要向服务器发送申请。强制缓存通过两种形式来设置,在 request headers 中的 Expires 属性和 Cache-Contorl 属性。

Expires属性,指定资源的过期工夫。在过期工夫以内,改资源能够被缓存应用,不须要向浏览器发送申请。这个工夫依赖于服务器工夫,会存在服务器工夫和客户端工夫不统一。

Cache-Control属性:

  • private:仅浏览器能够缓存
  • public:浏览器和代理服务器都能够缓存
  • max-age=xxx 过期工夫,单位为秒
  • no-cache 不进行强缓存,但会有协商缓存
  • no-store 不强缓存,也不协商缓存

如果 request header 中,Cache- Control的值中有max-age=xxx,这个时候走强缓存。如果值为no-cache,表明没有命中,走协商缓存。如值为no-store,不应用缓存。

协商缓存

如果没有命中强制缓存,在设置协商缓存状况下,先向服务器发送一个申请,如果资源没有产生批改,则返回一个 304 的状态,让浏览器应用本地的缓存正本。如果资源产生批改,则返回批改后的资源。在 request headers 中的 Etag 属性和 Last-Modified 属性,来进行设置。其中,ETage优先于Last-Modified

命中协商缓存条件:

  • Cache-Control: no-cache
  • max-age工夫过期

Last-Modified(文件的批改工夫):

服务器在响应头中增加 Last-Modified 属性,来指出资源最初一次批改工夫。当浏览器发动申请时,会在 request headers 中增加一个 If-None-Match 属性,值为上一次申请的资源返回的 Last-Modified 值。服务端会通过这个属性和资源最初一次批改工夫进行比照,以此来判断资源是否批改。如果资源没有批改,申请返回 304 状态,客户端应用本地缓存。如果资源有批改,则返回批改的资源。

这种形式有一个毛病,Last-Modified标记的工夫只能准确到秒。

ETag(文件改变):

同样在服务器返回资源的时候,在头信息中增加 ETag 属性,这个属性是资源的惟一标识符。当资源扭转时,这个值也会扭转。在一下次申请资源时,会在 request headers 中增加一个 If-None-Match 属性,值为上一次申请的资源返回的 ETag 值。服务端会通过这个属性和资源最初一次批改工夫进行比照,以此来判断资源是否批改。这种形式比 Last-Modified 更加精确。

区别
  • 强缓存优先级高于协商缓存
  • 强缓存不须要发申请,协商缓存须要。
  • 强缓存返回的状态码为200,协商缓存返回304
  • ctrl+F5 强制刷新会跳过所有缓存,而 F5 刷新跳过强缓存,然而会查看协商缓存。

POST 和 GET 的区别

  • 传递的参数不同,POST传递的参数在 request body 中,GET传递的参数在 url 后拼接
  • POST绝对 GET 申请平安
  • GET申请长度有限度,POST没有
  • GET申请会被浏览器被动缓存,POST不会,要手动设置
  • GET申请个别用于查问,POST个别用于提交某种信息进行某些批改操作

XSS、csrf 攻打

XSS(跨站脚本攻打)

Xss(cross-site scripting) 是一种代码注入攻打,攻击者往 Web 页面里插入歹意 html 标签或者 javascript 代码。在骗取用户点击后获取用户,获取用户信息。

防止形式:

  • url参数通过 encodeURIComponent 办法进行本义
  • 尽量不应用 InnerHtml 插入 HTML 内容
  • 对用户输出的中央和变量都须要仔细检查长度和对”<”,”>”,”;”,”’”等字符做过滤
CSRF(跨站申请伪造)

CSRFCross-site request forgery)攻击者盗用你的身份信息,向被攻打网站发送跨站申请。利用受害者在被攻打网站曾经获取的注册凭证,绕过后盾的用户验证,达到假冒用户对被攻打的网站执行某项操作的目标。

防止形式:

  • 增加验证码验证
  • 应用token

    • 服务端给用户生成一个token,加密后传递给用户
    • 用户在提交申请时,须要携带这个token
    • 服务端验证 token 是否正确

前端工程化

webpack 的 loader 和 plugin 的区别

loader

loader 是导出一个函数的 javascript 模块,webpack 原生是只能解析 js 文件,如果想将其余文件也打包的话,就会用到loader。如 babel-loader、Css-loader、image-loader、url-loader、Saas-loader…

plugin

Plugin 能够扩大 webpack 的性能,让 webpack 具备更多的灵活性。在 Webpack 运行的生命周期中会播送出许多事件,Plugin 能够监听这些事件,在适合的机会通过 Webpack 提供的 API 扭转输入后果。如 html-webpack-plugin、mini-css-extract-plugin、uglifyjs-webpack-plugin

手写系列🤮

节流防抖

new 操作符

call、bind、apply 实现

公布订阅模式

class EventEmitter {constructor() {
    // 事件列表
    this.eventList = {};}

  // 监听
  on(name, callBack) {
    // 以 name 为 key  创立容器   如果有容器就不必创立
    if (!this.eventList[name]) {this.eventList[name] = []}

    // 把事件放入容器
    this.eventList[name].push([callBack])
  };

  // 触发
  emit(name, data) {if (!this.eventList[name]) {return new Error('没有找到事件!')
    };

    // 从容器中取出事件进行调用
    this.eventList[name].forEach((item) => {item(data)
    })
  };

  // 只触发一次
  once(name, callBack) {if (!this.eventList[name]) return;
    // 利用 off  在 callBack 执行后  敞开订阅
    function onceFn(callBack) {callBack();
      this.off(name, callBack);
    };
    this.on(name, onceFn)
  };

  // 敞开监听  若第二个参数没有  移除 name 下所有的事件
  off(name, callBack) {if (!this.eventList[name]) return;

    if (callBack) {
      // 只移除对应的 callBack
      this.eventList[name] = this.eventList[name].filter((item) => {return item !== callBack});

      // name 容器长度为 0 间接删除整个 name 事件订阅公布
      if (this.eventList[name].length === 0) {delete this.eventList[name];
      };
    } else {
      // 没有 callBack  间接删除整个 name 事件订阅公布
      delete this.eventList[name];
    };

  };

};

函数柯里化实现

promise

实现一个队列

数组去重

深浅拷贝

替换两个变量的值

数组扁平化

输入后果

闭包

var name = "The Window";   
  var object = {   
    name : "My Object",   
    getNameFunc : function(){return function(){return this.name;};   
    }   
};   
alert(object.getNameFunc()());  //"The Window"
function aaa(){
 var a=0;
 function bbb() {
  a++;
  alert(a);
 }
 return bbb
}
var ccc=aaa();
ccc();  // 后果为 1
ccc();  // 后果为 2
var ddd=aaa();
ddd();  // 后果为 1
ddd();  // 后果为 2 

github 同步

参考:

2021」高频前端面试题

2021 年我的前端面试筹备

震惊!前端 300 根底面试题 + 答案、分类学习整顿(良心制作)继续更新

高级知识点

退出移动版