一个在教育行业苦干两年的前端菜鸟,到职后就在筹备温习面试,记录一下这次前端温习过程。前端常识是在是太多,继续更新中 … 心愿对真正找工作的你有所帮忙,文末我整顿了一下面试文章,感兴趣的能够看看,尤其是 2022 高频前端面试题汇总 系列,帮忙很大。文章有所有余的中央还指明。
2022 前端面试温习
HTML5、CSS3
HTML5
HTML5 新增个性
- 语义化标签:
header
、nav
、footer
、section...
- 媒体标签:
audio
音频、video 视频
- 表单类型属性:
email
、number
、工夫控件
、color 色彩拾取器
、placeholder
、autofocus 主动获取焦点...
- cavas 绘图
- web 存储:
localStorage
、sessionStorage
行内元素、块级元素有哪些
行内元素:a
、span
、img
、input...
块级元素:div
、ul
、li
、ol
、dt
、dh
、li
、p
、h1-6
iframe 的优缺点
长处:
- 一成不变的吧嵌入网页展现进去
- 减少代码的可重用
- 用来加载速度较慢的内容
毛病:
- iframe 阻塞 onload 事件加载
- 网页内容无奈被搜索引擎辨认,对 SEO 不敌对
- 会产生很多页面,不利于治理
canvas 和 SVG 的区别
canvas:通过 javaScript 来绘制 2D 图形,是逐像素进行渲染
- 依赖分辨率
- 不反对事件处理
- 可能以.png 或.jpg 的格局进行保留
- 适宜做游戏
SVG:基于 XML 形容的 2D 图形语言,是矢量图
- 不依赖分辨率
- 反对事件处理
- 适宜做大型区域渲染
回流重绘
回流 当 DOM 变动影响了元素,比方元素的尺寸、布局、显示暗藏等扭转了,须要重写构建。每个页面至多须要一次回流,就是在页面第一次加载的时候,这个时候肯定会产生回流。
重绘 当一个元素的外观发生变化,然而没有扭转布局,从新渲染元素的外观。比方background-color
、color
回流必将引起重绘,而重绘不肯定会引起回流
如何防止回流重绘:
- 防止应用
table
布局 - 尽可能在
DOM
树的最末端扭转class
- 防止设置多层内联款式
- 开启 GPU 减速
- 将动画成果利用到
position
属性为absolute
或者fixed
的元素上
src 和 href 的区别
srcsrc 指向内部资源的地位,将指向的内容嵌入到文档中以后标签所在的地位,如 js 脚本、img
图片、iframe
等
href用于在以后文档和援用资源之间确立分割,个别是用在 link
、a
等元素
CSS3
CSS3 新增个性
- 新增 CSS 选择器、伪类
- 特效:
text-shadow
、box-shadow
- 突变:
gradient
- 旋转适度:
transform
、transtion
- 动画:
animation
盒模型
盒模型都是有四局部组成:content
、padding
、border
、margin
规范盒模型和 IE 盒模型的区别在于设置 width
和height
时,对应的范畴不同
- 规范盒模型的
width
、height
只蕴含了content
- IE 盒模型的
width
、height
蕴含了border
、margin
、padding
通过批改元素的 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:center
和justify-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
值为:hidden
、auto
、scroll
display
值为:inline-block
、table-cell
、table-caption
、flex
等
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 根底
根底数据类型
string
、number
、boolean
、object
、function
、undefined
、null
、symbol
null
和 undefined
的区别:null
示意对是一个空的对象 (object)、undefined
是申明了但没赋值,在应用 typeo
f 检测类型时,nul
l 为object
,undefined
为undefined
null == undefined // true
null === undefined //false
值类型(根本数据类型):string
、number
、boolean
、undefined
、null
、symbol
援用类型:object
、function
、array
值类型和援用类型区别:
- 值类型保留在 栈中,占用空间固定,当一个办法执行时,每个办法都会创立本人的内存栈,办法中定义的变量会寄存在这个内存栈中。当办法执行完结时,这个内存栈也会被销毁。所以,栈中存储的是根底变量。而援用变量存储在栈中是指向堆中的数组或对象的援用地址。这也就是为何批改援用类型总会影响到其它指向这个地址的援用变量。
- 值类型能够应用
typeof
进行数据类型检测 - 援用类型保留在 堆中,占用空间不固定。创建对象会保留到堆内存中,这个内存不回随着办法完结而销毁,因为这个对象还可能被另外一个变量所援用,只有当一个对象没有被任何变量援用时,零碎的垃圾回收机制会将它回收。
- 援用类型应用
instanceof
检测数据类型 - 应用 new()办法结构进去的对象是援用类型
闭包
闭包就是可能读取到其它函数外部变量的函数,创立一个最简略的闭包,就是在一个函数外部创立另外一个函数,创立的函数能够拜访到以后函数的局部变量。
闭包长处:
- 创立全局公有变量,防止变量全局净化
- 能够实现封装、缓存等
闭包毛病:
- 创立的变量不能被回收,容易耗费内存,使用不当会导致内存溢出
变量晋升、作用域、作用域链
变量晋升
js 代码在解析的时候,会将所有的变量函数,晋升到代码的最下面。变量晋升,晋升的只是变量申明,并不会吧变量赋值晋升上来
console.log(i) // 4
var i = 4
作用域
作用域是一个变量或函数的可拜访范畴,作用域管制着变量或函数的可见性和生命周期
-
全局作用域:能够全局拜访
- 最外层函数和最外层定义的变量领有全局作用域
- window 上的对象属性办法领有全局作用域
- 为定义间接复制的变量主动申明领有全局作用域
- 过多的全局作用域变量会导致变量全局净化,命名抵触
-
函数作用域:只能在函数中拜访应用哦
- 在函数中定义的变量,都只能在外部应用,内部无法访问
- 内层作用域能够拜访外层,外层不能拜访内存作用域
-
ES6 中的块级作用域:只在代码块中拜访应用
- 应用 ES6 中新增的
let
、const
什么的变量,具备块级作用域,块级作用域能够在函数中创立(由 {} 包裹的代码都是块级作用域) let
、const
申明的变量不会变量晋升,const
也不能反复申明-
块级作用域次要用来解决由变量晋升导致的变量笼罩问题
var i = 3 function fnc() {console.log(i); var i = 6; } fnc() // undefined
- 应用 ES6 中新增的
作用域链
变量在指定的作用域中没有找到,会顺次向上一层作用域进行查找,直到全局作用域。这个查找的过程被称为作用域链。
call、apply、bind 区别
- 都能够用作扭转
this
指向 call
和apply
的区别在于传参,call
、bind
都是传入对象。apply
传入一个数组。call
、apply
扭转 this 指向后会立刻执行函数,bind
在扭转 this 后返回一个函数,不会立刻执行函数,须要手动调用。
new 操作符干了什么操作
- 创立一个空对象
- 设置原型,将对象的原型设置到函数的
prototype
对象上 - 扭转 this 指向,将 this 指向该对象,并执行构造函数。
- 判断函数的返回类型,如果是值类型,返回创立的对象。如果是援用类型,返回这个援用类型的对象。
原型、原型链
- 原型: 每个对象在外部初始化的时候,都会初始化一个
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 全副代码
、setTimeout
、setInterval
、I/O
、UI Rendering
- 微工作:
Promise.then
、Process.nexTick(Node 独有)
、MutationObserver
同步工作、异步工作
js 有一个 主线程 和一个 执行栈(调用栈),所有的工作都会放到执行栈中期待被主线程执行。
js 代码在执行时,所有函数都会压入 执行栈 中。同步工作会依照 后进先出 准则顺次执行,直到执行栈清空。异步工作会在异步工作有了后果后,将注册的回掉函数放入异步工作队列中,期待主线程闲暇后(执行栈中的同步工作执行结束)。
异步队列中的工作又分为 宏观工作 和宏观工作,当以后执行栈清空后,解决异步队列中的工作时,首先会判断是否有宏观工作可执行,如果有就将宏观工作压入执行栈中执行。当宏观队列中的工作在执行栈被执行结束,再来异步队列中将宏观工作放入执行栈。
简略的来说:
- 执行同步代码,这属于宏观工作
- 所有代码执行结束,执行栈清空,执行异步队列中工作
- 异步队列中,先执行宏观工作
- 宏观工作执行结束,再执行宏观工作
节流防抖
节流(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
存在变量晋升,let
和const
不存在变量晋升cons
t 申明的变量不可变const
申明之后必须赋值,否则会报错
Promise
Promise
是异步编程的一种解决方案,将异步操作以同步操作的流程表达出来,防止了层层嵌套的回调函数。
它有三种状态
pending
初始状态fulfilled
操作胜利rejected
操作失败。
Promise
状态扭转只有两种可能
- 从
pending
——>fulfilled
- 从
pending
——>rejected
Promise
构造函数接管一个参数和一个带有 resolve
和reject
参数的回调函数。
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
(视图模型),它是Model
和View
之间的桥梁,数据会绑定到 viewModel
层,并主动将数据渲染到页面层,视图变动时会告诉 viewModel
更新数据
Vue 生命周期
创立前后:
beforeCreated(创立前):
数据观测和初始化事件还未开始,不能拜访data
、computed
、watch
、methods
上的数据办法。created(创立后):
实例创立实现,能够拜访data
、computed
、watch
、methods
上的数据办法,但此时渲染节点还未挂在到 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 中的数据状态治理,有五种属性:
state
:Vuex
的根本数据,用于存储变量getter
:从state
派生进去的数据,当相遇state
的计算属性,在这里能够对state
数据进行过滤、筛选等操作mutation
:提交更新state
数据的办法action
:和mutation
性能类似,都是用来提交更新,但action
提交的是mutation
,而不是间接变更数据,并且action
能够蕴含异步操作module
:模块化 Vuex,每个模块都有本人的state
、mutation
、actoion
、getter
mutation 和 action 的区别
mutation
更专一于批改state
,必须是同步执行。action
提交的是mutation
,而不是间接更新数据,能够是异步的。action
能够整合多个mutation
Vuex 和 localstory 的区别
Vuex
存储在内存中,页面敞开刷新就会隐没。而localstorage
存储在本地,读取内存比读取硬盘速度要快Vuex
利用于组件之间的传值,localstorage
次要用于不同页面之间的传递Vuex
是响应式的,localstorage
须要刷新
路由守卫
- 全局前置钩子:
beforeEach
、beforeResolve
、afterEach
- 路由独享守卫:
beforeEnter
- 组件内钩子:
beforeRouterEnter
、beforeRouterUpdate
、beforeRouterLeave
hash 和 history 的区别
hash
hash 模式是 vue 开发中的默认模式,地址栏 URL 携带 #
,#
后为路由。
原理是通过 onhashchange()
事件监听路由 hash
的变动,这个益处就是当 hash
值发生变化,不须要向后端发动申请,window
就能够监听事件的扭转,并依照规定加载项对应的代码。除此之外,hash
值的变动对应的 URL
都会被浏览器记录下来,这样就能实现浏览器历史页面的后退后退。
history
vue 还提供 history
模式,在 history
模式下 URL 中没有#
,相比 hash 模式更加难看。然而须要后盾配置反对。
history
的原理是利用 HTML5 中 hostory
提供的 pushState
、replaceState
这两个 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-bind
和 v-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
树进行动态内容优化,剖析出哪些是动态节点,给其打一个标记,为后续更新渲染能够间接跳过动态节点做优化。
generate
将 AST
形象语法树编译成 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
中通过获取组件的 name
和include、exclude
进行匹配。匹配不胜利,则不须要进行缓存,间接返回该组件的 Vnode。
匹配胜利就进行缓存,获取组件的 key
在this.cache
中进行查找,如果存在就间接将缓存的组件实例笼罩到以后的 Vnode 上,而后将以后组件的 key
从keys
中进行删除,而后在 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 地址到浏览器实现渲染的整个过程
- 浏览器输出
URL
并回车 - 浏览器查找以后是否有缓存
-
DNS
解析URL
失去IP
- 浏览器
DNS
缓存 host
文件缓存
- 浏览器
- 建设
TCP
连贯(三次握手) - 发送
HTTP
申请 - 服务器解决申请,浏览器失去响应数据
-
浏览器解析渲染页面
- 解析
DOM
生成DOM
树 - 解析
CSS
生成CSS
树 - 合并
DOM
树和CSS
树,生成渲染树 - 浏览器开始渲染页面(回流重绘产生在这个阶段)
- 解析
TCP
连贯敞开(四次挥手)
网络协议、平安相干
TCP、UDP 协定
TCP
和 UDP
都是在传输层定义的两种传输协定。基于 UDP
协定传输不能保证数据准确无误的送达,但 UDP
不仅能够反对一对一的传输方式,还能够反对一对一、一对多等模式。也不须要像 TCP
一样建设连贯,所以传输速度快。
TCP
的目标是提供牢靠的数据,并且须要在传输前建设连贯(三次握手)。只反对一对一进行传输。
区别:
TCP
协定牢靠,UDP
协定不牢靠TCP
面向连贯,UDP
采纳无连贯TCP
能够保证数据程序,UDP
不能TCP
一对一传输,UDP
能够一对多、多对一等模式
HTTP 和 HTTPS 区别
HTTP
是明文传输,不平安。HTTPS
基于SSL
进行加密传输,比拟平安。HTTPS
须要CA
证书,HTTP
不须要。HTTP
端口为80
,HTTPS
端口为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
示意敞开本方数据流
三次握手:
- 第一次握手:客户端给服务端发一个
SYN
报文,并指明客户端的初始化序列号ISN
,此时客户端处于SYN_SEND
状态。 - 务器收到客户端的
SYN
报文之后,会以本人的SYN
报文作为应答,并且也是指定了本人的初始化序列号ISN
。同时会把客户端的ISN + 1
作为ACK
的值,示意本人曾经收到了客户端的SYN
,此时服务器处于SYN_REVD
的状态。 - 客户端收到
SYN
报文之后,会发送一个ACK
报文,当然,也是一样把服务器的ISN + 1
作为ACK
的值,示意曾经收到了服务端的SYN
报文,此时客户端处于ESTABLISHED
状态。服务器收到ACK
报文之后,也处于ESTABLISHED 状
态,此时,单方已建设起了连贯。
四次挥手
- 客户端会发送一个
FIN
报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1
状态。 - 服务端收到
FIN
之后,会发送ACK
报文,且把客户端的序列号值 +1 作为ACK
报文的序列号值,表明曾经收到客户端的报文了,此时服务端处于CLOSE_WAIT
状态。 - 如果服务端也想断开连接了,和客户端的第一次挥手一样,发给
FIN
报文,且指定一个序列号。此时服务端处于LAST_ACK
的状态。 - 客户端收到
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(跨站申请伪造)
CSRF
(Cross-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 根底面试题 + 答案、分类学习整顿(良心制作)继续更新
高级知识点