## 路由模式
hash:就是在url中加#,因为加#,url地址变化不会刷新页面。
history:没有#,url地址看起来更友好,但是会刷新页面。
## 如果用history模式会有什么问题?
页面显示不出来,因为404了,所以如果要用history模式就得配置404跳转到首页。
## 守卫
### 全局路由守卫
beforeEach:接收三个参数:to,from,next(回调函数,执行则进行下一个页面。)
afterEach
## 组件内路由守卫
beforeRouteEnter
beforeRouteLeave
beforeRouteUpdate
## 路由独享守卫
beforeEach
## 跳转方式
push:跳转
go:返回多少级,-1,-2,-3
replace:将当前路径删除,跳转路径加入
# vuex
## 使用场景
存储全局变量时。
## 使用时遇到的问题
页面刷新后就丢失了
## 页面刷新时数据会否丢失
会,使用持久化插件,将数据存储到localStorage或sessionStorage中。
## 五大核心
state: 存放状态 所有的数据都存储在state中 state是一个对象
mutations: 可以直接操作state中的数据
getters: 类似计算属性实现对state中的数据做一些逻辑性的操作
actions: 异步操作 一般在这里面调用mutations的方法进行更改数据
modules: 将仓库分模块存储
# JS
## var,let,const区别
var 存在变量提升,可以重复定义,在全局中定义的数据会挂载到window上。
let const在{}中定义的变量属于块级作用域,不可重复定义,在定义前使用会存在暂时性死区的问题。
const 定义的是常量,如果定义的是常量则不可修改,因为无法修改它的引用地址。
## 闭包
访问函数内部变量的函数就是闭包。
优点:
1. 避免污染全局环境。
2. 延迟计算
3. 定义私有变量
缺点:
1. 容易造成内存泄露 解决办法:把它的引用设置为null
## 原型和原型链
原型:每个对象都有一个特殊的属性叫作`原型(prototype)`,在原型上定义的属性和方法会被每一个实例对象共享。
原型链:获取对象属性时,如果对象本身没有这个属性,那就会去他的原型`__proto__`上去找,如果还查不到,就去找原型的原型,一直找到最顶层(`Object.prototype`)为止。Object.prototype对象也有__proto__属性值为null
## es6新特性
ES6新增特性常⽤的主要有:let/const,箭头函数,模板字符串,解构赋值,扩展操作符,模块的导⼊(import)和导出(export default/export),Promise,还有⼀些数组字符串的扩展⽅法,其实有很多,我平时常⽤的就这些
## es6数组常用的方法
filter():创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素(注意:它不会对空数组检测,它不会改变原数组)
1、Array.from( ):将对象或字符串转成数组,注意得有length。
2、Array.of( ): 将一组值转换为数组。
3、copyWithin(target,start(可选),end(可选)):数组内数据的复制替换
target:从该位置开始替换数据;
start:从该位置开始读取数据,默认为0;
end:到该位置停止数据的读取,默认为数组的长度
4、find( ):用于找出第一个符合条件的数组成员。
5、findIndex( ):返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
6、fill(value,start,end):使用给定值,填充一个数组。
value:填充的值;
start:开始填充的位置;
end:填充结束的位置。
7、keys( ):对键名的遍历。
8、values( ):对键值的遍历。
9、entries( ):对键值对的遍历。
10、includes( ):数组原型的方法,查找一个数值是否在数组中,只能判断一些简单类型的数据,对于复杂类型的数据无法判断。该方法接受两个参数,分别是查询的数据和初始的查询索引值。
11、flat( ):用于数组扁平,数组去除未定义。
12、flatMap( ):对原数组的每个成员执行一个函数。
,
13、Map( ):是一组键值对的结构,具有极快的查找速度。
14、Set( ):Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
15 使用 toString() 方法 数组中 toString() 方法能够把每个元素转换为字符串,
16 split() 方法 常见的转换技术是split字符串方法,但这也是有问题的一种。 通过使用空字符串作为split方法的分隔符,我们可以将字符串转换为字符数组。
17 Number()转换函数 Number() 函数把对象的值转换为数字。
## 箭头函数的this指向
主要是用来改变this的指向,就是说如果创建一个构造函数,我们在里面再加一个函数,它们两个的this指向不同,第一个指向实例的本身,而第二个默认指向window
因为箭头函数有一个特性,就是不绑定this,会捕获其定义时所在的this指向作为自己的this
## this指向
默认绑定规则:直接调用函数符合默认绑定规则,this指向window。
隐式绑定规则:对象点函数,this指向调用它的这个对象,就是谁点的它绑定谁。
显式绑定规则:使用call,apply,bind调用的方法,this指向call,apply,bind绑定的对象。
new绑定规则:new一个对象会使用new绑定规则,this指向对象的实例。
## Promis
解决了什么问题:回调地狱的问题。
promise有三种状态:
分别是Pending(进行中)、fulfiled(成功)、Rejectd(失败)。如果成功就执行成功的回调函数,失败就执行失败的。
属于微任务。
状态从pending变更到成功和失败之后就不能再变更了。
## js事件循环机制
js是单线程,所以有三个任务队列,同步任务,微任务,宏任务,每次先执行同步任务,在执行微任务,在执行宏任务,全部完成后再从头开始,这样周而复始的循环叫做事件循环
## JS继承
盗用构造函数:通过call,apply将要继承的函数的this指向当前的this。缺点:无法继承原型链上的属性和方法。
原型链继承:直接new一个对象赋值给prototype,缺点就是所有的属性都会被共享。
组合继承:结合盗用构造函数和原型链继承两种方式,既继承了原型链上的方法,又将构造函数中的属性添加到了实例对象上。
## 跨域解决方式
Jsonp:利用script标签的src属性不受同源策略的限制,可以利用src去调用后端的接口。缺点:必须定义一个全局方法。
反向代理:就是利用一个中间服务将我们发起的请求转发到服务端,并且在返回的时候在响应头里添加允许跨域的头。vue中的配置方法:在vue.config.js中配置proxy代理。
cors:后端在响应头里添加允许跨域的头,这个是后端解决的。
## 什么是跨域
协议域名端口一致是同源策略,如果违反了同源策略,则会造成跨域。
# React
## 什么是JSX?
JSX 是J avaScript XML 的简写。是 React 使用的一种文件,它利用 JavaScript 的表现力和类似 HTML 的模板语法。这使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能。
## 类组件和函数组件的区别?
相同点:它们都可以接收属性并且返回React元素。
不同点:
(1)类组件需要创建实例,是基于面向对象的方式编程,函数组件不需要创建实例,接收输入,返回输出,是基于函数编程的思想。
(2)类组件需要创建并且保持实例,会占用一定的内存,函数组件不需要创建实例,可以节约内存占用。
(3)类组件有完整的生命周期,函数组件没有生命周期(现在通过useEffect实现类似生命周期的功能)
(4)类组件通过shouldComponent和pureComponent跳过更新,而函数组件可以通过React.memo跳过更新。
(5)类组件服用逻辑一般用HOC,函数组件可以自定义Hook。
## setState 同步还是异步?
React生命周期中以及事件处理中,为异步。
原理:setState本身并不是异步,只是因为react的性能优化机制体现为异步。在react的生命周期函数或者作用域下为异步,在原生的环境下为同步。 因为每次调用setState都会触发更新,异步操作是为了提高性能,将多个状态合并一起更新,减少re-render调用。
性能优化机制:在 React 的 setState 函数实现中,会根据一个变量isBatchingUpdates判断是直接更新 this.state 还是放到队列中。isBatchingUpdates 默认是 false,React 在调用事件处理函数之前会将isBatchingUpdates改为true,造成的后果就是由 React 控制的事件处理过程 setState 不会同步更新 this.state。而原生方法不会被React控制。
## React的生命周期?
1. **componentWillMount\()** – 在渲染之前执行,在客户端和服务器端都会执行。
2. **componentDidMount\()** – 仅在第一次渲染后在客户端执行。
3. **componentWillReceiveProps\()** – 当从父类接收到 props 并且在调用另一个渲染器之前调用。
4. **shouldComponentUpdate\()** – 根据特定条件返回 true 或 false。如果你希望更新组件,请返回**true** 否则返回 **false**。默认情况下,它返回 false。
5. **componentWillUpdate\()** – 在 DOM 中进行渲染之前调用。
6. **componentDidUpdate()**– 在渲染发生后立即调用。
7. **componentWillUnmount\()** – 从 DOM 卸载组件后调用。用于清理内存空间。
## 你知道哪些hook?
useState()`,状态管理钩子。通过在函数组件中调用useState,就会创建一个单独的状态。
useEffect(),副作用钩子。它接收两个参数, 第一个是进行的异步操作, 第二个是数组,用来给出Effect的依赖项
useContext(),共享钩子。该钩子的作用是,在组件之间共享状态。
useReducer(),Action 钩子。useReducer() 提供了状态管理,其基本原理是通过用户在页面中发起action,
从而通过reducer方法来改变state, 从而实现页面和状态的通信。
useRef(),获取组件的实例;渲染周期之间共享数据的存储(state不能存储跨渲染周期的数据,因为state的保存会触发组件重渲染)
useMemo和useCallback:可缓存函数的引用或值,useMemo用在计算值的缓存,注意不用滥用。经常用在下面两种场景(要保持引用相等;对于组件内部用到的
object、array、函数等,如果用在了其他 Hook 的依赖数组中,或者作为 props 传递给了下游组件,应该使用
useMemo/useCallback)
首先,Hooks 通常支持提取和重用跨多个组件通用的有状态逻辑,而无需承担高阶组件或渲染 props 的负担。Hooks 可以轻松地操作函数组件的状态,而不需要将它们转换为类组件。
Hooks 在类中不起作用,通过使用它们,咱们可以完全避免使用生命周期方法,例如 componentDidMount、componentDidUpdate、componentWillUnmount。相反,使用像useEffect这样的内置钩子。
## 为什么虚拟 dom 会提高性能?
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。
用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。
## react diff 原理
把树形结构按照层级分解,只比较同级元素。
给列表结构的每个单元添加唯一的 key 属性,方便比较。
React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。
## 列出React的一些主要优点。
1. 它提高了应用的性能
2. 可以方便地在客户端和服务器端使用
3. 由于 JSX,代码的可读性很好
4. React 很容易与 Meteor,Angular 等其他框架集成
5. 使用React,编写UI测试用例变得非常容易
## React中的合成事件是什么?
合成事件是围绕浏览器原生事件充当跨浏览器包装器的对象。它们将不同浏览器的行为合并为一个 API。这样做是为了确保事件在不同浏览器中显示一致的属性。
## 什么是高阶组件(HOC)?
高阶组件是重用组件逻辑的高级方法,是一种源于 React 的组件模式。 HOC 是自定义组件,在它之内包含另一个组件。它们可以接受子组件提供的任何动态,但不会修改或复制其输入组件中的任何行为。你可以认为 HOC 是“纯(Pure)”组件。
## state 和 props 区别?
props和state是普通的 JS 对象。虽然它们都包含影响渲染输出的信息,但是它们在组件方面的功能是不同的。即
state 是组件自己管理数据,控制自己的状态,可变;
props 是外部传入的数据参数,不可变;
没有state的叫做无状态组件,有state的叫做有状态组件;
多用 props,少用 state,也就是多写无状态组件。
## 受控组件和非受控组件的区别?
**·** ***\*受控组件\****是 React 控制中的组件,并且是表单数据真实的唯一来源。
· 非受控组件是由 DOM 处理表单数据的地方,而不是在 React 组件中。
尽管非受控组件通常更易于实现,因为只需使用refs即可从 DOM 中获取值,但通常建议优先选择受控制的组件,而不是非受控制的组件。
这样做的主要原因是受控组件支持即时字段验证,允许有条件地禁用/启用按钮,强制输入格式。
# http
## http和https的区别
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
## 有哪些请求
get:把参数放在url中,所以传输的数据是透明的,有大小限制。
post:把请求数据放在body中,传输数据大,请求比get慢,因为会先发送一个options预请求去询问服务器能否接受这个请求。
put:更新。
delete:对这个资源的删操作。但要注意:客户端无法保证删除操作一定会被执行,因为http规范允许服务器在不通知客户端的情况下撤销请求。
patch:有一个对象你要更新有十个属性,但只能更新两个属性,只能部分。
options:用于获取当前URL所支持的方法。若请求成功,则会在http头中包含一个名为"Allow"的头,值是所支持的方法,如get和post
## 三次握手
第一次握手:客户端发送网络包,服务端收到了。这时候服务端的都结论:客户端的发送能力、服务端的接受能力正常。
第二次握手:服务端收到网络包会给客户端响应,这时候服务端发送网络包,客户端收到了,此时的服务端得出结论:服务端的发送能力没有问题,因为客户端没有给服务端响应。
第三次握手:客户端收到网络包后,给服务端响应,这时候客户端给服务端发送网络包,服务端收到了,此时服务端得出结论:客户端的发送、接受能力没有问题,自己的发送,接受能力也没有问题。
# 项目相关
## 登录鉴权的实现方式
## 动态路由的实现方式
后端会根据当前登录人的角色返回相应的权限菜单,我们会在全局路守卫中进行判断,如果当前进入的路径在这个权限菜单中,则可以跳转,如果不在的话我们就跳转到首页中。
## 移动端怎么做的适配
使用postcss-px-to-viewport这个插件将px转换为vw。
## vw是什么?
视口宽的百分比。
## rem是什么?
**是指相对于根元素的字体大小的单位**
按照设计稿的宽去设置一个合适的rem ,配合js查询屏幕大小来改变html的font-size,从而达到适配各种屏幕的效果
## 用rem做适配了解过吗?
没有,我们通常用vw做适配
## 用过Echarts中的哪些图表?
柱形图,线型图,饼图
## 对axios做过哪些二次封装?
首先设置它的busURL,它的基地址,然后去封装它的请求拦截器和响应拦截器,在请求拦截器里边咱们一般会给它的header加上验证头会把token传入,在响应拦截器里边我们会对这个将要返回的数据进一步处理,然后我们还会去判断它的http 响应码,一般会在里边判断401,如果是401的话就相当于身份未校验或token失效,我们会把本地的token清空,然后跳转的登录页去,让它重新登录
## token值会过期吗?怎么处理?
会,token有失效时间,在请求的响应拦截器中去判断状态码是否为401,如果是401 token失效,清空token,弹出警告框告知用户跳转到登录页面重新登录
## 封装过哪些组件?
封装组件大多封装业务组件,这个功能组件比较少。
## 封装组件的思路?有哪些考虑?
业务组件我们要首先考虑他的组件通用性,组件用在那些地方,那些变化,那些不变化,变化的东西放到props中。
## 项目优化
代码层面的话尽量减少冗余代码,命名要规范,提高代码的可读性。然后使用组件懒加载、路由懒加载等技术让非及时显示的页面或组件闲时下载。
打包方面的话将小图配置打包成base64,更小的icon图标打包成精灵图,开启Treeshaking,按需导入用到的方法,减少不必要的代码体积。然后开启多线程打包,加快打包速度。
说⼀下axios的拦截器的作⽤?应⽤场景都有哪些?(80%) ⾸先呢,axios拦截器是axios给我们提供的两个⽅法,通过这两个⽅法我们可以对请求发送之前以及响应之后进⾏逻辑的再次处 理(拦截). 这两个拦截器不需要⼿动触发,只要发送http请求的时候就会⾃动触发. 我在项⽬中经常通过拦截器发送token, 对 token进⾏过期处理,以及进⾏其他的⼀些操作 22. 说⼀下vue和jquery的区别?(50%) ⾸先呢jquery他是⽤js封装的⼀个类库,主要是为了⽅便操作dom元素,⽽vue他是⼀个框架,并且呢,他会从真实dom构建出⼀个 虚拟的dom树,通过di!算法渲染只发⽣改变的dom元素,其他的相同的dom元素不⽤在重新渲染. ⽽使⽤jquery去改变dom元素 的时候,即使有相同的dom元素也会重新渲染,以上就是我对vue和jquery区别的理解. 23. vue中data发⽣变化,视图不更新如何解决?(必问) 过⼀下 ⾯试官,您好,接下来我先给您介绍⼀下为什么data发⽣变化,视图不更新,因为Vue实例中的数据是响应式的**⽽我们新增的属 性并不是响应式的,由于受现在JavaScript的限制,Vue⽆法检测到属性的新增或删除。所以有时⽆法实时的更新到视图上。 ** 所以我在项⽬中遇到这类问题的时候⼀般是通过this. 方法去解决 $set⽅法⼀共有三个参数,分别是⽬前属性,新增属性, 新增的值. 以上就是我对视图不更新的理解. 24. 为什么vue中data必须是⼀个函数?(必问) 过⼀下 如果data是⼀个函数的话,这样每复⽤⼀次组件,就会返回⼀份新的data,类似于给每个组件实例创建⼀个私有的数据空 间,让各个组件实例维护各⾃的数据。⽽单纯的写成对象形式,就使得所有组件实例共⽤了⼀份data,就会造成⼀个变了全 都会变的结果。 所以说vue组件的data必须是函数。这都是因为js的特性带来的,跟vue本身设计⽆关。 25.MVVM模式的优点以及与MVC模式的区别? MVVM模式的优点: 1、低耦合: 视图(View)可以独⽴于 Model 变化和修改,⼀个 ViewModel 可以绑定到不同的"View"上,当View变化的时候Model 可以不变,当Model变化的时候View也可以不变。 2、可重⽤性: 你可以把⼀些视图逻辑放在⼀个ViewModel⾥⾯,让很多 view 重⽤这段视图逻辑。 3、独⽴开发: 开发⼈员可以专注于业务逻辑和数据的开发(ViewModel),设计⼈员可以专注于⻚⾯设计。 4、可测试: 界⾯素来是⽐较难于测试的,⽽现在测试可以针对ViewModel来写。 MVVM 和 MVC 的区别: mvc 和 mvvm 其实区别并不⼤。都是⼀种设计思想。 主要区别 mvc 中 Controller演变成 mvvm 中的 viewModel, mvvm 通过数据来显示视图层⽽不是节点操作。 mvvm主要解决了: mvc中⼤量的DOM 操作使⻚⾯渲染性能降低,加载速度变慢,影响⽤户体验。 26. 怎样理解 Vue 的单向数据流? 数据总是从⽗组件传到⼦组件,⼦组件没有权利修改⽗组件传过来的数据,只能请求⽗组件对原始数据进⾏修改。这样会防⽌从 ⼦组件意外改变⽗级组件的状态,从⽽导致你的应⽤的数据流向难以理解。 注意:在⼦组件直接⽤ v-model 绑定⽗组件传过来的 prop 这样是不规范的写法 开发环境会报警告 如果实在要改变⽗组件的 prop 值 可以再 data ⾥⾯定义⼀个变量 并⽤ prop 的值初始化它 之后⽤$emit 通知⽗组件去修改 27. 虚拟 DOM 是什么? 有什么优缺点? 什么是虚拟dom? 由于在浏览器中操作 DOM 是很昂贵的。频繁的操作 DOM,会产⽣⼀定的性能问题. 所以在vue中将真实的DOM节点抽离成⼀个虚拟 的DOM树,这个虚拟的DOM树就是虚拟DOM. 优点: 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产⽣的操作,它的⼀些 DOM 操作的实现必须是普适的,所以它 的性能并不是最优的;但是⽐起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM ⾄少可以保证在你不需要⼿动优化的 情况下,依然可以提供还不错的性能,即保证性能的下限; ⽆需⼿动操作 DOM: 我们不再需要⼿动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向 绑定,帮我们以可预期的⽅式更新视图,极⼤提⾼我们的开发效率; 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,⽽ DOM 与平台强相关,相⽐之下虚拟 DOM 可以进⾏更⽅便地跨平台操作,例如 服务器渲染、weex 开发等等。 缺点: ⽆法进⾏极致优化: 虽然虚拟 DOM + 合理的优化,⾜以应对绝⼤部分应⽤的性能需求,但在⼀些性能要求极⾼的应⽤中虚拟 DOM ⽆法进⾏针对性的极致优化。 ⾸次渲染⼤量 DOM 时,由于多了⼀层虚拟 DOM 的计算,会⽐ innerHTML 插⼊慢
TypeScript 中 const 和 readonly 的区别?枚举和常量枚举的区别?接⼝和类型别名的区别? const 和 readonly : const可以防⽌变量的值被修改,readonly可以防⽌变量的属性被修改。 枚举和常量枚举 : 常量枚举 只能使⽤常量枚举表达式,并且不同于常规的枚举,它们在编译阶段会被删除。 常量枚举成员在使⽤的地⽅会被内联进来。 之所以可以这么做是因为,常量枚举不允许包含计算成员。 接⼝和类型别名 : 两者都可以⽤来描述对象或函数的类型。与接 ⼝不同,类型别名还可以⽤于其他类型,如基本类型(原始值)、联合类型、元组。 8. TypeScript 中 any 类型的作⽤是什么? 为编程阶段还不清楚类型的变量指定⼀个类型。 这些值可能来⾃于动态的内容,⽐如来⾃⽤户输⼊或第三⽅代码库。 这种 情况下,我们不希望类型检查器对这些值进⾏检查⽽是直接让它们通过编译阶段的检查。 9.TypeScript 中 any、never、unknown、null & undefined 和 void 有什么区别? any : 动态的变量类型(失去了类型检查的作⽤)。 never : 永不存在的值的类型。例如:never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的 返回值类型。 unknown : 任何类型的值都可以赋给 unknown 类型,但是 unknown 类型的值只能赋给 unknown 本身和 any 类型。 null & undefined : 默认情况下 null 和 undefined 是所有类型的⼦类型。 就是说你可以把 null 和 undefined 赋值给 number 类型的变量。当你指定了 --strictNullChecks 标记,null 和 undefined 只能赋值给 void 和它们各⾃。 void`: 没有任何类型。例如:⼀个函数如果没有返回值,那么返回值可以定义为void