1.es5和es6的区别,说一下你所知道的es6
ES6是继ES5之后的一次改进,相对于ES5更加简洁,提高了开发效率
1)let声明变量和const声明常量,两个都有块级作用域
ES5中是没有块级作用域的,并且var有变量提升,在let中,使用的变量一定要进行声明
2)箭头函数
ES6中的函数定义不再使用关键字function(),而是利用了()=>来进行定义
3)模板字符串
模板字符串是增强版的字符串,用反引号(`)标识,可以当作普通字符串使用,也可以用来定义多行字符串
4)解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值
let a = 1;let b = 2;
[a,b] = [b,a]; //a=2 b=1
5)for of循环
for...of循环可以遍历数组、Set和Map结构、某些类似数组的对象、对象,以及字符串
let arr = [11,22,33,44,55];
let sum = 0;
for(let i=0;i<arr.length;i++){
sum += arr[i];
}
// 将下面for循环改成for of形式
let arr = [11,22,33,44,55];
let sum = 0;
for(value of arr){
sum += value;
}
6)import、export导入导出
ES6标准中,Js原生支持模块(module)。将JS代码分割成不同功能的小块进行模块化,将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用
// 只导入一个
import {sum} from "./example.js"
// 导入多个
import {sum,multiply,time} from "./exportExample.js"
// 导入一整个模块
import * as example from "./exportExample.js"
//可以将export放在任何变量,函数或类声明的前面
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
//也可以使用大括号指定所要输出的一组变量
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
//使用export default时,对应的import语句不需要使用大括号
let bosh = function crs(){}
export default bosh;
import crc from 'crc';
//不使用export default时,对应的import语句需要使用大括号
let bosh = function crs(){}
export bosh;
import {crc} from 'crc';
7)set数据结构
Set数据结构,类似数组。所有的数据都是唯一的,没有重复的值。它本身是一个构造函数
应用场景Set用于数据重组,Map用于数据储存
Set:
(1)成员不能重复
(2)只有键值没有键名,类似数组
(3)可以遍历,方法有add, delete,has
Map:
(1)本质上是健值对的集合,类似集合
(2)可以遍历,可以跟各种数据格式转换
let arr = [12,43,23,43,68,12];
let item = [...new Set(arr)];
console.log(item);//[12, 43, 23, 68]
8)... 展开运算符
可以将数组或对象里面的值展开;还可以将多个值收集为一个变量
9)修饰器 @
decorator是一个函数,用来修改类甚至于是方法的行为。修饰器本质就是编译时执行的函数
10)class 类的继承
ES6中不再像ES5一样使用原型链实现继承,而是引入Class这个概念
11)async、await
使用 async/await, 搭配promise,可以通过编写形似同步的代码来处理异步流程, 提高代码的简洁性和可读性
async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成
事件循环中分为宏任务队列和微任务队列
其中setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行
promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行
async函数表示函数里面可能会有异步方法,await后面跟一个表达式
async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行
12)promise
Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理、强大
13)Symbol
Symbol是一种基本类型。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的
ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
ES6 数据类型除了 Number 、 String 、 Boolean 、 Objec t、 null 和 undefined ,还新增了 Symbol
14)Proxy代理
使用代理(Proxy)监听对象的操作,然后可以做一些相应事情
2.promise/async/await的执行顺序
console.log('script start')
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
setTimeout(function() {
console.log('setTimeout')
}, 0)
new Promise(resolve => {
console.log('Promise')
resolve()
})
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
console.log('script end')
上述,在Chrome 66
和node v10
中,正确输出是:
script start
async2 end
Promise
script end
promise1
promise2
async1 end
setTimeout
- 正常输出
script start
- 执行
async1
函数,此函数中又调用了async2
函数,输出async2 end
。回到async1
函数,遇到了await
,让出线程。 - 遇到
setTimeout
,扔到下一轮宏任务队列 - 遇到
Promise
对象,立即执行其函数,输出Promise
。其后的resolve
,被扔到了微任务队列 - 正常输出
script end
- 此时,此次
Event Loop
宏任务都执行完了。来看下第二步被扔进来的微任务,因为async2
函数是async
关键词修饰,因此,将await async2
后的代码扔到微任务队列中 - 执行第4步被扔到微任务队列的任务,输出
promise1
和promise2
- 执行第6步被扔到微任务队列的任务,输出
async1 end
- 第一轮EventLoop完成,执行第二轮EventLoop。执行
setTimeout
中的回调函数,输出setTimeout
。
Vue为什么要求模板只能有一个根元素
首先看一看template这个标签,这个标签是html5的新标签,有三个特性:
隐藏性:不会显示在页面中
任意性:可以写在页面的任意地方
无效性: 没有一个根元素包裹,任何HTML内容都是无效的
每一个.Vue的单文件组件本质就是一个vue实例,既然是一个vue实例,它就要有一个入口,如果有多个div,就不无法指定这个vue实例的根入口。
就像一个HTML文档只能有一个根元素一样,多个根元素必将导致无法构成一颗树,所以解释了 <template></template>只有一个<div>根元素。
vue 生命周期
生命周期钩子 | 详细 |
---|---|
beforeCreate | 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。 |
created | 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。 |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用。 |
mounted | el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。 |
beforeUpdate | 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。 |
updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。 |
activated | keep-alive 组件激活时调用。 |
deactivated | keep-alive 组件停用时调用。 |
beforeDestroy | 实例销毁之前调用。在这一步,实例仍然完全可用。 |
destroyed | Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 |
computed和watch的区别
watch擅长处理的场景:一个数据影响多个数据
1. 不支持缓存,数据变,直接会触发相应的操作;
2.watch支持异步;
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
4. 当一个属性发生变化时,需要执行对应的操作;一对多;
5. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate:组件加载立即触发回调函数执行,
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
computed擅长处理的场景:一个数据受多个数据影响
1. 支持缓存,只有依赖数据发生改变,才会重新进行计算
2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
4. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
v-if和v-for哪个优先级更好,如何去优化这个问题?
1.1 v-for的优先级会更高 (两者的渲染函数里面是可以明确的看到的)
1.2 如果同时出现,每次渲染的时候都会先循环再判断条件,无论如何循环都不可避免,浪费了性能
1.3 要避免这种情况出现,在外层嵌套template,把v-if加在template上 (或者先做以一次计算,只显示需要渲染的数组)
Vue组件的data为什么必须是个函数,而Vue的跟实例没有此限制?
函数每次执行都会返回全新的data对象实例(initState->initData->)
data如果是个对象,会污染其他组件的data数据
根实例是通过new来创建的,只会创建一次,所以没有影响
vue中的key的作用和工作原理?说说对他的理解
1.key的作用是为了更高效的更细虚拟dom,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同的元素,是得整个patch过程更加高效,减少dom操作量,提高性能
2.另外,若不设置key还可能在列表更新时引发一些隐蔽得bug
3.vue中在使用相同标签名元素得过度切换时,也会使用key属性,其目的是为了让vue可以区分他们,否则vue只会替换其内部属性而不会出发过渡效果。
理解VUE双向数据绑定原理
1.vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
2.核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法;
3.介绍一下Object.defineProperty()方法
(1)Object.defineProperty(obj, prop, descriptor) ,这个语法内有三个参数,分别为 obj (要定义其上属性的对象) prop (要定义或修改的属性) descriptor (具体的改变方法)
(2)简单地说,就是用这个方法来定义一个值。当调用时我们使用了它里面的get方法,当我们给这个属性赋值时,又用到了它里面的set方法;
待整理 ........................
js 的深拷贝和浅拷贝
对于对象来说,浅复制是对对象地址的复制,并没 有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,
而深复制则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
同级组件之间传值,store,eventBus, this.$root.$on()
keepAlived得钩子函数()
vue-route得钩子函数,以及详情
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
route.beforeEach
route.afterEach
vue meta权限控制
本地缓存有哪些
cook localStorage() seesionStorage() indexBD
数据双向绑定原理(vue实现原理)
事件冒泡(原理以及原生如何阻止)
.stop .default
父子组件传值,所有得方法()
this.$emit() this.$parent props this.$chidren provide inject
原型链
每个对象都可以有一个_proto_,他会指向该对象构造函数的原型对象
prototype函数所独有的,指向对象的原型对象
js中的异步处理方式有哪几种?
1.回调函数
2.事件监听
3.观察者模式
4.promise
5.async await
js中的类型判断
1、typeof
检测不出null 和 数组,结果都为object,所以typeof常用于检测基本类型
2、instanceof
不能检测出number、boolean、string、undefined、null、symbol类型,所以instancof常用于检测复杂类型以及级成关系
3、constructor
null、undefined没有construstor方法,因此constructor不能判断undefined和null。
但是contructor的指向是可以被改变,所以不安全
4、Object.prototype.toString.call
全类型都可以判断
vue组件化的理解
虚拟dom的好处