一个面试面麻的人,在这里我把总结的所有面经分享给大家,希望大家能找到理想的工作。
我总结的面经内容囊括了自己面试题/笔试题,掘金、牛客、小红书、博客其他同学分享的内容,内容量很大,我会尽快更新的。都是个人总结的白话文描述,如有问题 欢迎指正。
Ex. var arr=[1,[2,[3,[4,5]]]]; => arr=[1,2,3,4,5]
- 传统方法 递归
- 使用reduce函数递归遍历
- 数组强制类型转换
对于数组对象,toString
方法连接数组并返回一个字符串,其中包含用逗号分隔的每个数组元素。返回的字符串使用split
分割成子字符串数组,最后将数组中每个元素的类型转换为Number
型- 使用ES6的flat方法 flat(depth)
- 使用JSON的函数和正则表达式
使用JSON的序列化函数stringify()
先对数组进行序列化,再用正则去掉[],得到的结果在最外层加上[]后使用JSON.parse()
恢复成数组对象。- 扩展运算符与some函数结合
先用some方法把数组中仍然是数组的项过滤出来,再执行concat操作,利用ES6的扩展运算符 ‘ ... ' 将其拼接到原数组中,最后返回。
(1)float+calc() : 左列开启浮动+右列开启浮动+右列宽度为父级100%减去左列宽
(2)float+margin-left :左列开启浮动+右列增加外边距
(3)absolute+margin-left :开启定位脱离文档流+(同上)
(4)float+overflow : {overflow:hidden}
(5)flex布局:.container {display:flex}
.right {flex:1}
(6)grid布局
一、什么是BFC?
一个块格式化上下文(block formating context)是Web页面得可视化CSS渲染出得一部分,它是块级盒布局出现的区域,也是浮动元素进行交互的区域
二、触发条件
- 浮动元素,float不是none
- 绝对定位元素元素具有position为absolute或fixed
- 内联块,元素具有display:inline-block
- 表格单元格,元素具有display:table-cell
- 表格标题,元素具有display:table-caption
- 具有overflow且值不是visible的块元素
- display:flow-root
- column-span:all 应当总是会创建一个格式化上下文,即便具有column-span:all 的元素并不被包裹在一个多列容器中
三、BFC特性
- 内部的Box会在垂直方向上一个接一个的放置
- 垂直方向上的距离由margin决定
- BFC的区域不会与float的元素区域重叠
- 计算BFC的高度时,浮动元素也参与计算
- BFC就是页面上的一个独立容器,容器里面的子元素不会影响外面元素
四、为什么要使用BFC
- BFC可以解决子元素浮动导致父元素高度塌陷的问题
- BFC可以解决两个兄弟盒子之间的垂直距离是由他们的外边距所决定的,以较大为准
- 不被浮动元素覆盖
- 防止文字环绕
1、margin:auto; 元素有宽度有高度时
2.、position:absolute; 元素有宽度有高度时,设置position和margin为负的宽高的一半
元素有宽度有高度时,利用calc计算top和left
元素宽度、高度未知时,设置position和transform:translate(-50%, -50%)
3、弹性盒子:为其父元素设置display:flex
4、利用水平对齐和行高:设置text-align和line-height,实现单行文本水平垂直居中
5、grid:在网格项目中设置justify-self, align-self 或者 margin:auto
在网格容器上设置justify, align-items或者jsutify-content, align-content
一、hash模式——即地址栏URL中的 # 符号
- hash不会被包含在HTTP请求中,对后端完全没有影响,因此改变hash不会重载页面
- 404错误:仅hash符号之前的内容会被包含在请求中,即使没有做到对路由的全覆盖也不会返回404错误
- hash的原理是采用hashchange事件,可以在window监听hash的变化,我们在url后面随便添加一个 #xx 触发这个事件
二、history模式
- 需要特定浏览器支持,有back,forward,go,pushState等方法,提供了对历史记录修改的功能,当它们执行时,虽然改变了当前url,但浏览器不会立即向后端发送请求
- 404错误:前后端发起请求的url需一致,返回404错误
- histor的原理是H5的几个新API
一、全局守卫
- 全局前置守卫 beforeEach
router.beforeEach((to, from, next) => {
})
在路由跳转之前被触发- 全局解析守卫 beforeResolve
参数: to, from, next
在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用- 全局后置钩子 afterEach
参数:to, from, failure二、组件内路由守卫
- beforeRouteEnter: 不能访问this,因为守卫在导航确认之前被使用,因此即将登场的新组件还没被创建
- beforeRouteUpdate: 主要是路由复用时被调用,即在当前页面跳转,会走该路由,而不会重头
- beforeRouteLeave: 这个离开路由守卫通常用来禁止客户在未保存修改前突然离开,该导航可以通过next(false)来取消
注意:beforeRouteEnter是支持给next传递回调的唯一守卫,对于beforeRouteUpdate和beforeRouteLeave来说,this已经可用了,所以不支持传递回调,因为没有必要了。
相同点:
- 都可以遍历数组每一项数据
- 都不会对空数组进行检测
- 都不会改变原始数组
不同点:
- some() 方法会依次执行数组的每个元素
如果有一个元素满足条件,则表达式返回true,剩余的元素不会再执行检测
如果没有符合条件的元素,则返回false- every() 方法使用指定函数检测数组中的所有元素
如果数组中检测到有一个元素不满足,则整个表达式返回false,且剩余的元素不会再进行检测
如果所有元素都满足条件,则返回false
相同点:
- 都是循环遍历数组中的每一项
- 每次执行匿名函数都支持三个参数,参数分别为item(当前每一项), index(索引值), arr(原数组)
- 匿名函数的this都指向window
- 只能遍历数组
不同点:
- map() 方法会得到一个新数组并返回;forEach() 会修改原来的数组
- forEach() 允许callback 更改原始数组的元素;map() 返回新的数组
使用场景:
1、forEach() 适合你并不打算改变数据的时候,而只是想用数据做一些事情——比如,存入数据库或打印
2、map() 适合你要改变数据值的时候,不仅在于它更快,而是返回一个新数组,可以搭配filter(), reduce() 等
一、浅拷贝——拷贝深度不够会改变原数组
push、pop、unshift、shift、reverse、sort、forEach、Object.assign(第一个参数是拷贝的目标对象,后面的参数是开呗的来源对象)、扩展运算符
二、深拷贝——不会改变原数组,增加了一个新指针并申请了一个新元素地址
slice、concat、map、filter、reduce、for...in...、使用JSON.parse和JSON.stringify
注意:基本类型(string, number, boolean, null, undefined, symbol)不存在深浅拷贝问题,因为赋值的是数据;引用类型(Object, Array, Date, RegExp, Function)存在这个问题
定义:reduce() 方法接收一个函数作为累加器,数组中的每个值(从左至右)开始缩减,最终计算为一个值
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)reduce的常用方法:1)数组求和
2)累加数组中对象的值
3)计算数组中每个元素出现的次数
4)数组去重
5)二维数组变一维
6)将多维数组变一维
7)根据属性把对象分类
浏览器时间循环 和 node.js事件循环
Event Loop:同步任务+异步任务
所有同步任务都在主线程上执行,形成一个函数调用栈(执行栈),而异步任务则先放到任务队列里,任务队列又分为宏任务和微任务。
宏任务:script(整块代码)、setTimeout、setInterval、I/O,UI交互事件、setImmediate(node环境)
微任务:new promise().then 回调、MutationObserver(h5新特性)、process.nextTick(node环境)
定义:有权访问其他函数作用域中变量得函数
JS中,变量得作用域属于函数作用域,在函数执行完毕后,它得作用域会被销毁,内传也会被回收,但由于闭包在函数内部创建一个子函数,且子函数可以访问父级函数中得作用域,即父函数执行完作用域也不会被回收,这就是闭包。
缺点:比普通函数更见占用内存,可能会造成内存泄漏
语法比函数表达式更加简洁,并且没有this, arguments, super 或 new.target;更加适用于本来需要隐匿函数的地方,并且它不能用作构造函数。
- 在普通函数中,this指向window
- 在构造函数中,this指向创建对象
- 在方法声明中,this指向调用者
- 在定时器中,this指向window
- 在事件中,this指向事件源
全局作用域 函数(局部)作用域 块级作用域 静态作用域 动态作用域
getElementById getElementByClassName getElementByTagName
querySelector & querySelectorAll getElementByName
document.title & document.body
静态布局 自适应布局 流式布局 响应式布局 弹性布局
通过数据劫持结合发布订阅模式的方法来实现
一、Composition API
Vue2是选择式API;Vue3是组合式API二、双向数据绑定原理的变化
Vue2利用数据劫持结合订阅发布 Object.defineProperty();Vue3使用ES6的Proxy API对数据代理
三、Vue3支持碎片
四、建立数据
Vue2放入data;Vue3需使用setup(),在组件初始化构造的时候触发五、生命周期钩子不同
六、父子传参不同
七、Vue3新增Teleport瞬移组件
- https需要到ca申请证书,一般免费证书较少,需要一定费用
- http是超文本文本传输协议,信息是明文,https是具有安全性的ssl加密传输协议
- 连接方式不同,用的端口不一样,前者是80,后者是443
- http的链接是无状态的;https协议是有ssl+http协议构建的可进行加密传输,身份认证的网络协议
按需引入,借助babel-plugin-component打包
ES6推出tree shaking,当我们在项目中引入其他模块时,它会自动将我们用不到的代码,或者永远不会执行的代码摇掉,在Uglify阶段查出,不打包到bundle中。
tree-shaking依赖ES module语法,webpack不支持导出ES module。
组件库都是用webpack开发,不支持ES module导出
- 渲染引擎首先通过网络获得请求文档的内容
- 解析HTML文件,构建DOM Tree
- 解析CSS,构建CSSOM Tree(CSS规则树)
- 将DOM Tree 和 CSSOM Tree合并,构建Render Tree(渲染树)
- reflow(重排):根据Render Tree进行节点信息计算(Layout)
- repaint(重绘):根据计算好的信息绘制整个页面(Painting)
- 通过style标签引入的样式和同步加载的link标签会阻塞页面渲染,但异步加载的link标签则不会
- js脚本通过添加async或defer的方法来开启异步下载,开启异步下载则不会阻塞页面渲染,但下载完成后,加async的脚本会立即执行,执行时会阻塞页面渲染;
而加defer的脚本会等样式dom结构加载完成后才会执行,此时页面已经渲染完了,所以只有同步脚本和个别情况下加了async的脚本会阻塞渲染
function debounce(fn,wait){
let timer = null;
return function(){
if (timer) {
clearTimeout(timer)
timer = null
}
timer = setTimeout(()=>{
fn.call(this, arguments)
}, wait)
}
}
节流
function throttle(fn, wait){
let timer = null
return function(){
if(!timer){
timer = setTimeout(()=>{
fn.call(this,arguments)
tiemr = null
}, wait)
}
}
}
三次握手:指建立一个TCP连接时,需要客户端和服务端总共发送3个包,以确认双方的接受能力和发送能力是否正常,为后面的可靠性传送做准备
四次挥手:终止TCP链接只需要发送4个包,客户端或服务端均可主动发起挥手动作
- 1XX (信息性状态码) 表示接受的请求正在处理
- 2XX (成功性状态码) 表示请求正常处理完毕
- 3XX (重定向状态码) 表示需要附加操作以完成请求
- 4XX (客户端错误状态码) 表示服务器无法处理请求
- 5XX (服务端错误状态码) 表示服务器处理请求出错
const flatten = (arr) => {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur)? flatten(cur) : (cur)
}, [])
}
setTimeout(function f() {
setTimeout(f,interval);
}, interval)
- flex布局,父元素:display:flex; justify-content: center; align-items: center;
- 子绝父相,子元素:left:50%; top:50%; transform: translate(-50%, -50%)
- 子绝父相,子元素:left:0; top:0; botton:0; right:0; margin: auto
- 文字的话,text-align:center; line-height 和 height 相等
用来确认一组异步操作是否全都结束了,包含了“fulfilled” 和 “rejected” 两种情况
Promise.allSettled() 方法接受一个数组作为参数,数组每个成员都是一个Promise对象,并返回一个新Promise对象,只有等到参数数组的所有Promise对象都发生状态变更(不管是fulfilled还是rejected),返回的Promise对象才会发生状态变更
- W3C标准的盒子模型(标准盒模型)
- IE标准的盒子模型(怪异盒模型)
- 浏览器向DNS服务器请求解析该URL中的域名所对应的IP地址
- 解析出IP地址后,根据该IP地址和默认端口80,和服务器建立TCP连接
- 浏览器发出读取文件(URL域名后面部分对应的文件)的HTTP请求,该请求报文作为TCP三次握手的第三个报文的数据发送给服务器
- 服务器请求作出回应,并把对应的html文本发送给浏览器
- 释放TCP连接
- 浏览器将该html文本显示内容
function getJSON(url) {
let promise = new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
if (this.status === 200) {
resolve(new Error(this.statusText));
} else {
reject(new Error(this.statusTzext));
}
};
xhr.onerror = function () {
reject(new Error(this.statusText));
};
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send(null);
});
return promise;
}
- XXS攻击(跨站脚本攻击)
- CSRF安全漏洞(跨站请求伪造)
- 文件上传漏洞
- 限制URL访问,越权访问
- 不安全的加密存储
- SQL注入攻击
- OS命令注入攻击
- 原型对象
- 原型链继承
- 空函数作为中介继承
- 绑定继承
- 组合继承
- 拷贝继承
- ES6的class继承
function superType() {}
function subType() {
//构造函数继承
superType.call(this, ...arguments);
}
//原型链继承
subType.prototype = new superType();
//对象增强
subType.prototype.constructor = subType();
一、
有async,加载和渲染后续文档元素的过程将和script.js的加载与执行异步二、
有defer,加载后续文档元素的过程将和script.js的加载异步,但是script.js的执行要在所有元素解析完成之后,DOMContentLoaded事件触发之前完成
工厂模式:主要是用来实例化有共同接口的类,它可以动态的决定应该实例化哪一类
主要分为三种形态:简单工厂模式、工厂方法模式、抽象工厂模式
一、简单工厂模式
主要有一个静态方法,用来接收参数,并根据参数进行switch或if判断来决定返回实现同一接口的不同类的实现二、工厂方法模式
把工厂类定义为接口,以多态的形式来削弱工厂类的职能,对简单工厂进一步的解耦,降低简单工厂模式的风险,提高可维护性,可扩展性
三、抽象工厂模式
工厂模式下一个工厂只能生产同类同品 的产品,而抽象工厂模式下一个工厂可以生产多类同品 的产品
- 在vue生命周期的created()里进行DOM的操作一定要使用nextTick(),因为created执行的时候DOM还未渲染
- 在方法里操作DOM,由于dom元素还没有更新,因此打印出来的还是为改变之前的值,而通过this.$nextTick()获取到的值为dom更新之后的值
- 先将数据进行Obj.defineProperty() 进行绑定,判断数据为数组或者对象进行绑定
- 当页面开始渲染会定义updateComponent方法,这个方法主要就是为了调用render方法
- 进入render的时候会执行页面使用的值,这时候会触发该数据的get属性
- 开始进行绑定依赖
- 之后通过patch方法将节点进行更新替换或者新增
- 如果数据发生变化,会执行数据的set方法,这时数据的Dep.notify会调用
- Dep.notify会去调用绑定的Watcher,促使它更新,并收集所有改变,一次性进行改变
- 调用Watcher的run()方法,run方法会调用updateComponent方法进行render更新
数组:v-for="(item, index) in/of arr"
对象:v-for="(value, index) in obj“
数字:v-for="(item,index) in 数字" index从1开始
- 页面首次进入渲染
- 浏览器resize
- 元素位置和尺寸发生改变
- 可见元素的增删
- 内容发生改变
- 字体font改变
- CSS伪类激活
get参数在请求地址 post参数在请求体 get有长度限制
post没有长度限制 get有缓存 / get返回的结果不会变 post结果可能不一样
GET、POST、OPTIONS、PUT、DELETE、HEAD
一、强制缓存
指只要浏览器缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边
二、协商缓存
与服务端协商之后,通过协商结果来判断是否使用本地缓存
1)属于文档对象模型:documentcookie
2)属于浏览器对象模型:localStroage、sessionStorage,indexDB
区别:
- cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据传给服务器,仅在本地缓存
- 存储大小限制不同,cookie数据不能超过4K,同时每次http请求都会携带cookie,所以cookie只适合保存很小的数据。
sessionStorage和localStorage虽然也有存储大小限制,但比cookie大很多,可以达到5MB或更大- 数据有效期不同:
sessionStorage 仅在当前浏览器窗口关闭前有效 localStorage 始终有效,窗口或浏览器关闭也一直保保存,因此用作持久数据 cookie 只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭 - 作用域不同:
sessionStorage 不在不同的浏览器页面中共享,即使同一个页面 localStorage 在所有同源页面窗口中都是共享的 cookie 在所有同源页面窗口中都是共享的
- transition、transform、animation这三个是CSS属性,而translate是2D转换的一种方法,是transform的一个属性值
- transform是2D、3D变换的属性,只是动画可用的一种属性,因为使用transform不会引起页面的重排
- transition、animation才是动画中必备的两个属性
div {
border-left:50px solid transparent;
border-right:50px solid transparent;
border-bottom:50px solid #333;
width:0;
height:0;
}