一、Vue
1. 简单介绍一下Vue的各个生命周期
总共分为 8 个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
breforeCreate: 在实例创建前阶段,此时已经完成的有初始化生命周期initLifecycle,初始化事件中心initEvents,初始化渲染initRender,Vue 实例的挂载元素 el 还没有,这个阶段实例的 data 和 methods 是读不到的。
created:实例创建后,这个阶段已经完成数据观测,属性和方法的运算,watch/event 事件回调,mount 挂载阶段还没有开始。$el 属性目前不可见,数据并没有在DOM元素上进行渲染。
created完成之后,进行template编译等操作,将template编译为render函数,有了render函数后才会执行beforeMount
beforeMount:在 beforeMount 阶段,Vue 实例的$el 和 data 都初始化了,但还是挂载之前为虚拟的 dom 节点,相关的 render 函数首次被调用。
mounted:Vue 实例挂载完成之后调用,el选项的DOM节点被新创建的 vm.$el 替换,并挂载到实例上去,之后调用此生命周期函数,此时实例的数据在DOM节点上进行渲染。
后续的钩子函数执行的过程都是需要外部的触发才会执行
更新前/后:有数据的变化,会调用beforeUpdate,然后经过Virtual Dom,最后updated更新完毕。
销毁前/后:当组件被销毁的时候,会调用beforeDestory,以及destoryed。在执行 destroy 方法后,对 data 的改变不会再触发周期函数,说明此时 Vue 实例已经解除了事件监听以及和 dom 的绑定,但是 dom 结构依然存在。
2. computed和watch的区别
computed: 计算属性是用来声明式的描述一个值依赖了其它的值。当你在模板里把数据绑定到一个计算属性上时,Vue 会在其依赖的任何值导致该计算属性改变时更新 DOM。这个功能非常强大,它可以让你的代码更加声明式、数据驱动并且易于维护。
特点及注意:①有缓存机制;②不能接受参数;③可以依赖其他computed,甚至是其他组件的data;④不能与data中的属性重复
watch:监听的是你定义的变量,当你定义的变量的值发生变化时,调用对应的方法。
①可接受两个参数(当前值和旧值);②监听时可触发一个回调,并做一些事情;③监听的属性必须是存在的;④允许异步
watch配置:handler(回调函数)、deep(是否监听对象内部值的变化,监听数组的变动不需要这么做。)、immediate (是否立即执行)
总结:
当有一些数据需要随着另外一些数据变化时,建议使用computed;
当有一个通用的响应数据变化的时候,要执行一些业务逻辑或异步操作的时候建议使用watch;
3. $router和$route的区别
$route 为'路由信息对象',是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
$router 为'路由实例'对象,包括了路由的跳转方法,钩子函数等。
4. Vue双向数据绑定的原理
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
第一步:需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到数据的变化;
第二步:compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图;
第三步:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:
在自身实例化时往属性订阅器(dep)里面添加自己,自身必须有一个 update()方法,待属性变动 dep.notice()通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。
第四步:MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的 model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。
5. Vue如何优化首页的加载速度?
① 第三方js库按CDN引入;(一、cdn引入; 二、去掉第三方库引入的import; 三、把第三方库的js文件从打包文件里去掉;四、修改webpack.base.conf.js文件.添加externals配置;)
② vue-router路由懒加载;
③ 压缩图片资源;
④ 静态文件本地缓存;
http缓存:推荐网站:http缓存浅谈
service worker离线缓存:,缺点:需要在HTTPS站点下,推荐网站:网站渐进式增强体验(PWA)改造:Service Worker 应用详解
6. Vue中 vm.$set的用法
vm.$set( target, propertyName/index, value ) 这是全局 Vue.set 的别名。
向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性。
7. Vuex 是什么? 有哪几种属性?
Vuex 是一个专为 vue.js 应用程序开发的状态管理模式。 有 5 种,分别是 state、getter、mutation、action、module
vuex 的 store 是什么? vuex 就是一个仓库,仓库里放了很多对象。其中 state 就是数据源存放地,对应于一般 vue 对象里面的 data, state 里面存放的数据是响应式的,vue 组件从 store 读取数据,若是 store 中的数据发生改变,依赖它的相应数据的组件也会发生更新,它通过 mapState 把全局的 state 和 getters 映射到当前组件的 computed 计算属性。
vuex 的 getter 是什么? getter 可以对 state 进行计算操作,它就是 store 的计算属性虽然在组件内也可以做计算属性,但是 getters 可以在多给件之间复用如果一个状态只在一个组件内使用,是可以不用 getters。
vuex 的 mutation 是什么? 更改Vuex的store中的状态的唯一方法是提交mutation。
vuex 的 action 是什么? action 类似于 muation, 不同在于:action 提交的是 mutation,而不是直接变更状态。action 可以包含任意异步操作。
vuex 的 module 是什么? 面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。 如果请求来的数据不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入 vuex 的 state 里,如果被其他地方复用,请将请求放入 action 里,方便复用,并包装成 promise 返回。
8. Vue怎么实现强制刷新组件?
① v-if
当v-if的值发生变化时,组件都会被重新渲染一遍。因此,利用v-if指令的特性,可以达到强制
<comp v-if="update"></comp>
<button @click="reload()">刷新comp组件</button>
data() {
return {
update: true
}
},
methods: {
reload() {
// 移除组件
this.update = false
// 在组件移除后,重新渲染组件
// this.$nextTick可实现在DOM 状态更新后,执行传入的方法。
this.$nextTick(() => {
this.update = true
})
}
}
② this.$forceUpdate
<button @click="reload()">刷新当前组件</button>
methods: {
reload() {
this.$forceUpdate()
}
}
二、JavaScript
1. 深拷贝与浅拷贝的区别,实现深拷贝的几种方法
自己实现了一个深拷贝,只考虑了数组和对象,不完善,直接上代码:
let deepClone = function (target) {
let res;
if (typeof target === 'object') {
let beArray = Array.isArray(target);
res = beArray ? [] : {};
if (beArray) {
for (val of target) {
res.push(deepClone(val));
}
} else {
for (key in target) {
if (target.hasOwnProperty(key)) {
res[key] = deepClone(target[key]);
}
}
}
} else {
res = target;
}
return res;
}
let testObject = {
a: 1,
b: 2,
c: ['a', 'b', 'c']
};
let copyObject = deepClone(testObject);
console.log(copyObject); // {"a":1,"b":2,"c":["Yeah!","b","c"]}
testObject.b = { 'changeB': { 'haha~': 2 } };
copyObject.c[0] = 'Yeah!';
console.log(testObject); // {"a":1,"b":{"changeB":{"haha~":2}},"c":["a","b","c"]}
console.log(copyObject); // {"a":1,"b":2,"c":["Yeah!","b","c"]}
浅拷贝和深拷贝理解
这两篇算比较好的暂时就不码了。
2. ES6中的...有哪些用法
不定参数 又称为剩余参数,在函数的命名参数前添加三个点(...)就表明这是一个不定参数,该参数是一个数组。
function pick(object, ...keys) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}
展开运算符
let values = [10, 845, 54, 959];
Math.max(...values); // 959
不定元素
let colors = ['red', 'blue', 'green', 'pink', 'violet'];
//收集元素
let [firstColor, ...resColor] = colors;
console.log(firstColor); // red
console.log(resColor); // ["blue", "green", "pink", "violet"]
//克隆元素
let [...cloneColors] = colors;
console.log(cloneColors); // ["red", "blue", "green", "pink", "violet"]
3. 检查数据类型的方法
比typeof和instanceof 相对准确的是,Object.prototype.toString.call()。
let set = new Set([1,2,3]);
Object.prototype.toString.call(set); // [object Set]
4. 怎么随机打乱一个数组
<div>原始值: 1,2,3,4,5,6,7,8,9,10</div>
<div class="demo">原始值</div>
let arr = [1,2,3,4,5,6,7,8,9,10];
let demoDom = document.querySelector('.demo');
let unSort = function(arr) {
let i = arr.length;
while(i) {
let j = Math.floor(Math.random() * i--);
[arr[j], arr[i]] = [arr[i], arr[j]];
}
return arr;
}
5.如何知道一串字符串中每个字母出现的次数?
var arrString = 'abcaddefaabc';
arrString.split('').reduce((res, cur) => {
res[cur] ? res[cur] ++ : res[cur] = 1
return res;
}, {})
// {"a": 4, "b": 2, "c": 2, "d": 2, "e": 1, "f": 1}