都说金九银十好找工作,但是放眼今年的这个环境来看,似乎变成了铜九铁十,boss是一刷再刷,回复寥寥无几,甚至已读不回,无情啊无情!和以前形成了一个明显的反差,以前的周周面试跑断腿,到现在静等静等在静等,偶尔给你抛个面试邀请都是稀罕的事情。
但是终究还是有一些面试,有面试就还有希望。都说面试造航母,工作拧螺丝,但是面试也的确磨炼人,考验人,通过面试,通过别人的找茬也能明确的知道自己的短板,知道现在市场需要一个真正拥有那些技能的人。自己的每次面试都有将没回答到的,回答的不好的地方记录下来,然后回去反省,巩固然后继续出发,也是一个反复锤实的过程。
总结多了,发现知识点也在一点点的累积,下面则是一些自己对问答的归纳,但每个公司的面试问题不同,问题也有所不同,解释的不对的欢迎大佬斧正!
http部分
-
http的请求报文和响应报文
- 请求报文:请求行,请求头,请求体
- 响应报文:响应行,响应头,响应体
-
http协议1.0,1.1,2.0, 3.0的区别
- 1.0不支持断点续传,需要手动进行长连接
- 1.1支持断点续传,默认支持长连接,新增了put,delete,options,connect,trace请求方式,请求存在数量限制,超过限制数据请求会被阻塞,加入了强缓存和协商缓存
- 2.0解决了性能限制,改进了传输性能,一个tcp连接多路复用,并发请求
-
强缓存:从客户端读取缓存,优先级高于协商缓存,通过response header返回的Expires和cache-control来判断是否使用强缓存,cache-control > Expires
-
协商缓存:从客户端读取缓存,当浏览器没有命中强缓存时,再会验证使用协商缓存,存在Etag或者last-modfied,则命中则返回304状态码,不命中则重新向服务器请求,Etag > last-modified
-
url在浏览输入的过程中发生了什么
- 通过DNS解析域名的实际IP地址
- 判断是否读取缓存
- 进行TCP连接
- 判断请求协议,若协议是https则会进行加密和安装CA安全证书的
- TCP连接建立成功后,浏览器向服务发送获取html请求
- 服务器响应请求
- 浏览器解析html,css,渲染页面
- 浏览器执行JS脚本
-
https为什么更加安全
- 在http的基础上进行数据加密
- 需要安装ca证书,相当于真实的身份校验
- 对称加密
- 非对称加密
- 对称加密和非对称加密
- 数字签名
-
常见的网络攻击
- CORS跨域资源共享
- CRSF跨站请求伪造
- xss跨站脚本
- DDoS分布式拒绝服务
- SQL注入攻击
浏览器部分
-
什么是跨域
- 当请求的地址的协议,域名和端口都不一致时,客户端就是视为不同源,即为跨域,跨域是浏览器做出的限制,服务端不受影响
-
解决跨域的方法
- cors:后端解决,在响应头添加Access-Control-Allow-*头,告知客户端通过此请求
- 反向代理:后端解决,后端将目的请求地址进行转发处理,服务端请求上游的服务端,将跨域请求处理成同源请求
- JSONP:前后端配合解决,只支持get请求,主要利用了客户端加载javascript文件不受同源策略的限制,进行跨域请求
-
浏览器重排和重绘
-
重排:节点大小和位置信息出现变化就会引起重排:例如:盒模型,容易大小,定位,窗口视图变化
-
重绘:节点外观发生变化,不改变节点位置和大小,例如:改变字体颜色,背景颜色等
-
总结:重排一定会引起重绘,重绘不一定引起重排
-
优化方案:
- 尽量减少样式的频繁操作
- 尽量批量读取和写入DOM
- 使用变量信息对DOM进行缓存,避免频繁读取DOM的信息,进行初始化
- 合理利用特殊性样式属性,将渲染层从提升到合并层,开启GPU加速,提升性能
-
-
浏览器的垃圾回收机制
-
内存泄露:应当被回收的内存对象没有被回收,一直存在内存栈当中,占用内存空间,影响浏览器性能
-
常见的内存泄露的原因
- 创建的全局变量没有手动回收
- 事件监听器,定时器,闭包没有及时被清理
- 使用js对象做数据缓存,且不设置清理策略和控制对象的大小
-
垃圾回收的方式
- V8的回收机制
- Reference Counting(引用次数)
- scavenger算法
-
-
事件循环
- 宏队列:settimeout,setinterval,script(整体代码),postMessage,
- 微队列:Await/async, promise,mutationObserver(h5新特性),process.nextTick
- 微任务优先于宏任务
-
栈和堆的不同
- 栈是系统自动分配,堆是人为申请分配
- 大小不同,栈更小,堆的内存空间会比栈大
- 分配效率不同,栈的系统自动分配会比堆的申请分配更加快
- 栈一般存放基础类型的值,使用完系统自动释放。堆一般存放引用类型的值,使用完不会立即自动释放,有自己的垃圾回收机制
-
事件循环
- 宏队列:settimeout,setinterval,script(整体代码),postMessage,
- 微队列:Await/async, promise,mutationObserver(h5新特性),process.nextTick
- 微任务优先于宏任务
js基础部分
-
new的过程中做了什么
- 定义一个空对象
- 将空对象的proto指向构造函数的prototype
- 将对象的this指向指向构造函数的prototype
-
script标签中的defer和async的区别
- defer用于保持脚本相对顺序执行
- async用于脚本异步执行,不阻塞页面
-
函数柯里化的作用
- 把多个参数的函数传参变成单一的传参,职责细化,利用闭包保存最先传入的参数
-
es5和es6继承的区别
- es5一般使用Object.create()进行继承,结果只能继承父对象的实例方法,不能继承私有属性
- es6使用class类中的extends和super进行继承,能继承实例方法,也能继承私有属性
-
var,let和const的区别
- var存在变量提升,let和const不存在变量提升
- 用const声明必须初始化值(必须给值)
- var没有自己的作用域,let和const有自己的作用域
- 同一个变量,不能用let重复声明,用const声明的变量内存地址不能被改变
-
JSON.parse(JSON.stringify)拷贝的弊端
- 如果对象了里面存在函数和undefined,将会造成丢失
- 也会丢失对象的constructor
-
什么是闭包
- 一个函数返回一个子函数,子函数访问外面函数的变量
-
函数和变量提升
- 函数声明优于变量声明的提升
-
es6和commonjs的区别(import和require的区别)
- es6: 是一个模块的引用,不能更改引用的数据,加载立即执行
- common:是一个模块的拷贝,按需执行,即运行时执
-
尾递归的作用
- 每个函数执行时都会在栈push一条执行内存,当a函数返回b函数的时候,若a函数还没有执行完,栈就会存在a和b两条执行内存,执行完之后再销毁a函数内存,而尾递归则是当函数return操作时,只单纯的返回一个函数,不做其他附加操作,如此就节约了执行栈一部分内存空间,减少爆栈的几率
-
defineproperty和porxy代理的优缺点
- defineproperty监听的是属性的变化,无法监听新增属性,或者除数组原生方法之外的操作 porxy代理的是整个对象和数组,解决了defineproperty的缺陷
-
怎么判断值是否为null
-
!value && typeof value != ``"undefined"` `&& value != 0 -
value === null //true
-
-
判断数组的方法
-
Object.prototype.toString.call([]) === [object Array] -
isArray([]) -
a instanceof Array -
[].constructor === Array
-
-
箭头函数的arguments
- 箭头函数没有arguments
css基础部分
-
移动端1px如何姐解决
- 移动端像素比都多数不为1
- 解决方式:scale,box-shown,svg
-
svg作用和使用
- 作用:内存小,清晰度高,可改变尺寸大小的矢量图
- 使用:html内嵌,img引入,css引入,object引入
-
BFC的形成和作用
- 形成:HTML根元素,float,position,fixed,table-cell,flex,grid
- 作用:避免浮动元素高度塌陷,外边距折叠,灵活的实现自适应布局
-
相对定位(relative)和绝对定位的区别(absolute)
- 相对定位:基于自身元素原始位置进行定位,不脱离文档流
- 绝对定位:基于最近的有定位元素的父盒子进行定位,脱离文档流,不占用浏览器位置
webpack部分
-
npm包开发及上传
- 初始化项目,配置packpage.json文件(包名,入口文件)
- 登录npm,上传npm包(npm publish)
- 检查是否上传成功
- 24小时内撤销上传(npn --force unpublish <包名>)
- 项目初始化使用,下载依赖 npm install <包名>
- require(commonJS)或import(es6)使用
-
npm run xxx的时候做了什么
- 找到package.json文件中对应的命令
- 运行该命令的配置
- 找到项目中node_modules使用到的依赖,并找到相应的js来执行
- 如果当前文件没找到该对应的依赖,就回去全局的node_modules中寻找
- 如果全局的node_modules下面也没有找到,就会去同环境path下找同名的文件
- 如果没有则抛错提示下载
-
package.lock.json文件的作用
- 记录和锁定package里下载的依赖准确版本,和依赖的依赖准确版本
-
npm中script命令详解
- webpack照片那个script对象配置参数名对应npm run 执行
- 执行特定命令时,则会指向命令配置的相应内容,如node index.js(执行index.js文件),sh index.sh(执行index.sh脚本), --color(执行webpack相应的插件文件)
- script配置命令可以并行运行,下载npm-run-all即可
-
webpack设置环境变量
- 下载cross-env插件
- 在script配置项中进行变量传参
- 通过node的全局process.env获得设置的环境变量
-
webpack配置打包文件
- 配置css允许打包 css-loader
- 升级css为引入式 style-loader
- 为css添加兼容前缀 aotuperfixed postcss postcss-loader
- 打包自动添加html文件 html-webpack-plugin
- 支持图片地址引入 url-loader filr-loader
- 启动本地服务 webpack-dev-server,配置devServer数据
-
babel的作用
- 将es7等高级语法,转换成浏览能识别,能兼容的语法,将高级语法转换成低级语法
-
babel原理
-
babel是什么
- 转换成js的编译器,把各类语言或新语法新特性转换成低版本自持的语法
- 解析(parse)阶段,一般分为词法解析和语法解析
- 转换(transform)阶段,对AST语法树深度遍历,按需对AST进行增删改操作
- 生成(generator)阶段,将处理后的AST转换成代码片段
-
-
webpack热更新原理
-
什么是webpack热更新
- 开发过程中,代码发生变动后,webpack会重新编译,编译后浏览器替换修改的模块,局部更新,无需刷新整个页面
-
原理
- 通过websocket实现,建立本地服务和浏览器的双向通信,当代码变化,重新编译后,通知浏览器请求更新的模块,替换原有的模块
-
步骤
- 通过webpack-dev-server开启server服务,本地server启动之后,再去启动websocket服务,建立本地服务器和浏览器双向通信
- webpack每次编译后,会生成一个hash值,hash代表每一次编译的表示,作为下一次热更新的表示
- webpack监听文件(通过文件的生成时间判断是否变化),当文件变化后,重新编译
- 编译结束后,通知浏览器请求变化的资源,同时将新生成的hash值传给浏览器,用于下次热更新使用
- 浏览器拿到更新的模块后,用新模块替换旧的模块,实现局部刷新
-
-
webpack的优化
- alias配置文件别名
- 静态文件拆分静态文件夹,在以外链的方式引入使用
- 给css添加前缀名
- 打包清除之前的打包文件
- 配置生成html文件的参考模板
- 配置编译缓存,减少冷气时间
- 多线程编译,打包
- 热更新
- 打包成gzip的压缩
- 生成环境打包压缩js代码
- 代码分割,按需加载
-
webpack打包的过程经历了什么?
- 执行打包命令
- 找到入口文件,从入口文件开始
- 递归解析引入的文件
- 对不同文件使用的loader进行编译解析,转换成js支持的文件
- 在同一集成在一个文件夹,安排配置生成打包模板,静态文件的存放
-
webpack的优化
-
构建性能优化
- 开启热更新
- 开启loader缓存,缓存loader结果
- 将不需要解析的文件或者一些第三方库进行缓存
- 多线程打包(thread-loader)
- 将静态文件拆分文件夹,并引入式使用(ExtractTextWebpackPlugin)
- 打包之前删除历史打包的文件(CleanWebpackPlugin)
- 自动生成打包文件(HtmlWebpackPlugin)
- 参照模板生成打包文件(CopyWebpackPlugin)
- 给css自动添加前缀(autoprefixed)
- css文件压缩(OptimizeCSSAssetsPlugin)
- 模块依赖的可视化(WebpackBundleAnalyzer)
- 将相同模块的代码提取成js(CommonsChunkPlugin)
-
传输性能优化
- 文件分包
- 打包gzip文件压缩
- 打包代码压缩(tree-shaking)
- 懒加载,通过import通过动态导入模块
-
运行性能优化
-
-
webpack5的升级优化?
-
增加了tree-shaking,只打包被使用到的文件,未使用到的将会剔除掉,同时只支持esModule的引入的打包,对于commonjs的require引入将不支持,可以在babel/perset-env中配置防止将文件转译成commonjs的类型
-
增加了cache的配置,不在需要额外引用引用HardSourceWebpackPlugin插件用于缓存
-
内置了terser-webpack-plugin插件,用于js代码压缩
-
打包输出可以配置生成es6的代码
-
可以区分js和css文件,颗粒化配置css和js的文件大小临界值
-
-
vite为什么快
- 按需编译按需打包
- 底层逻辑不同,vite的esbiuld使用go语言开发,比用js编写的打包快10-100倍
- 热更新快,只重新编译改动的模块,不会像webpack一样,模块引用的模块也会重新编译
规范部分
待整理
vue相关
-
vue是如何实现数据劫持的
- vue2是通过发布订阅模式,即Object.defineProperty,vue3是通过proxy代理,getter和setter,getter收集数据,setter分发派送给对应对象
-
vue是如何实现数据双向绑定的
- 实际是触发了v-bind和v-on语法糖,当数据更新时出发对应元素的事件方法(input,change等)进行数据更新,在将数据同步到对象的元素属性上
-
vue数据绑定的差异
- vue2不支持劫持对象新创建属性,和数组的变化及劫持数组更新索引,可通过set的方式进行数据更新
- vue3都支持
-
Vue-cli构建优化
- speed-measure-webpack-plugin依赖用来量化构建文件的时间
- hard-source-webpack-plugin用于添加缓存,为模块提供中间缓存步骤
- 内置了cache缓存loader
- loader多进程,vue-cli3已内置thread-loader,等同于happypack
-
vue虚拟dom
-
虚拟dom是什么:
- 虚拟dom是什么: 本质就是JS的数据对象,他代表或存储了一些dom的特征
-
虚拟dom的作用:
- 减少dom的操作次数,当数据改变时,找出虚拟dom和真实dom之间的差异,统一更新dom节点
-
-
vue中key的作用
- 高效的更新虚拟dom,精确的找到需要更新的虚拟dom进行更新
- vue在判断新旧虚拟dom是够相同时的时候,key是一个必要条件,如果没有唯一标识(key),会频繁更新元素,让整个patch(diff算法)过程比较低效,增加消耗,影响性能
- 尽量不适用数组的索引作为下标,因为当多数组进行了数据操作时,下标的话引起数据的变化,就会触发patch操作,相当于多余的操作
-
vue的diff算法
-
diff的原理
- 两个数的对比和更新
- 通过同层级的唯一标识,只会同层级的dom进行对比,深度优先,同事会通过是否携带key和tag来判断新旧节点是否相同
- 新老节点同时从左开始,新老节点同时从右开始,新从头旧从尾开始,新从尾旧从头开始(首尾指针)
-
diff的执行时机
- 数据更新的时候会运行rende函数得到新的虚拟dom
- 运行update,将新生成的虚拟dom
- 最后在Watcher执行diff,将新旧的dom进行对比(watcher会监测数据的变化,同时真正执行diff)
-
-
vue的nextTick
-
为什么有nextTick
- vue操作dom数据时并不是跟随着每次操作进行更新,而是在操作完成后统处理虚拟dom进行统一的数据更新
-
nextTick的作用
- nextTick接收一个回调函数为参数,并将这个回调函数延迟到在dom更新完成进行数据处理
-
vue的data为什么是函数式
-
vue组件是用来的复用的,为了防止data去复用
-
vue的data数据都应该是相互隔离,互不影响的,避免的别的组件被复用并更新data数据的时候,其他地方的组件不受影响
-
如果使用对象的形式,公用一个存储空间,全局都将会守影响
-
-
如何将.vue文件编译到vue文件里的
- 先解析template成render函数,模板中用到的data数据转换成js变量
- render返回vnode(虚拟dom)
- 在解析js部分,监听data对象里的数据变化, 在执行render函数,将vnode渲染成真实dom
-
vue的生命周期
- beforeCreated(初始化之前,实例还未创建)
- created(初始化完成,可以方位watch,computed,data,methods等方法)
- beforeMounted(render函数被调用,data的数据生产模板,但是还没有挂在到dom上)
- mounted(实例挂载在dom上,并且能通过方法获取dom节点)
- beforeUpdated(数据更新之前)
- Updated(数据更新之后)
- beforeDestroy(页面销毁之前)
- Destroryed(页面销毁之后)
-
keep-alive的原理
- 概念: 是vue内置的一个抽象组件,当它包裹动态组件时,会缓存不活动的组件实例,自身不会渲染成一个dom元素,也不会出现在父组件链中
- 作用:在组件切换的过程中将状态保存在内存中,防止重复渲染,减少性能消耗,提升用户体验
- 生命周期函数: activated(在keep-alive组件激活时使用),deactivated(在keep-alive组件停用时调用)
-
vue页面和组件的生命周期执行顺序
- 页面的beforeCreated,created,beforeMounted,组件的beforeCreated,created,beforeMounted,mounted,页面的mounted
-
vue2和vue3的diff区别
- vue2
- 收尾指针法,全量diff
- 出发更新全部重新创建
- vue3
- 头和头,尾和尾,基于最长递增子序列增删改查移动
- 静态标记,未参与更新的数据避免重复创建
- 将事件缓存
- vue2
-
vue和react的diff区别
- vue:首位指针,类型不同,判断节点的key值,元素类型和属性区分改变
- react:从节点左侧开始,一对多依次对比,判断节点的key值,元素和属性区分改变
-
vue-router有什么模式,模式什么差别
- 模式:hash和histore模式
- hash模式就是url带#号标志,通过window.location.hash来获取
- history模式就是由h5的history对象来实现
-
vuex的方法
- state
- mutation
- getter
- actions
- module(分模块)
-
vue3的新特性
-
所有语法糖皆按需引入
-
通过使用proxy代理来进行数据响应式更新
-
增加了语法糖,如: refs,toRefs,readonly,isReadonly,reactive,isReactive
-
未完待续
-
小程序部分
待补充