西安前端面试题总结

技术

1.flex布局
Flex是Flexible Box的缩写 flex布局表示弹性布局,可以为盒状模型提供最大的灵活性
属性:
flex-direction  设置容器主轴的方向
flex-wrap  设置当项目在容器中一行无法显示的时候如何处理。
flew-flow 是flex-deriction和flex-wrap属性的简写,默认值为[row nowrap]
justify-content 用于设置项目在容器中的对齐方式
align-items 项目在交叉轴上是如何对齐显示的
align-content 定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用
2.事件循环机制
js是通过事件循环机制来实现js得单线程异步
就是是单线程运行得
异步要基于回调来实现
evevt loop 就是异步回调得实现原理

callcstack 执行上下文   event queue 待执行队列  webapis 浏览器额给我们提供的线程 
 
 当执行到call stack里面的异步任务时候 会把异步任务放到对应的webApis里面  当异步任务到期之后 会放到待执行任务队列里面 当js里面的任务执行完后 js会去event queue里面查看是否有到时间需要执行的 如果有 就拿走执行  然后等任务执行完之后 继续循环去查看 直到所有任务执行完
 
事件循环机制的2个重要部分: 
     在分线程执行的管理模块: 定时器/ajax/dom事件
     保存待执行的回调函数的事件队列(Event queue)/任务队列(Task queue)
     
宏任务和微任务:
  宏任务: 
         script(整体代码)
		setTimeout,
		setInterval,
		Ajax,
		DOM事件监听
		postMessage (H5, 向其它窗口分发异步消息)
		setImmediate(立即执行, Node.js 环境
   微任务:
        Promise,
		async/await,
		mutationobserver(H5, 监视DOM元素变化
		
宏队列与微队列:
		宏队列: 用来保存n个宏任务的队列容器
		微队列: 用来保存n个微任务的队列容器
		
执行顺序:
       第一步: 先执行script宏任务
		第二步: 再依次取出微列中的所有微任务执行 ==> UI线程更新界面
		第三步: 再取出宏队列中第一个宏任务执行
		第四步: 再依次取出微列中的所有微任务执行 ==> UI线程更新界面
		后面重复三,四步
3.promise
Promise是一个对象 用来标识一个异步操作的最终完成(失败)及其结果值
优点:
   指定回调的时机非常灵活 可以在请求前 请求后(结果回来之后)
   就是因为这个特点 所以可以完美的去解决回调地狱的可读性问题
 
 为什么要有promise:
     在遇到promise之前,异步仍然是要用的,但是那会使用的都是纯回调函数来处理异步操作的 纯回调函数处理异步有缺点:就是指定回调的时机,是固定的,不够灵活,所以一旦形成回调地狱 那么,就没办法,回调地狱只是代码的可读性很差,不代表有错,但是给人的体验不好
      
promise的三种状态:
	pending  resolved/fulfilled   rejected
promise状态的两种变化:
    pending --> resolved
	pending --> rejected
	注意: 变化是不可逆, 且只能变一次 

promise里面的Api:
   
   then: 
    	总是返回一个新的promise
		新promise的结果状态由then指定的回调函数执行的结果决定
  		当返回值是一个非promise值,永远是成功的
   		当返回的值是一个 promise值得时候,此时需要判断
         返回一个初始状态的promise实例对象,result的值为pending状态
         返回一个成功状态的promise实例对象,result的值为fulfilled状态
         返回一个失败状态的promise实例对象,result的值为rejected状态
   		抛出一个错误(或者其他数据类型),result的值为rejected 状态
   		
   	catch:
   	     成功走.then 失败走.catch
 		 异常(错误穿透):当我们不写失败的回调的时候,可以一直向后.then()
     	如果出现一个失败的回调,在往之后走,就变成成功的回调
     	
     all:
        
     	参数:数组 
 		功能:批量/一次性发送多个异步请求
  		返回值:是一个新的promise对象
  		新promise对象的值由参数中所有的promise实例对象来决定
  		如果都成功,新的promise对象就成功
  		但凡有一个失败,新的promise对象就失败,值是失败promise对象的值,如果有多个失败的,值是参数中写在前面的失败的那个
   
   
终止promise链的方法:
         有且只有一种方法,使用pending状态的peomise中断 return new Promise(() => {})
4.cookie
1.Cookie是什么
	HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据(一般为4KB),它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的HTTP协议记录稳定的状态信息成为了可能
2.Cookie的应用场景
	1.会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
	2.个性化设置(如用户自定义设置、主题等)
	3.浏览器行为跟踪(如跟踪分析用户行为等)
3.Cookie的优缺点
  Cookie的优点:
	1.用来弥补HTTP无状态特性的一种方案。
	2.存储在客户端,不占用服务器的资源,减少服务器压力。
  Cookie的缺点主要是安全和隐私方面:
	1.可以被用户主动禁用浏览器的Cookie功能,可以通过window.navigator.cookieEnabled属性查看当前浏览器Cookie是否开启。
	2.可以被用户直接操作,Cookie保存在浏览器,并且是明文存储的,能够直接被用户查看、修改或删除。
	3.若Cookie中含有关键敏感信息,可能会被不法分子通过跨站脚本攻击(XSS)、跨站请求伪造(CSRF)等手段获取到Cookie造成严重后果。
5.防抖节流
出现的原因: 事件触发非常频繁,而且每一次的触发,回调函数都要去执行(如果时间很短,而回调函数内部有计算,那么很可能出现浏览器卡顿)

理解 : 
  
  函数节流 :在函数需要频繁触发时 函数执行一次后,只有大于设定的执行时间后才会执行第二次,节流的第一次是立即执行 最后一次是拖延执行({ 'trailing': false } 解决最后一次拖延的问题). 适合多次事件按             时间做平均分配触发  适用场景 :窗口调整 (resize)  页面滚动(scroll)  按钮秒杀
  
  函数防抖: 在函数需要频繁触发时,在规定时间内 只让最后一次生效,适合多次触发事件一次响应的情况  适用场景输入框实时搜索联想

本质:
     多次变少次(固定事件段内只执行一次) 是节流 
     多次变一次(最后一次) 是防抖

作用: 1 防止对后台造成没必要的压力
     2 解决浏览器的卡顿现象
6.vue2和vue3的区别
1、双向数据绑定原理不同
vue2:vue2的双向数据绑定是利用ES5的一个APIObject.definePropert() 对数据进行劫持,结合发布订阅模式的方式来实现的。

vue3:vue3中使用了ES6的Proxy API对数据代理。相比vue2.x,使用proxy的优势如下:

defineProperty只能监听某个属性,不能对全对象监听
可以省去for in,闭包等内容来提升效率(直接绑定整个对象即可)
可以监听数组,不用再去单独的对数组做特异性操作vue3.x可以检测到数组内部数据的变化。
2、是否支持碎片
vue2:vue2不支持碎片。

vue3:vue3支持碎片(Fragments),就是说可以拥有多个根节点。

3、API类型不同
vue2:vue2使用选项类型api,选项型api在代码里分割了不同的属性:data,computed,methods等。

vue3:vue3使用合成型api,新的合成型api能让我们使用方法来分割,相比于旧的api使用属性来分组,这样代码会更加简便和整洁。

4、定义数据变量和方法不同
vue2:vue2是把数据放入data中,在vue2中定义数据变量是data(){},创建的方法要在methods:{}中。

vue3:,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发。使用以下三个步骤来建立反应性数据: 

从vue引入reactive;
使用reactive() 方法来声明数据为响应性数据;
使用setup()方法来返回我们的响应性数据,从而template可以获取这些响应性数据。
5、生命周期钩子函数不同
vue2:vue2中的生命周期:

beforeCreate 组件创建之前
created 组件创建之后
beforeMount 组价挂载到页面之前执行
mounted 组件挂载到页面之后执行
beforeUpdate 组件更新之前
updated 组件更新之后
vue3:vue3中的生命周期:

setup 开始创建组件
onBeforeMount 组价挂载到页面之前执行
onMounted 组件挂载到页面之后执行
onBeforeUpdate 组件更新之前
onUpdated 组件更新之后
而且vue3.x 生命周期在调用前需要先进行引入。除了这些钩子函数外,vue3.x还增加了onRenderTracked 和onRenderTriggered函数。

6、父子传参不同
vue2:父传子,用props,子传父用事件 Emitting Events。在vue2中,会调用this$emit然后传入事件名和对象。

vue3:父传子,用props,子传父用事件 Emitting Events。在vue3中的setup()中的第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。

7、指令与插槽不同
vue2:vue2中使用slot可以直接使用slot;v-for与v-if在vue2中优先级高的是v-for指令,而且不建议一起使用。

vue3:vue3中必须使用v-slot的形式;vue3中v-for与v-if,只会把当前v-if当做v-for中的一个判断语句,不会相互冲突;vue3中移除keyCode作为v-on的修饰符,当然也不支持config.keyCodes;vue3中移除v-on.native修饰符;vue3中移除过滤器filter。

8、main.js文件不同
vue2:vue2中我们可以使用pototype(原型)的形式去进行操作,引入的是构造函数。

vue3:vue3中需要使用结构的形式进行操作,引入的是工厂函数;vue3中app组件中可以没有根标签。
7.watch和computed的区别
computed 计算属性必须同步返回计算结果, 而watch中可以在异步操作后更新数据显示
watch 可以深度监视, 计算属性只是监视了使用到的数据 计算属性有缓存, 多次读取显示只计算一次 可以写异步
method: 主动调用、每调用一次都会触发一次
8.深浅拷贝思路
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址
即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址

深拷贝开辟一个新的栈,两个对象属性完成相 同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
 
区别:
	浅拷贝只复制属性指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,修改对象属性会影响原对象
	深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
	
数据回显的时候 用过 还有就是在做权限管理的时候 动态添加路由的时候用过 当时用的是loadsh工具库里面的clonedeep
9.输入url到页面渲染具体步骤
    1、浏览器向 =>DNS 服务器请求=>解析 URL 的域名=>所对应的 IP 地址;
    2、解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;
    3、浏览器发出读取文件的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
    4、服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
    5、释放 TCP连接;
    6、浏览器将 html 文本解析,渲染布局
10.三次握手四次挥手
三次握手:
TCP建立连接的过程我们称之为3次握手。
(1)第一次握手
PC1使用一个随机的端口号向PC2的80端口发送连接请求,此过程的典型标志为SYN控制位为1,其他五位为0。
(2)第二次握手
这次握手实际上是分为2个步骤完成的。
首先,PC2收到PC1请求,向PC1回复确认信息。
并且,PC2也向PC1发送建立连接请求。
(3)第三次握手
PC1收到PC2回复,也要向PC1回复一个确认信息。

四次挥手:
TCP断开连接得过程分为4步,我们称之为四次挥手。
(1)服务器向客户端发送FIN,ACK位置1得TCP报文段。
(2)客户端向服务器返回ACK位置1得TCP报文段。
(3)客户端向服务器发送FIN,ACK位置1得TCP报文段。
(4)服务器向客户端返回ACK位置1得TCP报文段。
在TCP断开连接的过程中,有一个半关闭得概念。TCP一端可以中止发送数据,但是仍然可以接收数据,称之为半关闭:
(1)客户端发送FIN,半关闭了这个链接。服务器发送ACK接受半关闭。
(2)服务器继续发送数据,而客户端只发送ACK确认,不发送任何数据。
(3)当服务器所有数据传输完毕,就发送FIN报文段,客户再发送ACK报文段,这样就关闭了TCP连接。
11.http协议以及常用api
HTTP协议的基本知识
	介绍:全程超文本传输协议,用来在浏览器和服务器上来传输超文本信息,后来发展到服务器与服务器之间,app和服务器都有使用
	特点:通讯双方分文客户端和服务端,目前所有HTTP协议是基于TCP协议的,所有首先要创建一个TCP连接
一定是客户端发送请求给服务端,TCP连接可以用一段时间,一段时间不用会消失
一般常用的请求方法:get , post, put, delete
12.react和vue的区别
React与Vue的相同点
(1)都支持服务器渲染;
(2)都是数据驱动视图;
在以前,我们需要频繁操作DOM实现页面效果。而Vue和React就隐藏了DOM的频繁操作,采用数据驱动视图的方式,只需要关注数据的变化。
(3)都遵循组件化思想;
React和Vue都遵循组件化思想,它们把注意力放在UI层,将页面分成一一些细块,也就是组件,组件之间组合嵌套就形成最后的网页界面。
(4)都使用虚拟DOM;
(5)都有状态管理;
react有redux,vue有vuex。

不同点
(1)框架本质不同;
	Vue本质是MVVM框架,是由MVC发展来的;
	React是前端组件框架,是由后端组件演化而来的。
(2)数据流不同;
Vue实现双向绑定,在vue1.0中有两种方法可以实现双向绑定,父子组件之间的props以及组件与DOM直接的v-model。vue2去掉了第一种双向绑定方法,通过v-model实现数据双向绑定。
React一直不支持双向绑定,提倡的是单向数据流(onChange/setState)。
(3)监听数据变化的实现原理不同;
Vue通过getter,setter以及一些函数的劫持,能精确知道数据的变化。
React是通过比较引用方式(diff)进行的,当应用的状态改变时,全部组件都会重新渲染。
(4)组件写法差异;
	React推荐的做法是JSX + inline style, 也就是把 HTML 和 CSS 全都写进 JavaScript 中;
	Vue 推荐的做法是 template 的单文件组件格式,即 html,css,JS 写在同一个文件(vue也支持JSX写法)
(5)渲染过程不同。
Vue可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
React在应用的状态被改变时,全部子组件都会重新渲染。通过shouldComponentUpdate这个生命周期方法可以进行控制。
(6)在state上的不同;
React中,state对象需要用setState方法更新状态;
在Vue中,state对象不是必须的,数据由data属性在vue对象中管理。
13.数据类型
分为基本数据类型和引用数据类型
基本数据类型:
  es5中 有数字Number 字符串String' 布尔Boolean null undefined
  es6+:  Symbol     Bigint
 引用数据类型 : 数组  函数 对象(内置对象(Math,正则,Data...),包装对象 (String,NUmber,Boolean))
14.v-model的原理
其核心就是,一方面modal层通过defineProperty来劫持每个属性,一旦监听到变化通过相关的页面元素更新。另一方面通过编译模板文件,为控件的v-model绑定input事件,从而页面输入能实时更新相关data属性值
15.子组件如何调用父组件的方法
1、子组件中通过“this.$parent.event”来调用父组件的方法。
2、子组件用“$emit”向父组件触发一个事件,父组件监听这个事件即可。
3、父组件把方法传入子组件中,在子组件里直接调用这个方法即可。
16.vue2 的 create 和 mounted 的区别
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
其实两者比较好理解,通常created使用的次数多,而mounted通常是在一些插件的使用或者组件的使用中进行操作,比如插件chart.js的使用: var ctx = document.getElementById(ID); 通常会有这一步,而如果你写入组件中,你会发现在created中无法对chart进行一些初始化配置,一定要等这个html渲染完后才可以进行,那么mounted就是不二之选。
17.BFC
直译为 "块级格式化上下文" ,把BFC理解成一块独立的渲染区域,BFC看成是元素的一种属性,当元素拥有了BFC属性后,这个元素就可以看做成隔离了的独立容器。容器内的元素不会影响容器外的元素.
实现BFC属性的方法:
    1. 浮动元素,float 除 none 以外的值
    2. 定位元素,position的值不是static或者relative。
    3. display 为 inline-block 、table-cell、table-caption、table、table-row、table-row-group、table-header-group、table-footer-group、inline-table、flow-root、flex或 inline-flex、grid或 inline-grid
    4. overflow 除了 visible 以外的值(hidden,auto,scroll)
    5. 根元素<html> 就是一个 BFC
18.作用域链
什么是作用域:
	 变量起作用的范围或者区域 叫做作用域 作用域是虚拟的 写完代码就有了
作用域的作用 :隔离变量 防止污染
作用域的分类: 
            全局作用域
            函数作用域
            块级作用域:非函数的花括号里面用let和const声明 才会有块级作用域
            
什么是作用域链:
     程序查找变量的过程,叫做作用域链 本质是由内到外的各执行上下文当中变量对象组成的数组
     作用域链是真实存在的 函数调用才会形成作用域链,函数定义的时候,形成作用域
     
作用域链如何形成的:
     函数定义的时候 在函数对象身上就保存了函数调用的时候上一级的作用域链[[scopes]]
     函数调用的时候,会把自己执行上下文当中收集的变量对象添加到上一级作用域链数组的头部,形成自己的作用域链
19.垂直居中
` <div  class="wrap">
        <div  class="box"></div>
   </div>`
方法1(常用):display:flex
  `.wrap{
      width:300px;
      height:300px;
      border: 1px solid red;
      display:flex;
      justify-content:center;
      align-items:center;
  }
  .box{
      height:100px;
      width:100px
      boder:1px solid blue;
  }`
方法2: table-cell
`        .wrap{
            width: 300px;
            height: 300px;
            border: 1px solid red;
            display: table-cell;
            text-align: center;
            vertical-align: middle;
        }
        .box{
            width: 100px;
            height: 100px;
            border: 1px solid blue;
            display: inline-block;
        }
`
方法3: margin,transform配合
`.wrap{
            width: 300px;
            height: 300px;
            background-color: pink;
            /* border: 1px solid red; */
            /*防止外边距塌陷。解决外边距塌陷的方法:
            父元素加overflow:hidden或加上边框*/
            overflow: hidden;
        }
        .box{
            width: 100px;
            height: 100px;
            background-color: plum;
            margin:50% auto;
            transform: translateY(-50%); 
        }
`
方法4:absolute+负margin
`        .wrap{
            width: 300px;
            height: 300px;
            position: relative;
            background-color: plum;
        }
        .box{
            width: 100px;
            height: 100px;
            position: absolute;
            left: 50%;
            top: 50%;
            /*宽高的一半*/
            margin-left: -50px;
            margin-top: -50px;
            background-color: powderblue;
        }
`
方法5 absolute+margin:auto
和方法4类似,当宽度和高度未知时使用
`        .wrap{
            width: 300px;
            height: 300px;
            position: relative;
            background-color: plum;
        }
        .box{
            width: 100px;
            height: 100px;
            position: absolute;
            left: 0;
            top: 0;
            bottom:0;
            right:0;
            margin:auto;
            background-color: powderblue;
        }
`
方法6 强大的grid
`.wrap {
            width: 300px;
            height: 300px;
            display: grid;
            background-color: plum;
        }

        .box {
            width: 100px;
            height: 100px;
            align-self: center;
            justify-self: center;
            background-color: powderblue;
        }
`
20.css优先级
常见权重优先级如下:

!important。在属性后面使用该关键字可覆盖任何其他样式

内联样式

id选择器,如#id

类选择器、属性选择器([attribute])、伪类选择器(a:hover)

标签选择器、伪元素选择器(::before)

通配选择器(*)
权值划分:

第一等级:代表内联样式,style="",权值为1000

第二等级:代表ID选择器,如#id,权值为100

第三等级:代表类,伪类和属性选择器,如.content,权值为10

第四等级:代表标签选择器和伪元素选择器,如div p,权值为1
21.let const和var的区别
1 块级作用域
2 不允许重复声明
3 没有变量提升
4 let /const的全局变量不会添加window的属性
22.闭包
1什么是闭包: 
    闭包是包含了被引用变量的一个容器(不是js对象) 被内部函数对象引用着
     内部函数引用外部函数的局部变量的一个引用关系 ,这个关系是用一个容器对象去描述的 在内部函数对象上
2产生闭包的条件
     1函数嵌套
     2 内部函数引用外部函数的局部变量
     3 调用外部函数(外部函数要调用,内部函数要定义)
     
4什么时候生成闭包?
     执行内部函数定义,也就是创建内部函数对象
     
5闭包的作用:
   1 延长外部函数局部变量的生命周期
   2 让函数外部能间接操作内部的局部变量
  
  
如何用:
    1 外部函数返回内部函数的方法体,用一个变量去接收 永久闭包
    2  定时器

6 区别闭包的三个操作:
    产生闭包: 内部函数对象创建时产生, 包含那个被引用的变量的容器(不是js对象)
    使用闭包:执行内部函数
    释放闭包:让内部函数对象成为垃圾对象 断开指向它的所有引用
  
 7 闭包的优缺点:
      优点:
                    延长局部变量的生命周期
                    让函数外部能间接操作内部的局部变量
      缺点:
                    闭包是不会自己销毁的,形成内存泄漏,泄漏的厉害了会造成内存溢出
                    闭包不能滥用  不用的时候记得销毁

8 闭包的应用?
                具体功能说: 可以说根据id删除品牌(需要显示确定框)
                大的说: 我们定义的很多模块在编译后的代码中都存在闭包 
                
23.diff算法详解
diff算法可以看作是一种对比算法,对比的对象是新旧虚拟Dom。顾名思义,diff算法可以找到新旧虚拟Dom之间的差异,但diff算法中其实并不是只有对比虚拟Dom,还有根据对比后的结果更新真实Dom。
24. $set和$delete
数组的响应式只是重写了七个数组方法 页面初始化完成之后 数据劫持和数据代理有已经完成了 如果我们后期要修改或者删除数组里面的数据 数组里会更改 但是页面不会 因为这两个方法不是响应式的 所以后期又添加了$set和$delete
25.async和await 和promise的区别
什么是什么是async/await?
	async/await是写异步代码的新方式,以前的方法有回调函数和promise
	async/await是基于promose实现的,他不能用于普通的函数
	async/await与promise一样,是非阻塞的
	async/await使得异步代码看起来像同步代码
区别:
	1、函数的前面多了一个aynce关键字。await关键字只能用在aync定义的函数内。async函数会隐士地返回一个promise,该promise的reosolve值就是函数return的值。
	2、也就是说await只能在aync函数内使用
26.移动端适配(响应式)
方法一:@media + rem
    @media
      媒体查询, 可以针对不同的屏幕尺寸设置不同的样式,特别是如果你需要设置设计响应式的页面,@media 是非常有用的。当你重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。
 media + rem适配移动端还有一个不可少的条件
   要在head标签中写入一个meta标签
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, minimum-scale=1">
    作用是让layout viewport = visual viewport,用户也不可缩放页面
    
方法二:手机淘宝 flexible.js
  flexible.js也是rem适配的,它是将设备分成10份,1rem等于1/10 
方法三:vw,vh进行适配
  vw:viewport width(可视窗口宽度)  1vw等于1%的设备宽度(设计稿宽度)
  vh:viewport height(可视窗口高度) 1vh等于1%的设备高度(设计稿高度) 
  这样看来vw,vh其它是最方便的,但是目前兼容性不是特别好
27.vue2的响应式数据原理(数组和对象)
数组:
	数组的响应式是修改了7个方法,push pop shift unshift splice sort reverse  如果使用的是这七个,那么一定响应式,其实本质就是给这些数组方法添加了修改页面的功能而已
对象:
	我们一旦实例化vm实例的时候,vue内部会做数据劫持,把data当中所有的对象属性(包括深层次),都添加了getter和setter,让每个属性都是响应式的
	
为什么数组要重写七个方法?
占用率小,效率高   因为不用给每个元素都添加getter和setter
28.原型原型链
1 什么是原型?
      每个函数对像身上都有一个属性叫做prototype 它所指向的对象  我们称之为原型对象 简称原型 也叫显示原型对象
      每个实例化对象身上都有一个属性__proto__ 它和实例化它的函数对象的prototype指向的是同一个对象 ,常称为隐式原型对象
  
2 显示原型对象和隐式原型对象的区别:
         通过显示原型对象 堆原型对象进行设置操作
         通过隐式原型对象 对原型对象进行读取操作,通常是在查找属性的时候通过隐式原型对象去查找 
          
3 为什么要有原型:
         共享资源 节约内存   
         因为如果实例化多个 内存当中会有开辟多个空间 我们一般把方法添加到原型上 让每个实例化队形通过原型链去访问到原型对象 去调用方法
   
4 什么是原型链:
     从对象的 __proto__ 开始, 连接的所有对象, 就是我们常说的原型链, 也可称为 隐式原型链
      原型链可以认为就是多个隐式原型组成的链式解构 用于对象查找属性
5 原型链的查找规则:
      先在对象自身上查找, 如果有, 直接返回,如果没有, 根据 __proto__ 在原型对象上查找, 如果有, 直接返回,如果没有根据原型对象的 __proto__ 在原型对象的原型对象上查找, 一直查找到Object原型对象为止 ,如果找到了返回, 如果查找不到由于它的 __proto__ 为null, 只能返回undefine
29.vue2组件间通信
1.props
2.自定义事件
3. .sync
4.v-model
5.ref
6.$children / $parent
7.$attrs / $listeners
8.provide / inject
9.全局事件总线
10.Vuex
11.slot
30.v-for里面的key作用
1、 key的作用主要是为了高效的更新虛拟DOM,其原理是vue在patch(补丁)过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
2、 另外,若不设置key还可能在列表更新时引发一些隐蔽的bug。如某行数据不该更新的却更新了。
3、vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
31.hash和history模式的区别,原理
hash模式的实现原理是通过监听hashChange事件来实现的,前端js把当前hash地址对应的组件渲染到浏览器中。
history模式是通过调用 history.pushState方法(或者replaceState) 并且 监听popstate事件来实现的。history.pushState会追加历史记录,并更换地址栏地址信息,但是页面不会刷新,需要手动调用地址变化之后的处理函数,并在处理函数内部决定跳转逻辑;监听popstate事件是为了响应浏览器的前进后退功能。
32.new Vue做了什么
主要执行了_init()方法
在_init方法中 组件实例化属性 $parent $children 等
处理自定义事件
处理插槽信息
最重要的是组件状态初始化,响应式处理等
两个声明周期的调用(beforeCreate, created)
33.组件进行过二次封装没有 怎么封装的
实现静态组件: 模板/样式写好
设计从外部接收的数据: props
设计内部的数据: data

设计基于props和data的计算属性数据: computed
根据props和data数据和computed进行动态显示
34.react 的函数式组件和类式组件的区别
区别			函数组件				      类组件
生命周期		 无		   				     有
this			无	      					有
state			无	      					有
改变state	React Hooks:useState			this.setState()
性能			高(不用实例化)			   低(需要实例化)
35.cookie sessionStorage 和 localStorage 的区别
1.相同点是都是保存在浏览器端、且同源的。
2.cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。
3.存储大小限制也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。这里需要注意的是cookie的数据大小是指单个cookie的大小,而localStorage的大小是单个域名下localStorage所占用的大小总和。
4.数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效; localStorage:始终有效,窗口或浏览器关闭也—直保存,因此用作持久数据,除非用户主动删除; cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭。
5.作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面; localstorage在所有同源窗口中都是共享的; cookie也是在所有同源窗口中都是共享的。

`cookis`
注意事项:

1.前后端都可以写入和获取Cookie。

2.Cookie有数量限制,每个域名下的Cookie数量有限,根据浏览器的不同数量上线不同,如果超出限制浏览器会清除以前设置的Cookie。

3.Cookie有大小限制,最多只有4KB左右。

4.Cookie的名称或值如果包含非英文字母,则写入时需要使用encodeURIComponent()编码,读取时也使用encodeURIComponent()编码。

5.关于Domain,使用JS只能读写当前域或父域的Cookie,无法读写其他域的Cookie。

6.关于Path,使用JS只能读写当前路径和上级路径的Cookie,无法读写下级路径的Cookie。

7.当Name、Domain、Path这3个字段都相同的时候,才是同一个Cookie。

使用:

1.写入:document.cookie='username=xxxx';

2.读取:document.cookie;

`localStorage`
注意事项:

1.单个域名下的localStorage总大小有限制,具体大小浏览器不同大小不同。

2.localStorage中的数据的生命周期为永久生效,除非用remove或者clear手动删除,否则关闭页面或者关闭浏览器后也数据会存在。甚至,关闭电脑再打开数据仍然存在。

3.不同域名下不能共用localStorage

4.以键值对的形式存储使用,并且只能是字符串类型,如果不是字符串类型,也会先自动转化为字符串类型再存进去。

使用:

1.存储:localStorage.setItem('username','alex');

2.获取:localStorage.getItem('username');

3.单独删除:localStorage.removeItem('username');

4.全部删除:localStorage.clear();

5.自动填充:一般是用在form表单,在表单提交的时候把需要填充的数据保存在localStorage,下次输入前取到对应的值进行填充即可。

`sessionStorage`
1.sessionStorage中的数据的生命周期是根据浏览器来的,关闭浏览器时sessionStorage中的数据就会被清空。

2.sessionStorage和localStorage基本一样,方法名和用法都一样。

3.sessionStorage在不同的窗口中不能共享,哪怕是同一个页面。
36.执行上下文
什么是执行上下文:
  执行上下文全称是执行上下文环境 是程序执行过程中依赖的环境
  
 执行上下文分类 全局执行上下文 和函数执行上下文
 执行上下文的阶段: 创建阶段 和执行阶段
 
 全局执行上下文创建阶段 主要做了三件事 
         1 收集变量 形成变量对象(其种就已经包含了变量提升) Global
         2 确定上下文环境的this指向(this是程序执行的时候上下文当中存在的东西 是内置变量)
         3 确定上下文环境的作用域链(每一个上下文环境都有自己独立的一条作用域链)  
         注意 作用域是虚拟的 看不见摸不着的 但是作用域链是真实存在的 可以看到的  作用域链本质是一个数组 而且这个数组当中存储的是执行上下文当中的变量对象  作用域的作用是隔离变量 防止污染
         
  执行阶段主要做了一件事  :
  
            1 执行代码 根据作用域链或者原型链找对应的变量或者属性,使用或者修改数据
            
            
函数的执行上下文过程和全局执行上下文过程基本是一致的 只是再创建阶段
37.跨域
一.为什么会出现跨域问题
       出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的。javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。
二、什么是跨域
1.当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。
三.跨域的解决方案
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
38.数组的方法
【对原数组有影响】:
  方法     功能                参数        返回值
  push    末尾增加一个或者多个   增加的元素   数组的新长度
  pop     从数组的末尾删除一个   无          返回删除的那一个元素
  unshift 头部增加一个或者多个   增加的元素   数组的新长度
  shift   从数组的头部删除一个   无          删除的那一个元素
  reverse 翻转数组             无          返回翻转后的原数组
  splice  增删改一体化
  	删除(两个,第一个代表从哪开始,第二个代表删除几个) 返回删除的元素组成的新数组
  	增加(多个,第一个代表从哪开始,第二个代表删除0个,后面的代表新增的元素)返回删除的元素组成的新数组,最终是空数组
  	修改(多个,第一个代表从哪开始,第二个代表删除几个,后面的代表新增的元素)返回删除的元素组成的新数组
  	
 【对原数组没有影响】:
  join   功能:以指定的字符串为连接符,讲数组元素连接成一个字符串
         参数:如果不传,默认以逗号为连接符,将元素连接成字符串
         	  如果传的是正常字符串,那么以这个字符串为连接符将元素连接成字符串
         	  如果传的是空串,那么直接将字符串连接成字符串,中间没有任何连接
 		返回值:返回连接好的字符串
  
  concat 功能:在数组的末尾拼接元素
  		 参数:可以不写,相当于复制一个数组
  		 	  也可以写一个或者多个值,会把这些值拼接到数组末尾
  		 	  也可以写数组,会先把数组拆开,把元素拼接到数组末尾
  		 返回值:返回拼接好的新数组
 
 slice  功能:在数组当中截取部分元素形成新数组
  		 参数:和字符串方法slice一致;起始位置和结束位置,不包含结束位置的元素
  		      如果只传一个代表起始位置,一直到结束。两个位置都可以使用负数
  		 返回值:返回截取的元素形成的新数组 
 
 sort	 功能:对数组进行排序	
  		 参数:如果不写,默认把每个元素转化为字符串进行排序(按照Unicode码)
  		 	  如果要按照升序降序去排,需要传一个参数是函数,这个函数有两个形参
  		 返回值:排好序的原数组
 
 valueOf功能:获取数组对象的基本值,数组实例对象。
  		 参数:无
  		 返回值:返回原数组,因为数组是非包装对象,所以它是没有基本值
  
  toString功能:将数组对象转化为字符串
  		  参数:无
  		  返回值:把数组的中括号去掉,其余加引号形成字符串返回
  		  
 
 forEach  应用场景:为一些相同的元素,绑定事件处理器!强调的是数组中每一项都要遍历
  		   作用:1.只能是用来遍历 
  		   		2.一旦开始了遍历就停不下来
  		   		3.返回值是undefined   这个undefined对于我们来说没有用
 
 map      应用场景: 对数组中的每一项数据进行操作,比如:给每数组中的每一项添加一个相同的样式
  		   作用:1.可以循环遍历数组中的每一项数据
  		   		2.可以对循环遍历到的每一项数据进行操作
  		   返回值:一个新数组,每个元素都是回调函数的结果。
  
  filter   应用场景:根据条件过滤数组中的数据
  		   作用:1.可以循环遍历数组中的每一项
  		   	   2.可以对循环遍历到的数据进行判断
  		   	   3.当条件成立时,使用了return true后会将满足条件的那一项存到一个新的数组当中
  		   返回值:一个新数组,存储了所有返回true的元素
 
 some     应用场景: 条件成立时不再执行后续的循环,比如,注册邮箱时如果有某个人名字注册了就不能再注册了
		   作用: 1.可以用来循环遍历数组中的每一项
		   	    2.在回调函数中进行条件判断,如果return true执行之后,会阻止后续代码的遍历执行
 
 every    应用场景:重点是强调整体的一个处理结果,比如,某地区所有人健康码是否都为绿码
  		   作用:1.可以对数组中的每一项进行遍历,但是只打印第一项
  		   		2.对数组中的每一项进行判断,都满足条件则返回true,如果有一项不满足条件则返回false
  		   返回值:只有当所有的元素返回true,才返回true,否则返回false。

reduce   reduce() 方法对数组中的每个元素执行,一个由您提供的reducer函数,将其结果汇总为单个返回值   
  		   语法:reduce(callback, initValue)
               callback: 每个元素都会执行一次的回调函数
               initValue: 初始值
               
               callback的4个参数
					prev: 上一次的值,第一次为初始值
 					item:  当前值
					index: 下标
					arr: 数组
39.vue2的生命周期
常用的八个:
1初始化阶段:
   创建阶段: 
   		beforeCreate 不能通过this读取data数据和调用methods中的方法
   		created:可以通过this读取data数据和调用methods中的方法

   挂载阶段:
   		beforeMount 不能通过ref读取到页面中内容
   		mounted  能通过ref读取到页面中内容
2更新阶段: 
		beforeUpdate (在数据更新后,界面更新前调用): 读取的数据是最新的, 但页面是老的,页面还没有变化
		updated: 读取的数据和页面都是新的,页面也已经更新完成了

3卸载阶段:
		beforeDestory(): 需要调用$destroy(),才能进入此阶段  主要是做一些收尾工作,比如清除定时器,解绑事件,当执行此函数时,Vue实例进入销毁的阶段
		destoryed():组件已经全部销毁,所有的data、methods都无法使用,不怎么关注
		
不常用的三个:
         activeated:激活 
         deactivtivated:离开当前路由  失活   注意激活和时候 必须配合keep-alive使用
         errorCaptured: 父组件里用来捕获子组件中的错误     参数有三个 err 错误信息 child 错误的子组件对象 info 子组件错误的地方   如果不想让显示报错信息 直接return false 
40.自定义指令有什么配置项
directives: {
 // big 函数何时会被调用? 
 1: 指令与元素成功绑定时(一上来就会绑定)
 2: 指令所在的模板被重新解析时
 big(element, binding) {   //  第一种函数写法
   console.log('big')  //  页面已加载就会调用一次
   element.innerText = binding.value * 10; 
 }
 第二种对象写法:
 fbind: {
  // 指令与元素成功绑定在一起
  bind() {
 
  },
  // 指令所在的元素被插入到页面时
  inserted() {
 
  }
  // 指令所在的模板被重新解析
  update() {
 
  }
 }
}
41.vue2的watch 和 vue3watch的 区别
深度侦听属性说明:
deep  如果是true 代表深度侦听 不仅会侦听地址的变化 还会侦听对象内部的属性变化

immediate  立即 立刻是否立即侦听 默认是false 如果是 true 代表页面 一加载 会先执行 一次处理程序

简介:
Vue3 watch增加了同时 监听多个变量的能力 用数组表达要监听的变量 回调参数是这种结构: [newR,newS,newT] ,[oldR,oldS,oldT] 

Vue2 和 Vue3 的写法不一样 一个是配置 一个是导入watch函数

还有Vue监听的时候 可以传递一个数组 监听多个属性

多了几个watchEffect相关函数
42.权限控制(菜单权限和按钮权限)
权限控制又包括路由权限(菜单权限)和按钮权限控制

菜单权限控制的目的是让不同的用户登录成功看到的菜单是不一样的

流程:
   1、菜单的显示是根据注册的路由遍历而来的
   2、不同的用户要显示不同的菜单,那么也就是说不同的用户登录后路由注册是不一样的
   3、所以不同用户登陆的时候,需要携带不同的路由相关的权限信息数据
   4、所以我们之前的路由是不能用的,因为已经写死了
   5因此我们就要把路由给修改为三大类路由
        常量路由(静态路由): 所有的用户都可以看到的菜单路由
		异步路由(动态路由): 根据用户登录返回的路由权限信息决定动态注册的路由
		任意路由(最终返回404):这个路由是用户随意输入路径的时候要匹配的,最终重定向到404
		任意路由必须注册到最后一个
   6用户登录成功的时候,除了name和avatar以外的其余三个数组数据:buttons,roles,routes,对应的就是我们要的权限信息数据,其中routes就是不同用户给我们的不同动态路由相关的信息,routes本质是字符串数组,这里面的字符串是和当年我们配路由的时候的name值对应的     
   7、用户登录成功获取到用户信息的时候,我们需要使用这个用户对应的路由权限信息数据routes,从我们配的动态路由数组当中,过滤出当前这个用户所需要注册到路由器里面的路由数组
   8、我们需要把用户过滤出来的自己的动态路由,通过路由器的api addRoute动态的添加注册到路由器
   9、我们还需要根据注册的动态路由构造菜单遍历的时候需要的路由数组,让侧边栏动态生成菜单
   
按扭权限控制:
 按钮级别的权限依赖于菜单级别权限,没有菜单权限是不可能有按钮权限

流程:  
1 :书写组件
2:配置路由规则 注意要写name
3 自定义指令 通过返回的信息对按钮进行鉴权
4在菜单权限里添加权限信息 绑定权限的值 也就是我们在路由里书写的name的值
5 点击加号 在权限信息里 添加按钮的权限信息 权限的值一般写成上一级的权限值.当前的权限值.按钮
6 在用户管理里添加用户 并绑定角色
7 在角色管理里 给我们绑定的角色添加权限
8 退出登录 使用新添加的用户登录


vue2 里面不用定义插件 可以直接定义一个函数 然后挂载到vue的原型上 后续用v-if去判断按钮显示不显示
43.小程序登录流程
调用 wx.login() 获取 临时登录凭证 code,有效期为 5分钟;(临时登录凭证 code 只能使用一次)

将临时 code 传到我们的后端,后端调用 auth.code2Session 接口,换取用户唯一标识 OpenID 和 会话密钥 session_key;( openid 是用户唯一标识,session_key 能保证当前用户进行会话操作的有效性)

注意:获取 session_key 出于安全性的考虑,要在后端调用。如果我们在前端通过 request 调用此接口,就不可避免的需要将我们小程序的appid 、secret 和服务端下发的 session_key 暴露在外部,会给我们的业务安全带来极大的风险。 session_key 拥有一定的时效性。用户越久未使用小程序,用户登录态越有可能失效。反之如果用户一直在使用小程序,则用户登录态一直保持有效。具体时效逻辑由微信维护,对开发者透明。开发者需要调用 wx.checkSession 接口检测当前用户登录态是否有效。

后端自定义新的密钥并关联返回的 session_key 和 openid,将新的密钥返给前端,前端将其存储在 storage 中。(会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥,所以要定义新的密钥)。 之所以存在storage中,是因为小程序没有 cookie,相应的后端 set-cookie 在小程序中不起作用。

前端发送请求的时候,带着密钥,后端根据密钥识别用户身份,返回数据。
44.小程序支付流程
1 开通商户号
2 商户号平台操作
2.1 绑定小程序appId
2.1.1登录商户平台-产品中心-账号关联(AppID绑定),绑定小程序appId
2.1.2登录微信公众平台,点击“微信支付-商户号管理”,查看相关商户号信息,确认授权申请,或在“公众平台安全助手”下发的模板消息中确认授权信息;
2.2 设置API密钥
进入【账户中心】->【账户设置】->【API安全】->【API密钥】中设置,建议把APIV2和APIV3设置成一样的
2.3 开通JSAPI支付
产品中心->JSAPI提交申请
3 拉起微信支付
3.1 调用API步骤
统一下单——>生成签名——>调起小程序支付
45.小程序分包
1.什么是分包

分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,构建的时候打包城不同的分包,按需加载

2.分包的好处

①可以减少小程序首次启动的下载时间

②可以多人开发中更好的解耦协作

3.分包前后的项目构成

①分包前,小程序中所有的页面和资源都被打包到了一起,导致整个项目体积过大,影响小程序的首次启动的时间

②分包后,小程序有一个主包外加多个分包组成:

        主包:一般只包含项目的启页,或tabBar页面,以及所有分包都需要用到的公共资源,

        分包:只包含和当前分包有关的页面和私有资源

4.分包加载的规则

①在小程序启动时,默认会下载主包并启动主包内页面

②当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示

③非 tabBar 页面可以按照功能的不同,划分为不同的分包之后,进行按需下载

5.分包体积的限制

整个小程序,主包加分包不能超过20M,单个包不能超过2M,主包也是

6.使用分包

配置

①在 app.json 的 subpackages 节点中声明分包的结构

7
  "tabBar": {
    "custom": true,
    "color": "#777",
    "selectedColor":"#e11c34",
    "backgroundColor": "#fafafa",
    "borderStyle":"white",
    "list": [
      {
        "text": "首页",
        "iconPath": "",
        "selectedIconPath": "",
        "pagePath": "xxx/xxx/xxx"
      },
      {
        "text": "专题",
        "iconPath": "",
        "selectedIconPath": "",
        "pagePath": "xxx/xxx/xxx"
      },
      {
        "text": "分类",
        "iconPath": "",
        "selectedIconPath": "",
        "pagePath": "xxx/xxx/xxx"
      },
      {
        "text": "购物车",
        "iconPath": "",
        "selectedIconPath": "",
        "pagePath": "xxx/xxx/xxx""
      },
      {
        "text": "我的",
        "iconPath": "",
        "selectedIconPath": "",
        "pagePath": "xxx/xxx/xxx"
      }
    ]
  },
7.打包原则 

①小程序会按 subpackages 的配置进行分包, subpackages 之外的目录将被打包到主包中

②主包也可以有自己的 pages (即最外层的 pages 字段)

③ tabBar 页面必须在主包内

④ 分包之间不能互相嵌套

8.引用原则

① 主包无法引用分包内的私有资源

② 分包之间不能相互引用私有资源

③ 分包可以引用主包内的公共资源
46.谈一下代理的理解
一、正向代理

所谓正向代理就是顺着请求的方向进行的代理,即代理服务器他是由你配置为你服务,去请求目标服务器地址。
二、反向代理

所谓反向代理正好与正向代理相反,代理服务器是为目标服务器服务的,虽然整体的请求返回路线都是一样的都是Client到Proxy到Server。
47.axios的二次封装
1,代码封装,重用性高,减少代码量,减低维护难度。

2,统一处理一些常规的问题一劳永逸,如http错误。

3,拦截请求和响应,提前对数据进行处理,如获取token,修改配置项。 
链接:https://blog.csdn.net/m0_66285809/article/details/127304923
48.template的作用,为什么组件内只有一个根标签
Vue 的 VDOM 算法只允许 VDOM 的树状结构有一个根节点。因为从效率上讲,如果逻辑抽象树有多个根,那么就会产生多个入口,这对于 遍历、查找、比较 都不方便。

组件的 template 最终都会转换成 VNode 对象,组件的根元素对应的就是一个 VNode 对象。
49.混入 (mixin)
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项

全局混入
混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,这可以用来为自定义选项注入处理逻辑。
50.常用hooks有哪些
Hook 这个单词的意思是"钩子"。React Hooks 是加强版函数组件,提倡组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。React 官方默认提供了一些常用钩子,当然也可以按照需要封装自己的钩子进行使用。
1.  useState():用于为函数组件引入状态(state),并进行状态数据的读写操作。
2. useEffect():用于引入副作用操作(控制组件的生命周期)。常见操作:发送ajax异步请求数据、设置订阅 / 启动定时器、手动更改真实DOM。
3.useMemo():解决hooks会触发多次无用的渲染问题。如果useMemo(fn, arr)第二个参数匹配,并且其值发生改变,才会多次执行执行,否则只执行一次,如果为空数组[],fn只执行一次。
4.useRef():保存初始化的常量,在整个生命周期内不会变化,并且当更新current值时并不会render ,这是与useState不同的地方。
5、useCallback():避免函数的多次更新调用。用法与useState的用法基本一致,但最后会返回一个函数,用一个变量保存起来。
51.微前端
微前端是一种多个团队通过独立发布功能的方式,来共同构建现代化 web 应用的技术手段及方法策略
不同于单纯的前端框架/工具,微前端是一套架构体系,这个概念最早在2016年底由 ThoughtWorks 提出。 微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,将 Web 应用从整个的「单体应用」转变为多个小型前端应用的「聚合体」。

各个前端应用「原子化」,可以独立运行、开发、部署,从而满足业务的快速变化,以及分布式、多团队并行开发的需求。

核心价值(为什么要使用微前端?)
- 不限技术栈

主应用不限制接入的子应用的技术栈,子应用拥有完全自主权。所接入的子应用之间也相互独立,没有任何直接或间接的技术栈、依赖、以及实现上的耦合。

- 可独立开发、部署

微应用仓库独立,前后端均可独立开发,部署完成后主框架自动完成同步更新。独立部署的能力在微前端体系中至关重要,能够缩小单次开发的变更范围,进而降低相关风险。 各个微前端都应该有自己的持续交付管道,这些管道可以将微前端构建、测试并部署到生产环境中。

- 增量升级

在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构。 因此,微前端是一种非常好的实施渐进式重构的手段和策略,它可以逐渐升级我们的架构、依赖关系和用户体验。当主框架发生重大变化时,微前端的每个模块可以独立按需升级,不需要整体下线或一次性升级所有内容。如果我们想要尝试新的技术或互动模式,也能在隔离度更好的环境下做试验。

- 简单、解耦、易维护

微前端架构下的代码库倾向于更小/简单、更容易开发,避免无关组件之间不必要的耦合,让代码更简洁。通过界定清晰的应用边界来降低意外耦合的可能性,更好地避免这类无意间造成的耦合问题。

在什么场景下使用?
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用 (Frontend Monolith) 后应用不可维护的问题。这类问题在企业级 Web 应用中尤为常见。

- 兼容遗留系统

现今技术不断更迭,团队想要保技术栈不落后,就需要在兼容原有系统的前提下,使用新框架去开发新功能。而遗留系统的功能早已完善,且运行稳定,团队没有必要也没有精力去将遗留系统重构一遍。此时团队如果需要使用新框架、新技术去开发新的应用,使用微前端是很好的解决方案。

- 应用聚合

大型的互联网公司,或商业Saas平台,都会为用户/客户提供很多应用和服务。如何为用户呈现具有统一用户体验和一站式的应用聚合成为必须解决的问题。前端聚合已成为一个技术趋势,目前比较理想的解决方案就是微前端。

- 不同团队间开发同一个应用,所用技术栈不同
52.Vuex
有五个属性 state getters mutations actions modules

- State就是数据源存放地,对应一般vue对象的data,state里面存放的数据是响应式的,state数据发生改变,对应这个数据的组件也会发生改变 
- Getters 相当于store的计算属性,主要是对state中数据的过滤或者计算

- Mutations 处理数据逻辑的方法全部放在mutations中

- Actions 异步操作数据,但是是通过mutation来操作 用this.$store.dispatch来触发
-modules 模块化,模块拆分。当应用变得非常复杂,store对象就会变得非常臃肿;为了解决这个问题,Vuex允许将store分隔成模块,每个模块拥有自己的state,mutation,action,getter
53.ref和reactive是做什么的,区别是什么,原理是什么
创建响应式对象的
区别:
ref函数可以把数据创建成ref对象,只要是ref对象,那么一定是响应式的
ref创建对象类型的数据时 本质也是在使用reactive 返回的仍然是ref对象 它的value是代理对象 修改的时候也需要.value
ref在渲染页面的时候使用 不用写.value


reactive: 
reactive是用来对一个对象创建代理对象,代理对象也是响应式的 必须是对象
reactive创建的代理对象,直接通过.语法去操作,不需要.value
reactive的原理用的是代理和反射	

注意 :
代理对象被解构的时候 数据失去响应能力 需要使用torefs方法让它变成响应式的 
原理是把代理对象的所有属性 变成ref对象
54.scoped
scoped本意是作用域的意思,在style身上添加scoped是在限制这个style的样式作用域
如果style当中没有添加scoped,那么内部所写的样式会影响其它组件
		如果其它组件当中也有和这个组件一样的选择器,那么选中的元素也会被影响到(整个页面)
如果style当中添加scoped,那么内部所写的样式被限定了作用域
		在style当中添加了scoped会让样式作用域被限定在本组件内部和子组件的根标签
		如果子组件的根标签和样式的选择器一样,那么也能被影响到
原理:		
添加了scoped,本组件的所有元素以及子组件的跟标签,最后解析完都会添加一个data-v-xxxx的一个标识数据,只要有这个标识数据,就代表样式,可以影响到这些区域
不添加scoped,样式最终是  
             h2:{
		          color:hotpink
	              }

加了scoped
              h2[data-v-38fc2d66] {
	              color: hotpink;
	                     }


想让一个元素有样式必须符合两个条件
  1、scoped能够作用到,也就是添加标识数据
  2、样式的选择器必须能选择到
55.nextTick的作用及原理
主要用于处理数据动态变化后,DOM还未及时更新的问题,用nextTick就可以获取数据更新后最新DOM的变化
$nextTick保证页面更新完成   是等待页面最近一次更新完成,执行操作
watch监视配合nextTick使用
new swiper 的时候 用的 watch监视 和nextTick 
56.登录逻辑
注册:
静态页面  
收集数据 发请求获取验证码
表单验证 vee-validate 
发请求注册用户

登录:
静态页面
点击登录 登录成功的标志是拿到token  这里登录成功需要跳转页面 所以要返回一个ok
token要放到请求拦截器的请求头里 每次发送请求都要带着token

token校验  
在router里面配置了一个全局前置守卫 
判断有没有token 如果有 判断去往的路径 如果是登录页面 直接重定向首页 
如果是其他页面 要判断有没有用户信息 如果有 就放行 没有就获取
注意获取用户信息失败的时候 要清空token

自动登录 (持久化存储) 
获取到token的时候 存到localstorage里面 
然后state的面的token先从localstorage里面拿 如果没有 就或上一个空串

退出登录:
需要发请求
清空用户的信息 清空token localstorage里面的token也要清除
57.call、apply、bind
一、call,apply,bind的相同点:
	都是改变this指向的;

	第一个参数都是this要指向的对象;

	都可以利用后续参数传参;
二、call,apply,bind的区别:
	call和bind的参数是依次传参,一一对应的;

	但apply只有两个参数,第二个参数为数组;

	call和apply都是对函数进行直接调用,而bind方法返回的仍是一个函数;
58.普通函数和箭头函数的区别
1.箭头函数比普通函数更加简洁
2. 箭头函数没有自己的this
3. 箭头函数继承来的this指向永远不会改变
4. call()、apply()、bind()等方法不能改变箭头函数中this的指向 
5. 箭头函数不能作为构造函数使用 
6. 箭头函数没有自己的arguments
7. 箭头函数没有prototype
59.vuex存储的数据持久化
1、我们可以使用localStorage进行存储

2.使用插件进行持久化存储(vuex-persist)
60.路由守卫
路由守卫又称导航守卫,指是路由跳转前、中、后过程中的一些钩子函数
理解:
	当路由跳转的时候,这个守卫可以去拦住,检测你是否有去往这个页面的条件
    有特定条件才能去到相应的页面的功能 
    拦截路由,查看是否满足条件,满足的放行,不满足的处理
有三种
 1 全局守卫 :无论是从哪个页面往哪个页面跳转,只要有路由跳转,就会拦住,进行检测
       全局前置守卫 :  配置的比较靠前       匹配路由前拦截,用的最多     
       全局解析守卫 :   配置的位置中间      匹配路由中拦截,用的比较少
       全局后置守卫 :  配置的比较靠后       匹配路由完成拦截,用的比较少
 2 独享守卫 :只能去拦住固定的往某个页面跳转的,是配置在当前路由当中,时间比较靠前
 3 组件内部守卫 :
 		只能去拦住固定的往某个页面跳转的,是配置在组件内部,也就是路由匹配已经完成了,时间比较靠后
		就是解析完了,已经跳转到组件的时候,但是组件还没创建成功的时候拦截

每一种守卫都有三个参数 to 去哪里  from 从哪来  next 是否要进行下一步
   next()相当于next(true) 继续执行 不写next相当于终止执行 next('/')跳转页面

token校验的时候 用到了全局前置守卫   项目快结束的时候 用了一些独享守卫 比如只有从支付页面才能跳转到支付成功页面
61.http和https区别
1、HTTPS  协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。)

2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。

3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)
62.tostring和jsonstringfiy的区别
js数组使用JSON.stringify和toString的区别如下:
1、JSON.stringify()是json对象的一个方法,它可以把对象序列化成json字符串。
     toString是一个js对象的方法,任何对象都会继承这个方法,也就是Object.prototype.toString(),返回值类型为:[object Object]
2、用法上的区别举例:
比如定义:obj =[1,2,3]
那么用toString的结果是"1,2,3",用JSON.stringify()的结果是"[1,2,3]"

二者处理后的结果是不同的。
63.iframe
1.iframe是html元素,用于在网页中内嵌另一个网页。

2.iframe默认有一个宽高,存在边界

3.iframe是一个行内快级元素,可以通过display修改

优化

1. 代码层面优化

1.v-for遍历列表 以及v-if和v-for尽量不要同时使用

key是虚拟dom进行diffing算法的唯一标识 指定唯一值为key 尽量不要用下标
使用下表为例 结果正确的时候 也尽量不要用 因为效率太低  添加的时候 下表会重新指定 所以每一i个标里面的内容都会被更改 所以效率低
用id就不会这样 因为会根据id去比较 原有的不会变 只是去重新添加一个

v-if和v-for同时使用的时候 v-if每一个都需要解析 效率很低 所以不用
  1. 图片懒加载

还没有加载得到目标图片时(图片没回来之前) 先显示loading图片 (这个图片在本地)
在可视区域外显示本地的loading图
做法:
下载vue-lazyload
引入并配置loading图片
main.js里面注入
使用 v-lazy='图片路径'

3.路由懒加载

如果不适用路由懒加载 所有的路由都会打包到一起 比较大  影响页面加载
所以我们可以使用路由懒加载 用到的时候 才会去加载路由

特点: 
	每个路由组件都会打包成一个单独的文件
	第一次访问哪一个路由组件,再去加载哪一个打包好的文件
	本质就是Vue 的异步组件在路由组件上的应用
	
使用:
   import()函数 
   复杂写法
      const Home=()=>{
          return import('@/pages/Home')
      }
    简单写法:
      const Home=()=>import('@/pages/Home')

4.第三包插件的按需引入

比如 element-ui  以及vant组件 我们采用的都是按需引入的 用不到的不引入

5 .高频事件进行节流或防抖处理

共同点:都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
节流:多次变少次  三级菜单的时候使用了
防抖:多次变一次   输入框实时搜索
  1. 及时销毁事件监听

比如定时器  和全局事件总线 这些都需要我们自己去手动销毁的
我们会在组件销毁的时候去处理 如果不销毁 会继续存在

7.冻结响应式数据 (优化大数组)

当我们拿到的数据只是为了真实 没有什么后续的操作时 我们可以使用object.freeze()去冻结数据

如果不冻结的话 数据内部会自动递归添加get和set变为响应式数据 递归很消耗性能 
所以如果只展示的时候 我们可以直接给他冻结

 this.users = Object.freeze(users); // 这样数组内部就没有做数据劫持处理, 效率更高
  }

8.虚拟列表(优化大数组)

当组件处于非常长的列表时,数据过多导致DOM元素同样多,导致卡顿。

使用业界常用手段`虚拟列表`,只渲染可以看到的窗口的区域DOM。

利用数组的方法slice 去截取我们当前窗口展示的 然后利用滚动条和scrollTop去继续截取数里面的东西去展示
这样就可以避免直接去创建很多的真实dom
2 webpack配置层面优化

1.拆分打包与压缩

对第三方js包,css进行拆分打包
作用: 
	抽取公共代码
	拆分多个文件,减少单个文件的体积 (避免单次请求的时间过长)
  1. 资源预加载

作用:让资源提前加载
praload 让当前页面的要使用资源加载  对同步模块包使用
prefetch 让后面要使用资源提前加载 对异步模块包使用

加载就是下载  还没到渲染某个页面的时候 就已经把需要的资源加载好了 那么渲染页面的时候 效率肯定会提高

需要使用chrome团队提供的一个工具包  preload-webpack-plugin

3.生产环境下不生成SourceMap(资源映射)

SourceMap(资源映射) 就是告诉我们我们写的代码在打包之后对应的是哪些
如果不生成SourceMap 那么打包的时候就会减少一些体积 所以会提升效率
需要在配置文件里配置 productionSourceMap: false 

4.文件名hash化

目的是为了利用浏览器的缓存机制来提高性能
浏览器会缓存文件,但是文件名如果不改变,浏览器不会缓存新的,因此我们要保证内容改变了,把文件名也改变,浏览器就会重新缓存新文件。如果内容没有变,文件名也不会变。浏览器就会拿缓存好的文件。这样队医没更改的文件 就不会重新去加载了 直接从缓存里面读取就可以 提高了性能
默认脚手架已经配置好了,可以查看打包后的文件,都会有一个hash名字

5.tree Shaking 摇树

效果:打包时"摇掉"没有被使用的代码
条件:
	必须是ES6模块到出且进行代码压缩时 
	生产环境会摇,开发环境不会
	只有分别暴露的时候 才会摇
3. 基础的Web技术层面的优化

静态资源(css/js/img)使用CDN引入

浏览器从服务器上下载 CSS、js 和图片等文件时都要和服务器连接,而大部分服务器的带宽有限,如果超过限制,网页就半天反应不过来。而 CDN 可以通过不同的域名来加载文件,从而使下载文件的并发连接数大大增加,且CDN 具有更好的可用性,更低的网络延迟和丢包率 。
 需要在webpack里面配置
 configurWebpack:{
 externals:{
 "vue":'Vue',
 "vuex":'Vuex'
 }
 }

最后

感谢阅读,如有不足之处,欢迎在评论区讨论!

猜你喜欢

转载自blog.csdn.net/weixin_60172238/article/details/129128879