# vue
## 生命周期
created:初始化了$el(dom节点),data和methods(请求放在哪?因为这个时候初始化data和methods,所以在这近早的发起请求)
beforeCreate 创建前、 created创建后、beforeMount 挂载前、mounted挂载后、beforeUpdate 更新前、updated更新后、beforeDestory 销毁前、 destoryed销毁后
## 组件通信
父子:父组件绑定一个属性,通过子组件的props接收
子父:在父组件的子组件上定义一个事件,通过this.$emit来派发
兄弟:建一个空的envbus(事件总线),导出vue实例,在组件内引入用$emit派发,用$on来接收,vuex
多级:通过provide传递,通过inject接收
## 通过下标更改数组
使用方法如splice,pop,push,unshift
原理:vue内部重写了这些数组的操作方法,所以被调用时会感知到
## 有时候设置某些属性没有变化
使用$set动态添加
原理:用$set动态添加的属性会使用object.difineproperty()去劫持对象
## vue的双向绑定原理
通过object.difineproperty()劫持对象,在get函数中收集依赖,在set函数中通知更新。
## key的作用
标识vnode(虚拟节点)的唯一性可以在diff算法中进行新旧节点的虚拟dom树对比,没有变化的不替换,
## index作为key的不好的地方
index是有变化的,不具有唯一性,所以在diff算法中进行新旧节点的虚拟dom树对比时,虽然dom节点没变化,但是key值不一样,所以会导致重新渲染
数组常用的一些方法:
1、push()
向数组的末尾添加新内容
参数:要添加的项。传递多个用逗号隔开,任何数据类型都可以
返回值:新增后数组的长度
是否改变原数组:改变
2、pop()
删除数组的最后一项
参数:无
返回值:被删除的项
是否改变原数组:改变
3、shift()
删除数组的第一项
参数:无
返回值:被删除的项
是否改变原数组:改变
4、unshift()
向数组首位添加新内容
参数:要添加的项,多项用','隔开
返回值:新数组的长度
是否改变原数组:改变
5、slice()
按照条件查找出其中的部分内容
参数:
array.slice(n, m),从索引n开始查找到m处(不包含m)
array.slice(n) 第二个参数省略,则一直查找到末尾
array.slice(0)原样输出内容,可以实现数组克隆
array.slice(-n,-m) slice支持负参数,从最后一项开始算起,-1为最后一项,-2为倒数第二项
返回值:返回一个新数组
是否改变原数组:不改变
6、splice()
对数组进行增删改
增加:ary.splice(n,0,m)从索引n开始删除0项,把m或者更多的内容插入到索引n的前面
返回空数组
修改:ary.splice(n,x,m)从索引n开始删除x个,m替换删除的部分
把原有内容删除掉,然后用新内容替换掉
删除:ary.splice(n,m) 从索引n开始删除m个内容
(如果第二个参数省略,则从n删除到末尾)
返回删除的新数组,原有数组改变
7、join()
用指定的分隔符将数组每一项拼接为字符串
参数:指定的分隔符(如果省略该参数,则使用逗号作为分隔符)
返回值:拼接好的字符串
是否改变原数组:不改变
8、concat()
用于连接两个或多个数组
参数:参数可以是具体的值,也可以是数组对象。可以是任意多个
返回值:返回连接后的新数组
是否改变原数组:不改变
9、indexOf()
检测当前值在数组中第一次出现的位置索引
参数:array.indexOf(item,start) item:查找的元素 start:字符串中开始检索的位置
返回值:第一次查到的索引,未找到返回-1
是否改变原数组:不改变
10、lastIndexOf()
检测当前值在数组中最后一次出现的位置索引
参数:array.lastIndexOf(item,start) item:查找的元素 start:字符串中开始检索的位置
返回值:第一次查到的索引,未找到返回-1
是否改变原数组:不改变
11、includes()
判断一个数组是否包含一个指定的值
参数:指定的内容
返回值:布尔值
是否改变原数组:不改变
12、sort()
对数组的元素进行排序(默认是从小到大来排序 并且是根据字符串来排序的)
参数:可选(函数) 规定排序规则 默认排序顺序为按字母升序
返回值:排序后新数组
是否改变原数组:改变
sort在不传递参数情况下,只能处理10以内(个位数)数字排序
13、reverse()
把数组倒过来排列
参数:无
返回值:倒序后新数组
是否改变原数组:改变
14、forEach()
循环遍历数组每一项
参数:函数 ary.forEach(function(item,index,ary){}) item:每一项 index:索引 ary:当前数组
返回值:无
是否改变原数组:不改变
forEach中不能使用continue和break,forEach中不能跳出,只能跳过(return跳过)
## 常用的指令
v-html:用innerHTML
v-text:用innerTEXT
v-if:通过添加删除节点进行显示隐藏
v-show:通过display进行显示隐藏,频繁显示隐藏时用,
v-for:优先大于v-if,不建议和v-if一起使用,与key搭配使用
v-bind:绑定属性
v-on:绑定事件
v-once:只渲染一次
v-model:
## 常用的修饰符
.stop:阻止事件冒泡
.prevent:阻止默认事件
.trim:去除前后空格
.once:只触发一次
.keydown:建盘摁下
.number:将数据转换为数字
.sync:可以让子组件双向绑定
.native:绑定dom的原生事件
## 绑定事件不生效
使用.native
原理:绑定dom的原生事件
## keep-alive
名称:缓存组件
用法:
生命周期:activated激活时 deactivated未激活时
属性:
max:缓存的最大数量
include:可以缓存的组件名称
exclude:不可以缓存的组件名称
## data为什么是个函数
防止组件在重复使用时,数据互相干扰,使用函数将产生新作用域,所以同一个组件在不同位置被使用时,不适用同一份数据
## computed,watch,methods的区别
抗不秋他是 买塞吃
computed 计算结果会缓存,如果依赖值发生改变,就会重新调整计算结果,有get和set函数。
watch: 监听数据变化,可以接收新值和旧值,
属性
deep:开启深度监听
immediate:立即执行没有旧值
handler:执行函数
``` js
watch: {
name(new,old) {
},
name: {
deep:true,
immediate:true,
hanlder: function(new,old) {
}
}
}
```
methods 事件方法 执行一次,调用一次,不会缓存
## 怎么操作dom元素
ref
document.querySelector
倒块们他 块瑞 死来们他
document.getElementById
哎了们他
document.getElementsByName/ByClassName/ByTagName
# 路由
## 传值方式
query:通过url传参,刷新值不会变化,不能传输对象。获取方式: this.$route.query.id
params:可以传递对象,但是刷新会消失。获取方式:this.$route.params.id
## $route和$router的区别
$route:路由对象,包含当前的路由信息。
$router:包含路由的操作方法。
## 路由模式
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,按需导入用到的方法,减少不必要的代码体积。然后开启多线程打包,加快打包速度。
部署方面的话可以使用CDN加快访问速度。
其实核心就是首页一定要小,这样才能尽快渲染出来,请求文件一定要少,不要让css或js等文件的请求影响了渲染速度。
## 进新公司的工作流程
先把开发工具(vscode、git、乌龟git、nodejs)装好(如果之前电脑没装好的话),先问领导`git`用https还是ssh链接方式,如果是https的话就等领导给你开好账号,然后使用账号密码把代码 git clone 把代码克隆下来就行,如果是ssh的话就执行 ssh-keygen -t rsa 命令生成公私秘钥,并且将公钥给领导,领导将你的公钥添加完成后就可以使用 git clone 命令直接克隆代码了。