太平人寿-线下二面
1、本地存储以及区别
答:本地存储包括:cookie localStorage sessionStorage indexDB,区别如下:
2、css中隐藏元素的方法
- opacity:0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如 click 事件,那么点击该区域,也能触发点击事件的。
- visibility:hidden,该元素隐藏起来了,但不会改变页面布局,还占据位置,该元素绑定的事件不会生效。
- display:none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉,不占位置。
3、js事件循环机制
js是单线程执行的,页面加载时,会自上而下执行主线程上的同步任务,当主线程代码执行完毕时,才开始执行在任务队列中的异步任务。具体如下:
- 所有同步任务都在主线程上执行,形成一个执行栈。
- 主线程之外,还存在一个"任务队列(eventloop队列或者消息队列)"。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
- 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。哪些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
- 主线程不断重复上面的第三步。
4、浅拷贝和深拷贝;实现深拷贝的方法
-
浅拷贝:拷贝对象的一层属性,如果对象里面还有对象,拷贝的是地址, 两者之间修改会有影响,适用于对象里面属性的值是简单数据类型的。
-
深拷贝:拷贝对象的多层属性,如果对象里面还有对象,会继续拷贝,使用递归去实现。
// 浅拷贝实现方法
拷贝对象:
1、Object.assign()
2、展开运算符{...obj}
拷贝数组:
1、Array.prototype.concat()
2、展开运算符 [...arr]
// 深拷贝实现方法
1、JSON序列化实现
const obj = {
name: '佩奇',
family: {
father: '猪爸爸'
},
hobby: ['跳绳','唱歌']
}
const newObj = JSON.parse(JSON.stringify(obj))
newObj.family.father = '猪老二'
console.log(newObj)
2、lodash实现
const person = {
name: "西精品",
age: 10000,
hobby: ["爱折腾", "目无法纪", "狂妄自大"],
family: {
daughter: "席明哲",
wife: "评论员",
},
};
const baozi = _.cloneDeep(person)
baozi.hobby.push('123')
console.log(baozi)
3、递归实现 (这是重点)
function cloneDeep(target, source) {
for (let k in source) {
if (source[k].constructor === Object) {
target[k] = {};
cloneDeep(target[k], source[k]);
} else if (source[k].constructor === Array) {
target[k] = [];
cloneDeep(target[k], source[k]);
} else {
target[k] = source[k];
}
}
}
const obj = {};
cloneDeep(obj, person);
obj.hobby.push('abroad')
console.log(obj, person);
5、网页请求到渲染经历了什么
- 输入url地址后,首先进行DNS(Domain Name System域名系统)解析(域名服务器负责解析),将相应的域名解析为IP地址。
- 根据IP地址去寻找相应的服务器。
- 与服务器进行TCP的三次握手,建立连接。
- 客户端发送请求,找到相应的资源库,拿到数据后,进行相应的渲染。
6、Vue2中v-if和v-for的优先级?
v-for优先级高于v-if;如果同时出现v-for和v-if,无论判断条件是否成立,都会执行一遍v-for循环,这样浪费性能,所以要尽可能的避免两者一起使用。
7、computed和watch区别
-
计算属性computed
- 支持缓存,只有依赖数据发生改变,才会重新进行计算
- 不支持异步,当computed内有异步操作时无效,无法监听数据的变化。(异步操作包括:axios,回到函数,promise,async/await,事件监听)
- 如果computed需要对数据修改,需要写get和set两个方法,当数据变化时,调用set方法。
- computed擅长处理的场景:一个数据受多个数据影响,例如购物车计算总价。
-
侦听器watch
- 不支持缓存,数据变,直接会触发相应的操作;
- watch支持异步;监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
- immediate:组件加载立即触发回调函数执行
- deep:true的意思就是深入监听,任何修改obj里面任何一个属性都会触发这个监听器里的handler方法来处理逻辑
- watch擅长处理的场景:一个数据影响多个数据,例如搜索框当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。例如ajax请求,复杂的业务逻辑处理等。
8、Vue的核心:数据驱动用什么实现;Vue中数组的方法可以实现响应式是为什么?(源码中加入数组的方法)
-
数据驱动绑定的实现
- vue2的双向数据绑定指的是v-model
- v-model本质上是个语法糖,真正的实现靠:
- v-bind绑定响应式数据
- 触发input事件并传递数据(核心和重点)
等价于
<input v-bind:value="searchText" v-on:input="searchText = $event.target.value">其中:
- $event指当前触发的事件对象
- $event.target 指代当前触发的事件对象的dom
- $event.target.value 当前dom的value值
- 在@input方法中,value => searchText
- 在value中,searchText => value
9、原型链:一个对象的实例原型指向的是哪
null
10、节流、防抖(鼠标滚动事件用什么比较好)
-
防抖:就是指触发事件后 n 秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
- 应用场景:1、用户在搜索框输入文字的时候;2、window触发resize事件的时候。
-
节流:指连续触发事件但是在n秒中只执行一次函数。
- 应用场景:1、鼠标不断点击触发;2、鼠标滑过;3、监听滚动事件,比如是否滑到底部自动加载更多。
-
代码实现
// 防抖
const div = document.querySelector("div");
let i = 1;
function mouseMove() {
div.innerHTML = i++;
}
function debounce(fn, time) {
let timer;
return function () {
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
fn();
}, time);
};
}
div.addEventListener("mousemove", debounce(mouseMove, 500));
// 节流
const div = document.querySelector("div");
let i = 1;
function mouseMove() {
div.innerHTML = i++;
}
function throttle(fn, time) {
let timer;
return function () {
if (!timer) {
timer = setTimeout(function () {
fn();
timer = null;
}, time);
}
};
}
div.addEventListener("mousemove", throttle(mouseMove, 500));
11、Promise和Async Await区别?
-
promise:
- 含义:它是一个对象,也就是说与其他JavaScript对象的用法相似;它使得异步操作具备同步操作的效果,使得程序具备正常的同步运行的流程,回调函数不必再一层层嵌套。
- 特点
- 三种状态:pending(执行中)、resolve(成功)、rejected(失败)
- 可以进行链式调用
- 能错误捕获:Promise。prototype.catch用于指定Promise状态变为rejected时的回调函数,可以认为是.then的简写形式,返回值和.then一样。
-
async await
- 含义
- async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
- await 只能出现在 async 函数中。
- async 函数返回的是一个 Promise 对象,后面可以用then方法。
- 错误捕获:若是reject状态,可以用try-catch捕获
- 含义
let p = new Promise((resolve,reject) => {
setTimeout(() => {
reject('error');
},1000);
});
async function demo(params) {
try {
let result = await p;
}catch(e) {
console.log(e);
}
}
demo();
- 两者区别:
- promise是ES6,async/await是ES7
- async/await相对于promise来讲,写法更加优雅
- reject状态:
- promise错误可以通过catch来捕捉,建议尾部捕获错误
- async/await既可以用.then又可以用try-catch捕捉
12、axios二次封装做了什么?配置基地址直接在原型上加或创建实例加有什么区别?应用上哪个更合理?
- 为什么要封装:
- 随着项目规模增大,如果每发起一次HTTP请求,就要把这些比如设置超时时间、设置请求头、根据项目环境判断使用哪个请求地址、错误处理等等操作,都需要写一遍。这会让代码变得冗余不堪,难以维护。为了提高我们的代码质量,我们应该在项目中二次封装一下 axios 再使用。
- 如何封装:
-
新建一个request.js文件用于调用接口的时候使用
-
在文件中通过axios的create方法新建一个实例,里面配置请求地址和相应的时间,最后将这个配置的实例用instance进行接收
-
通过instance配置请求拦截器和相应拦截器
-
最后将instance默认导出
-
13、跨域
- 同源策略:同源策略是浏览器的一种安全策略, 所谓同源是指域名、协议、端口完全相同,不同源则跨域。
- 解决跨域的方案: - CORS跨域资源共享 - nginx代理跨域
14、常用git命令
git init // 初始化
git clone 地址 // 克隆远程仓库
git clone -b 分支名 地址 // 克隆分支代码到本地
git status //查看状态
git add 文件名 // 将某个文件存入暂存区
git checkout -- file // 撤销工作区的修改 例如:git checkout -- readMe.txt 将本次readMe.txt在工作区的修改撤销掉
git add b c //将b和c存入暂存区
git add . //将所有文件提交到暂存区
git commit -m '提交的备注信息' // 提交到仓库
git remote add origin git@gitee.com:lzwan/smart-mall-2.git // 将远程仓库的名字改为 origin
git push -u origin "master" // 将本地库的所有内容推送到远程库里面
15、webpack熟悉吗?
含义: webpack是一种静态编译工具(预编译),它能把各种资源,例如JS(含JSX)、样式(含less/sass)、图片等都作为模块来使用和处理。 优势:
- 支持异步模块加载
- 扩展性强,插件机制完善
- 开发便捷
16、Vue项目中怎么解决跨域问题?前端怎么配置?后端怎么配置?
- 开发阶段:通过vue-cli解决跨域问题,具体是在config.js里面的webpack的属性proxy里面配置跨域的地址,前端即可通过改地址获取接口里面的数据
- 上线阶段:通过Nginx服务器实现,这个主要是后端操作
17、Vue中data为什么是个函数?
组件是用来复用的,组件中的data写成一个函数,数据以函数返回值形式定义,函数有独立的作用域,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
18、Vue中父子组件生命周期渲染顺序?更新父子组件顺序?在哪个发送请求?mounted发送请求有什么区别
-
父子组件生命周期渲染顺序
- 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
-
更新父子组件顺序
- 父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
-
在哪里发送请求:
- created
-
mounted发送请求有什么区别
- 在created时期请求接口拿到页面数据,DOM 还没有渲染,最后数据和DOM会同步渲染
- 在mounted时期请求接口拿到页面数据,DOM 已经渲染到页面中,拿到数据后再染数据。
19、组件通讯方式;Vuex主要内容
- 组件的通讯方式
1、父传子
通过props传递
父组件: <child :list = 'list' />
子组件: props['list'],接收数据,接受之后使用和data中定义数据使用方式一样
2、子传父
在父组件中给子组件绑定一个自定义的事件,子组件通过$emit()触发该事件并传值。
父组件: <child @receive = 'getData' />
getData(value){value就是接收的值}
子组件: this.$emit('receive',value)
3、兄弟组件传值 provide inject7
通过中央通信 let bus = new Vue()
A组件:methods :{t
sendData(){
bus.$emit('getData',value)
} 发送
B组件:created(){
bus.$on(‘getData’,(value)=>{value就是接收的数据})
} 进行数据接收
- vuex的主要内容
- Vuex 是专为Vue设计的状态管理工具,采用集中式储存管理 Vue 中所有组件的状态。
- 属性
- state属性:基本数据
- getters属性:从 state 中派生出的数据,相当于state的计算属性
- mutation属性:更新 store 中数据的唯一途径,其接收一个以 state 为第一参数的回调函数
- action 属性:提交 mutation 以更改 state,其中可以包含异步操作,数据请求
- module 属性:用于将 store分割成不同的模块。
20、keep-alive;怎么捕获状态(actived钩子函数)
- keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染
- 一般结合路由和动态组件一起使用,用于缓存组件
- 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated
- 提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
21、插槽;插槽和组件的区别
- 插槽:插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。
- 组件:可复用的vue实例,把一些公共的模块抽离出来,写成单独的工具组件或页面,在需要的时候直接引入。
22、Vue中常用的修饰符
事件修饰符:
.prevent 阻止事件默认行为
.stop 阻止事件冒泡
.capture 设置事件捕获机制 多用于遇到事件冒泡时控制触发顺序。
.self 只有点击元素自身才能触发事件
.once 事件只触发一次
按键修饰符:
.tab
.enter
.esc
.space
.delete(捕获"删除"和"空格"键)
.up
.down
.left
.right
23、v-model原理
- v-model本质上是个语法糖,真正的实现靠:
- v-bind绑定响应式数据
- 触发input事件并传递数据(核心和重点)
- 等价于
<input v-bind:value="searchText" v-on:input="searchText = $event.target.value">- $event指当前触发的事件对象
- $event.target 指代当前触发的事件对象的dom
- $event.target.value 当前dom的value值
- 在@input方法中,value => searchText
- 在value中,searchText => value
- 主要提供了两个功能,view层输入值影响data的属性值,属性值发生改变会更新层的数值变化。
- 其底层原理就是(双向数据绑定原理):
- 一方面model层通过Object.defineProperty()来劫持每个属性,一旦监听到变化通知相关的页面元素进行更新。
- 另一方面通过编译模板文件,为控件的v-model绑定input事件,从而页面输入能实时更新相关data属性值。
24、动态路由什么时候会用到
动态菜单
25、导航守卫有几种?常用哪个?防越权具体如何实现?导航守卫设置
-
导航守卫种类:
- 全局路由守卫
- 组件路由守卫
- 路由独享守卫
-
常用全局路由守卫
-
防越权具体实现
- 前后端同时对用户输入信息进行校验,双重验证机制
- 执行关键操作前必须验证用户身份,验证用户是否具备操作数据的权限
- 特别敏感操作可以让用户再次输入密码或其他的验证信息。
- 可以从用户的加密认证 cookie 中获取当前用户 id,防止攻击者对其修改。 或在 session、cookie 中加入不可预测、不可猜解的 user 信息。
- 直接对象引用的加密资源ID,防止攻击者枚举ID,敏感数据特殊化处理
- 永远不要相信来自用户的输入,对于可控参数进行严格的检查与过滤
-
导航守卫如何设置
- 使用router.beforeEach注册一个全局前置守卫,接收3个参数:to/from/next