面试记录

124 阅读14分钟

第一家

SPA 页面优缺点?

单页面应用:

单页面应用程序将所有的活动局限于一个Web页面中,在该Web页面初始化时加载相应的HTML、JavaScript 和 
CSS,一旦页面加载完成,单页面应用哪个不会因为用户的操作而进行页面的重新加载或者跳转,取而代之利用
javascript 动态的变化HTML的内容,从而实现UI与用户的交互,避免了页面的重新加载,单页面应用可以提
供较为流程的用户体验

优点:

1)良好的交互体验(内容该表不需要重新加载整个页面,获取数据也是通过ajax异步获取,没有页面之间的切换
不会出现白屏现象,也不会出现假死并有"闪烁"现象,页面显示流畅)
2)良好的前后端工作分离模式(后端不在负责模板渲染,输出页面工作,后端API通用化,同一套后端程序代码
不用修改就可以用于web界面,手机,平板灯多种客户端)
3)减轻服务器的压力(单页面应用相对服务器压力小,服务器只用出数据就可以了,不用管展示逻辑和页面合成
吞吐能力会提高几倍)

缺点:

1)首屏加载慢  vue-router 懒加载 、 cdn 加速 异步加载组件 SSR服务端渲染
2)不利于SEO搜索引擎 服务端渲染 页面预渲染  路由采用H5 history模式
3)不适合大型项目的开发,大型项目会涉及大量的DOM操作,复杂的动画效果,也就不适合使用vue react框架进
行开发。

iframe 标签的优缺点?

iframe 是一个内联框架(行内框架),可以包含另外一个文档的内容
优点:
    1)能原封不动的展示内嵌网页
    2)如果有多个网页引用iframe,那么只需要修改iframe 内容,那就可以实现调用的每一个页面内容的更改,
    方便快捷
    3)如果需要加载缓慢的第三方内容如图标和广告,这些问题可以用iframe解决
缺点:
    1)产生很多页面,不便于管理
    2)不利于SEO爬虫
    3)很多移动设备不兼容
    4iframe框架会增加服务器的http请求,对大型网站是不可取的
    5url不同步,如果刷新页面iframe中的页面路由会丢失。
    6)全局上下文完全隔离,内存变量不共享。
    7)慢
    8UI不同步,比如遮罩层只能在iframe 框下,不能覆盖整个浏览器。

v-model 实现方式及原理?

v-bind动态绑定一个value属性v-on给当前元素绑定input事件
原理:
1)new vue()首先执行初始化,对data执行响应化处理,这个过程发生在observe中
2)同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在complie中
3)同时定义一个更新函数Watcher,将来对应数据变化时Watcher 会调用更新函数
4)由于data的某个key在一个视图中可能出现多次,所以每个key都需要一个管家Dep来管理多个Watcher
5) 将来data 中数据一旦发生变化,会找到对应的Dep,通知所有的Watcher执行更新函数的流程图

为什么不能父组件给子组件传值?

vue中父组件向子组件传值时,其父子prop之间形成单向下行绑定,反过来则不行,这样会防止子组件意外改变父
组件的值,从而数据流变的难以理解;另外,每次父组件的数据发生更新时,子组件的都会刷新到最新的数据,但
不能改变子组件内部改变prop,这样浏览器就会发出警告。

webpack 打包包体积过大的时候怎么优化的?

优化loader配置  通过配置include exclude
合理使用reslove.extensions 合理的找到对应的文件扩展名
优化 reslove.modules 指定只从node_moudles下找第三方模块
优化reslove.alias 减小../../../查找过程
使用DLLPlugin 插件 东塔链接库,为实现windows数据共享,方便后续其他项目使用
使用cache-loader 性能开销大的loader 添加到磁盘中,显著提升二次构建速度
terser启动多线程 多线程构建
合理使用sourceMap 

什么情况下不能使用箭头函数?

代码简洁易懂,方便更新与维护。this keyword 变得更灵活,可以根据不同的情况/区域发生变化。适合与lambda函数相结合,例如与JS的foreach,every,mapfilter等相结合

不能使用箭头函数的场景: 

需要在object里加入方法时,箭头函数没有用。
创建constructor时,箭头函数没有用。这也是为什么不能用new与箭头函数相结合。
没有prototype属性
不能作为事件中callback function
性能问题:不能被及时的垃圾回收

display block visiblity:hidden 区别?

display:nonde 不占位  visbility:hidden 只是让元素变得透明占位

vue 父子组件的执行顺序?

父beforeCreate --- 父 created --- 子beforeCreate -- 子created ---父beforeMount --- 子beforeMount --- 子mounted -- 父mounted

父 beforeUpdate -- beforeUpdate -- 子updated --- 父updated

Vue2 源码解析

为什么不用class 的方式而用function的方式呢?

类只能通过继承的方式实现,会导致整个框架特别重,而且不确定到底继承哪个?
function 则通过原型的方式继承,更叫轻量级

import link 引入样式的区别?

从属性关系区别
@import 是css 提供的语法规则,只有导入样式表的作用,Link是html提供的标签,不仅可以加载css换可以定义
RSS,rel 连接属性等
加载顺序区别
加载页面时,link标签引入的css被同时加载 @import引入的css将在页面加载完毕后被加载
兼容性的区别
@import是css2.1才有的语法,故只可在IE5+才能识别到 ,link 作为HTML标签不存在兼容性
DOM 可控性区别
可以通过JS操作DOM,插入link标签来改变样式,由于DOM方法是基于文档的,无法是用@import方法插入样式
权重的区别
import导入的样式会被置于顶部导致重叠覆盖 
CSS 权重优先级顺序简单表示为:!important > 行内样式 > ID > 类、伪类、属性 > 标签名 > 继承 > 通配符

标签页之间的通讯都是怎么实现的?

localStorage  websocket sharedWorker cookie 

vue2 data 必须为函数吗?

根组件为单例,所以data可以为函数也可以为对象不会产生污染现象,组件则必须为函数,因为extends时,data会进行合并
key 相同则会指向同一个地址,A组件数据变化则会影响B组件数据变化,导致数据污染。

vue给data上直接添加新的属性?

vue不允许给已经创建的实例添加新的响应式属性,若想实现数据与视图的同步更新必须采取下面三种解决方案:
Vue.Set()
Object.assgin()
$forceUpdated()
 $nextTick 数据已经更新页面未更新则 $nextTick创建一个异步操作队列tick,等待数据挂载完成执行新的异
    步线程挂在数据,即使多次修改页面也只会刷新一次

v-if v-for 哪个优先级高?

v-for 比v-if vue源码中先判断,所以一般是v-if添加到template上先判断是否展示然后在进行for循环 
v-if 删除DOM 由falsetrue 会触发beforecreate created beforemount mounted
v-show  display:none的方式
v-if 开销比 v-show大
需要频繁切换DOM 则用v-show

key是什么?

key是vue中的diff算法的一种优化策略,key是给每一个vnode加上一个唯一的id,可以根据key 更快更准确地找
到对应的vnode节点

vue常用的修饰符有?

表单修饰符:trim number lazy
事件修饰符:
once prevent(阻止默认事件行为) 
stop(阻止事件冒泡) self(当前元素触发自身时触发的处理函数)
capture(使事件触发从包含这个元素的顶层从开始往下触发) 
passive(移动端onscroll会使网页卡顿,添加这个相当于给onscroll事件添加lazy属性)
native 让组件变成像html内置标签那样监听根元素的原生事件,否则组件上使用v-on只会监听自定义事件
鼠标按键修饰符:
left 左键点击
right:右键点击
middle中键点击
键盘修饰符:
onkeyup  
onkeydown
键盘修饰符:enter tab delete space esc up  ctrl alt meta shift
v-bind 修饰符:async prop camel

vue 跨域解决方式?

JSONP 
CROS: 跨域资源共享 只要服务器声明允许访问来源就可以
Proxy vue.config.js中配置
nginx 反向代理

自定义指令

directives:{
    focus::{
        inserted:function(el,binding ,vnode , oldvnode){
            el.focus()//页面加载完成后自动让输入框获取到焦点的小功能
        }
    }
}
<input v-focus/>
bind: 只调用一次指令第一次绑定到元素上调用
inserted 被绑定元素插入到父节点时调用
update 所在组件vnode 更新时调用
componentUpdated 指令所在组件的Vnode 以及子组件的Vnode全部更新完成后调用
unbind 指令与元素解绑时调用

for forEach区别?

for循环是通过生成数组的索引下标 forEch item 是类数组含义的方法
for 可调用break forEach 报错
for return可终止循环 forEach不可以,只能使用throw error /删除数组的方式
for循环可以通过控制index值控制循环的执行,forEach 不行
setTimeout 在for循环中异步执行只输入最后一次的值连续n次,在forEach中同步执行

防抖

当事件触发时,相应函数不会立即触发,而会被推迟执行,等到密集触发事件没有在执行时再触发相应的请求
应用场景:
    输入框频繁的输入内容搜索或者提交信息
    频繁的点击按钮,触发某个事件
    监听浏览器滚动事件
    监听用户缩放浏览器的resize事件
 function debounce(fn,delay=1000){
    let time = null;
    function _debounce(...args){
        if(time!=null){
            clearTimeout(time)//清除time方法
        }
        time = setTimeout(()=>{
            fn.apply(this,args)
        }) //防抖
    }
    return _debounce
}

节流

节流是指当事件触发时,会执行这个事件的响应函数,频繁触发只执行第一次,其他的等下个周期执行
function throttle(fn,interval){
    let lastTime =0;
    const _throttle = function(...args){
        const nowTime = new Date().getTime();
        const remainTime = nowTime - lastTime
        if(remianTime - interval >0){
            fn.apply(this,args)
            lastTime = nowTime
        }
    }
    return _throttle
}

第一次会立即执行

闭包 作用主要是用来读其他函数内部的变量

作用:函数作用域
问题:会导致内存泄漏,无法被垃圾回收机制回收
解决:变量赋值为null 

动态路由的配置

第一种:前端通过策略模式实现3套权限动态赋予用户相应的路由权限
第二种: 后台返回相应的name,前端通过循环筛选出相应匹配路由,然后动态添加,用户即可访问权限控制页面

query 和 params区别?

使用params传参只能用name来引入路由,即push里面只能是name:’xxxx’,不能是path:’/xxx’,因为params只能用name来引入路由,如果这里写成了path,接收参数页面会是undefined!!!
使用query 可以使用path 来引入路由
params是路由的一部分,必须要在路由后面添加参数名。query是拼接在url后面的参数,没有也没关系
query 相当于get请求,params相当于post请求

当页面渲染缓慢的时候,排查流程?

F12 network 看它的加载过程
1)分析具体是什么原因导致加载缓慢,前端包过大,还是后台请求返回慢
2)减少http请求,提高接口速度
3)懒加载
4)静态资源放cdn
5)keep-alive
6)本地缓存

微博评论数过多应该怎么存储?

cookie
localStorage  sessionStorage
indexDB
webSQL
application Cache

http:406 405区别?

405 禁用请求中指定的方法  406 无法使用请求内容特性响应请求页面

header 请求字段?

Authorization  keep-alive connection cache-control expries 

localStorage sessionStorage?

存储本地  存储内存中 

typescript 一个箭头函数返回什么? 函数体

解释this 

当纯函数调用
var x = 1;
function test() {
   console.log(this.x);
}
test();  // 1作为对象方法调用
function test() {
  console.log(this.x);
}
var obj ={};
obj.x =1;
obj.m = test;
obj.m()//1
作为构造函数调用
function test(){
    this.x =1;
}
var obj = new test();
obj.x //1
apply call bind 改变

promise async await setTimout执行时机的区别?

promise 是微任务 then 宏任务
setTimeout 宏任务
async 微任务 await 宏任务

什么是异步操作?

一次可以执行多个任务,返回相应的执行结果给微任务队列

跨域?

访问域名端口不一样的地址
解决方式nginx webpack 代理
axios jsonp
后端设置cros  Access-Control-Allow-Origin  允许访问
websocket HTML5的持久化协议,实现浏览器与服务器的全双工通信,同时也是跨域的一种解决方案
iframe 标签

css flex 中有什么属性?

flex-direction  flex-basis flex-flow flex-grow flex-shrink flex-wrap

怎么垂直居中?

1. line-height text-align
2. text-align:center  display:inline-block  vertical-align:middle
3.position: absolute  left:50% top:50% transform:(-50%,-50%);
4 text-align:center  margin:auto
5.display:flex align-items:center justify-content:center

BFC

两边float 或者绝对定位 使用margin为盒子大小中间自适应

TS 中定义枚举类型?

enum pages{
    one=10,
    two:2;
    thre:3
}

vue中组件通信

props bus parent root provude inject vuex pina 

vue3获取组件实例的方法是?

createApp   getCurrentInstance

vue.watch 函数的基本用法:嵌套的响应式对象有什么方法?

object.definepropety  proxy

[2,[3,[33,[333]]]] --->[2,3,33,333] 抹平数组

方法1 arr.flat(Infinity);
方法2 function a(args){ for(var i=0; i<args.length; i++){    if(args.length>0){a()}}}
方法3 const newarr = (arr) =>{
    return arr.reduce((prev,cur)=>{return pre.concat(Array.isArray(cur)?newarr(cur):cur)},[])
} 

 前端的强缓存 协商缓存

强缓存是客户端直接查看本地的缓存文件是否过期,如果没有过期就直接取用 
expires(过期时间)cache-control(相对时间)
协商缓存指的是客户端去询问服务器对应的文件是否有更新,如果有更新才会重新请求
依靠的是上次响应头上的last-modified(最后更新时间)及Etag(内容变更的标识)来确认文件是否有更新
更新去请求更新资源,没有更新就返回304/200 去取本地资源

pnpm yarn npm 区别?

npm 基于Node.js的包管理工具,优点:软件资源丰富,缺点:下载慢
pnpm:共享相同依赖减少磁盘的占用,它使用硬链接或符号链接来共享依赖项
yarn:安装速度快,并行安装缓存机制qin

websocket

http 请求头添加 Upgrade:websocket 实现双向通信  Connection: Upgrade 表示客户端希望连接升级
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==  客户端发送的base64编码的密文,用于简单的认证秘钥服务端必须返回相应的Sec-WebSocket-Accept应答,否则客户端抛出错误Sec-WebSocket-Version:13表示websocket版本协议是 ws wss 分别代表明文和密文 默认端口80443,几乎和http一致
优点:
较少的开销控制,数据包头部协议较小,不同于http每次请求都携带完整的头部
更强的实时性
保持创连接状态:创建连接后,可省略状态信息,不同于http 每次请求都携带身份验证
更好的二进制支持
支持扩展:用户可扩展websocket协议,自定义子协议
更好的压缩效果:在webscoket扩展协议支持下,可以延用之前内容的上下文,在传递类似数据时,可以显著的提高压缩率

输入url 后

url 解析--- DNS 域名解析 --- TCP 协议 ---- http请求 --- 响应请求 ----页面渲染

http协议

三次握手四次挥手
http1.0 
浏览器服务器只保持短暂的链接,浏览器每次请求都要与服务器建立一个TCP链接
http1.1
引入持久化链接,即默认TCP链接不关闭,可以被多个请求复用,同一个TCP里,只可以循序渐进发送多个数据请求,新增请求头响应头 请求方法
http2.0
采用二进制,完全多路复用,只需要一个请求即可实现并行,使用报头压缩降低开销,服务器推送

为什么说https 比 http安全?

http 明文发送,内容容易被窃听到,https 多了SSL/TSL加密证书

请求突然中断

try catch
catch 捕获 处理

堆栈顺序

栈:先进后出
堆:先进先出

创建节点

createElement 创建元素
createTextNode 创建文本
createDocumentFragment 创建文档碎片
createAttribute 创建属性节点
querySelector 获取节点
querySelectorAll 获取所有与之匹配的元素节点

标准事件阶段

捕获阶段 -- 目标阶段 ---冒泡阶段

事件委托的优点: 减少页面所需内存,提升整体性能 动态绑定减少重复工作

浅拷贝

function shallowClone(obj) {
 const newObj = {};
 for(let prop in obj) {
 if(obj.hasOwnProperty(prop)){
 newObj[prop] = obj[prop];
 }
 }
 return newObj;
}js 方式 Object.assign() / Array.prototype.slice() / Array.prototype.concat()
Object.assign({},copyobj)
const fxArrs  = fxArr.slice();
const fxArrs = fxArr.concat();
const fxArrs = [...fxArr];

深拷贝(深拷贝开辟一个新的栈,两个对象属性相同,对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性)

_.cloneDeep()  jQuery.extend()  JSON.stringfy()
手写循环递归

javascript 实现函数的缓存 闭包 柯里化 高阶函数

const add = (a,b) => a+b;
const calc = memoize(add);
calc(10,20);
calc(10,20);//缓存

js操作方法

concat()
删 slice substr substring
改 trim() trimLeft() trimRight()  repeat() padStart() padEnd() toLowerCase() toUpperCase()
查 chatAt() indexOf() startWith() includes()
转化方法 split() match() search() replace()
数组常见的操作方法
增 push() unshift() splice() concat()
删 pop() shift() splice(1, 1, "red", "purple")//在删除index 1 添加两个 slice()indexOf() includes() find()
排序 reserve() sort()
转换方法 join() 
迭代方法 some() every() forEach() filter() map()
some 对每一项传入测试函数,有一个元素返回true 则这个方法返回true
every 对数组每一项运行传入测试函数 全部返回true 则这个方法返回true 
forEach 对数组的每一项运行传入的函数 没有返回值
for 循环 return 可终止循环
filter 对数组每一项都运行传入的函数,函数返回true 的项会组成数组之后返回
map 对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组
reduce

缓存的几种方式?

cookie sessionStorage localStorage indexedDB
cookie:可设置有效期,默认关闭浏览器后失效
sessionStorage:有效期仅保存当前页面,关闭当前会话页或者浏览器会失效
localStoarge:不手动删除一直有效

原型链 作用域链顶级分别是?

原型链顶级是 Object 作用域链 window

箭头函数的作用是?

简洁
捕获其所在上下文的this,作为自己的this
箭头函数不绑定arguments 取而代之用rest 参数解决,同时没有supernew.target
call apply bind 并不会改变箭头函数中this的指向
箭头函数没有原型对象 prototype这个属性
不能使用yeild 关键字 不能用Generator函数

new object()  object.create()

new object() 创建一个空的javascript对象
let obj = object.create(foo.prototype) 为了把obj挂到原型链上 

事件循环机制 : 宏任务  微任务

webpack loader  pulgins 的区别?

loader 文件加载器,操作的是文件将A通过loader 转化为B 单纯的文件转化过程
pulgins 是一个扩展器,丰富webpack 本身 增强功能,针对的是在loader结束之后,webpack打包的整个过程

常见数组的操作

push pop unshift shift slice splice reverse反转数组

性能优化

浏览器:
减少http 请求
使用http2.0
设置浏览器缓存策略
白屏时间做加载动画
资源:
静态资源cdn 
静态资源单独域名
gzip 压缩
服务端渲染
css 放在文件头部,js 放置文件底部
图片 :
字体图标代替图片图标
精灵图
图片预加载
图片懒加载
使用png 格式图片
小于10k的图片可以打包为base64格式
代码:
慎用全局变量
缓存全局变量
减少重绘回流
节流防抖
少用闭包,减少内存泄漏
减少数据读取次数
文档碎片优化节点加载
减少判断层级
webpack
减少代码体积
按需加载
提取第三方库代码
weboack dll 优化

原型原型链

function Person(name) {
 this.name = name;
 this.age = 18;
 this.sayName = function() {
 console.log(this.name);
 }
}
var person = new Person('person');
1)构造函数的原型属性 === 实例化对象的原型 person.__proto__ === Person.Prototype
2)Person.Prototype指向 constructor ----constructor中包含constructor Prototype  
---- prototype 内置属性object --- __proto__:object ---  __proto__:null 原型链寻找结束
person.__proto__.constructor.__proto__ == Object.__proto__
Person.prototype.__proto__ === Object.prototype
Array.prototype.constructor.__proto__ == Object.__proto__
Array.__proto__.constructor.__proto__ == Object.__proto__
person.__proto__.constructor.prototype.__proto__.__proto__ = null 查找到值为null的数据
person.__proto__.constructor.__proto__.__proto__.__proto__ = null
person.__proto__.__proto__ == Object.prototype //true
Array.__proto__ == Object.prototype //true

画一个三角形?

<div class="samrec"></div>        .samrec {            width: 0px;            height: 0px;            border-left: 100px solid red;            border-bottom: 100px solid transparent;        }

for in for of

for in  key  --- array index 是字符串 不可以遍历数组 遍历对象 遍历对象的原型
const object = { a:1 , b:2 }
object.__proto__ = { c:3 , d:4 }
for(let key in object) {
    console.log(key)
}
for of item 遍历数组

ES6

var let const
...扩展运算符
Array.from   Array.from([1, 2, 3], (x) => x * x)
Array.of     Array.of(1,3,5) //[1,3,5] 参数不少于3个,少于部分空Array.of(3)//[ , , ,]
copyWithin() find() findIndex() fill() entries() keys() values() includes() flat() flatMap()