1、怎么理解mvvm这种设计模式
| M | Model 模型 | 指的是数据层 | 当model的属性改变时,我们不用自己手动操作DOM元素,来改变view的显示 |
|---|---|---|---|
| V | View 视图 | 指的是用户页面 | 反之亦然,我们称之为数据的双向绑定。 |
| VM | ViewModel | 视图模型 | 视图模型是MVVM模式的核心,它是连接view和model的桥梁, |
| Model–View–ViewModel (MVVM) 是一个软件架构设计模式,是一种简化用户界面的事件驱动编程方式。 | MVVM实现了view和model的自动同步 |
2、v-if和v-show的区别,使用场景区别
| v-if | v-show |
|---|---|
| v-if在条件切换时,会对标签进行适当的创建和销毁 | v-show则仅在初始化时加载一次 ,因此v-if的开销相对来说会比v-show大。 |
| v-if是惰性的,只有当条件为真时才会真正渲染标签;如果初始条件不为真,则v-if不会去渲染标签。 | v-show则无论初始条件是否成立,都会渲染标签,它仅仅做的只是简单的CSS(display)切换。 |
| v-if适用于不需要频繁切换元素显示和隐藏的情况 | v-show适用于需要频繁切换元素的显示和隐藏的场景。 |
| v-for优先级高于v-if | |
| 如果同时出现v-for和v-if,无论判断条件是否成立,都会执行一遍v-for循环,这样浪费性能,所以要尽可能的避免两者一起使用。 |
3、事件修饰符和按键修饰符有哪些
| 事件修饰符: | 按键修饰符: | v-model修饰符有哪些 |
|---|---|---|
| .prevent 阻止事件默认行为 | .tab | trim 去除首尾空格 |
| .stop 阻止事件冒泡 | .enter | .lazy 只在输入框失去焦点或按回车键时更新内容,不是实时更新 |
| .capture 设置事件捕获机制 | .esc | .number 将数据转换成number类型(原本是字符串类型) |
| .self 只有点击元素自身才能触发事件 | .space | |
| .once 事件只触发一次 | .delete 捕获"删除"和"空格"键 | |
| .up | ||
| .down | ||
| .left | ||
| .right |
5、v-for中为什么要加key
| 作用 | 原理 |
|---|---|
| 1.key的作用主要是为了高效的更新虚拟DOM,提高渲染性能。 | 1.vue实现了一套虚拟DOM,使我们可以不直接操作DOM元素只操作数据,就可以重新渲染页面,而隐藏在背后的原理是高效的Diff算法 |
| 2.key属性可以避免数据混乱的情况出现。 | 2.当页面数据发生变化时,Diff算法只会比较同一层级的节点; |
| 3.就近更新原则 DIFF算法直接查询当前key值所在的位置进行数据diff算法中的patch 函数进行新旧值进行对比,然后新值覆盖旧值 | 3.如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点后面的子节点; 如果节点类型相同,则会重新设置该节点属性,从而实现节点更新 |
| 4.使用key给每个节点做一个唯一标识,Diff算法就可以正确失败此节点,"就地更新"找到正确的位置插入新的节点。 |
7、组件中的data为什么是函数,new Vue 实例里,data 可以直接是一个对象
1、组件是用来复用的,组件中的data写成一个函数,数据以函数返回值形式定义,函数有独立的作用域,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
2、而单纯的写成对象形式,由于对象是引用类型,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
3、因为new vue里面的代码是不存在复用的情况,所以可以写成对象形式
8、computed和watch的区别是什么
| 计算属性computed: | 侦听属性watch: |
|---|---|
| 1、支持缓存,只有依赖数据发生改变,才会重新进行计算 | 1、不支持缓存,数据变,直接会触发相应的操作; |
| 2、不支持异步,当computed内有异步操作时无效,无法监听数据的变化 | 2、watch支持异步;监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值; |
| 3、如果computed需要对数据修改,需要写get和set两个方法,当数据变化时,调用set方法。 | 3、immediate:组件加载立即触发回调函数执行 |
| 4、computed擅长处理的场景:一个数据受多个数据影响,例如购物车计算总价 | 4、deep:true的意思就是深入监听,任何修改obj里面任何一个属性都会触发这个监听器里的 handler方法来处理逻辑 |
| 5、watch擅长处理的场景:一个数据影响多个数据,例如搜索框 |
9、组件化和模块化的区别
| 组件化 | 模块化 |
|---|---|
| 组件相当于库,把一些能在项目里或者不同类型项目中可复用的代码进行工具性的封装。 | 模块相应于业务逻辑模块,把同一类型项目里的功能逻辑进行进行需求性的封装。 |
10、怎么理解vue中的虚拟DOM
| 原理 | 好处 |
|---|---|
| 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象; | 1. 性能优化 |
| diff 算法 : 比较两棵虚拟 DOM 树的差异; | 2. 无需手动操作DOM |
| pach 算法 : 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。 | 3. 可以跨平台,服务端渲染等 |
11、怎么理解vue的生命周期
vue的生命周期:vue实例从创建到销毁的全过程,这个过程可以分为3个阶段
第一阶段:初始化阶段 创建vue实例,准备数据,准备模板,渲染视图
第二阶段:数据更新阶段 当数据变化时,会进行新旧DOM的对比,对比出差异的部分,进行差异化更新。
第三阶段:实例销毁阶段 当vm.$destroy()被调用,vue实例就会被销毁,释放相关资源,此时再更新数据,视图不会再变化。
12、vue 钩子函数有哪些,有哪些使用的场景
1、各阶段包含钩子:
beforeCreate 在data数据注入到vm实例之前,此时vm身上没有数据
created 在data数据注入到vm实例之前,此时vm身上有数据
beforeMount 生成的结构替换视图之前,此时DOM还没更新
mounted 生成的结构替换视图之前,此时DOM已经更新完成
beforeUpdate 数据变化了,dom更新之前
updated 数据变化了,dom更新之后
activated 被keep-alive缓存的组件激活时调用
deactivated 被keep-alive缓存的组件停用时调用
beforeDestroy 实例销毁,是否资源之前
destroyed 实例销毁,是否资源之后
这些钩子函数会在vue的生命周期的不同阶段,自动被vue调用
2、常用的钩子函数使用场景:
beforeCreate 做loading的一些渲染
created 结束loading, 发送数据的请求,拿数据
mounted 可以对dom进行操作
updated 监视数据的更新
beforeDestroy 销毁非vue资源,防止内存泄漏,例如清除定时器
activated 当我们运用了组件缓存时,如果想每次切换都发送一次请求的话,需要把请求函数写在activated中,而写在created或mounted中其只会在首次加载该组件的时候起作用。
13、Vue 的父组件和子组件生命周期钩子函数执行顺序
1、Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:
1)加载渲染过程
父 beforeCreate -> 父 created ->
父 beforeMount -> 子 beforeCreate ->
子 created -> 子 beforeMount ->
子 mounted -> 父 mounted
2)子组件更新过程
父 beforeUpdate -> 子 beforeUpdate ->
子 updated -> 父 updated
3)父组件更新过程
父 beforeUpdate -> 父 updated
4)销毁过程
父 beforeDestroy -> 子 beforeDestroy ->
子 destroyed -> 父 destroyed
14、vue组件传值的方式
| 父传子 | 子传父 | 兄弟组件传值 |
|---|---|---|
| 通过props传递 | 在父组件中给子组件绑定一个自定义的事件,子组件通过$emit()触发该事件并传值。 | 通过中央通信 |
| 父组件: | 父组件: | |
| 子组件: props['list'],接收数据,接受之后使用和data中定义数据使用方式一样 | 子组件: this.$emit('receive',value) |
let bus = new Vue()
A组件://发送
methods :{
sendData(){
bus.$emit('getData',value)
}
}
B组件://进行数据接收
created(){
bus.$on(‘getData’,(value)=>{//value就是接收的数据})
}
15、$nextTick是什么?原理是什么
| 背景 | 定义 | 原理 | 场景 |
|---|---|---|---|
| 1、简单来说,Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。 | 2、在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数。 | 3、vue用异步队列的方式来控制DOM更新和nextTick回调先后执行。简单来说,nextTick是做了promise加上setTimeout的封装,利用事件换行机制,来确保当nextTick出现时,都是在我们所有操作DOM更新之后的。 | 4.1 点击获取元素宽度4.2 使用swiper插件通过 ajax 请求图片后的滑动问题4.3 点击按钮显示原本以 v-show = false 隐藏起来的输入框,并获取焦点 |
16、vue是如何获取DOM
1、先给标签设置一个ref值,
再通过`this.$refs.domName`获取,这个操作要在mounted阶段进行。
2、例如:
mounted(){
const dom = this.$refs.test
}
17、v-on可以监听多个方法吗
可以 例如:
18、谈谈你对 keep-alive 的了解
| keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 |
| 一般结合路由和动态组件一起使用,用于缓存组件 对应两个钩子函数 activated 和 deactivated |
| 对应两个钩子函数 activated 和 deactivated,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated |
| 提供 include 和exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高; |
// 例如:
19、谈谈你对slot的了解
1、什么是插槽
1.1 插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。
1.2 插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制
2、插槽使用
2.1 默认插槽
在子组件中写入slot,slot所在的位置就是父组件要显示的内容
2.2 具名插槽
在子组件中定义了三个slot标签,其中有两个分别添加了name属性header和footer
在父组件中使用template并写入对应的slot名字来指定该内容在子组件中现实的位置
2.3 作用域插槽 在子组件的slot标签上绑定需要的值
在父组件上使用slot-scope=“user”来接收子组件传过来的值
20、vue中动态组件如何使用
1、在某个中使用 is 特性来切换不同的组件:
TabComponent:已注册组件的名字
21、v-model的原理是什么
1、v-model主要提供了两个功能,view层输入值影响data的属性值,属性值发生改变会更新层的数值变化.
2、v-model指令的实现:
3.1 v-bind:绑定响应式数据
3.2 触发input事件并传递数据 (核心和重点)3、其底层原理就是(双向数据绑定原理):
3.1 一方面modal层通过defineProperty来劫持每个属性,一旦监听到变化通过相关的页面元素更新。
3.2 另一方面通过编译模板文件,为控件的v-model绑定input事件,从而页面输入能实时更新相关data属性值。
22、vue响应式vue的原理
1、原理:
Vue 的响应式原理是核心是通过 ES5 的 Object.defindeProperty 进行数据劫持,然后利用 get 和 set 方法进行获取和设置,data 中声明的属性都被添加到了get和set中,当读取 data 中的数据时自动调用 get 方法,当修改data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。
2、底层代码实现:
let data = { name: "lis", age: 20, sex: "男" }
// vue2.0实现 使用Object.defineProperty进行数据劫持
for(let key in data){
let temp = data[key]
Object.defineProperty(data, data[key], {
get(){
return temp
},
set(value){
temp = value
}
})
}
// vue3.0实现 使用Proxy 进行数据的代理
let newData = new Proxy(data, {
get(target, key){
return target[key]
},
set(target, key, value){
target[key] = value
}
})
23、vue2.0和vue3.0响应式的区别
| vue2.0 | vue3.0 |
|---|---|
| Object.defineProperty | Proxy |
| 1) 用于监听对象的数据变化 | 1. proxy返回的是一个新对象, 可以通过操作返回的新的对象达到目的 |
| 2) 无法监听数组变化(下标,长度) | 2. 可以监听到数组变化,也可以监听到动态添加的数据 |
| 3) 只能劫持对象的自身属性,动态添加的劫持不到 |
24、router和route的区别
| $router对象 | $route对象 |
|---|---|
| 1)$router对象是全局路由的实例,是router构造方法的实例 | 1)$route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等 |
| 2)$router对象上的方法有:push()、go()、replace() | 2)$route对象上的属性有:path、params、query、hash等等 |
25、路由传参的方式和区别
1、方式:params 和 query
2、区别:
1)params用的是name,传递的参数在地址栏不会显示,类似于post
2)query用的是patch,传递的参数会在地址栏显示出来,类似于get
3、举例说明:
1)params 传参
传:this.$router.push({
name: 'particulars',
params: { id: id }
})
接:this.$route.params.id
2)query传参
传:this.$router.push({
path: '/particulars',
query: { id: id }
})
接:this.$route.query.id
26、Vue模版编译原理知道吗,能简单说一下吗
1、简单说,Vue的编译过程就是将template转化为render函数的过程。
2、首先解析模版,生成AST语法树(一种用JavaScript对象的形式来描述整个模板)。
使用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相关处理。
3、Vue的数据是响应式的,但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化,对应的DOM也不会变化。那么优化过程就是深度遍历AST树,按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的比对,对运行时的模板起到很大的优化作用。
4、编译的最后一步是将优化后的AST树转换为可执行的代码。
27、SSR了解吗
1、SSR也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端。
2、SSR有着更好的SEO、并且首屏加载速度更快等优点。不过它也有一些缺点,比如我们的开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于Node.js的运行环境。还有就是服务器的压力比较大。
3、vueJS的ssr 主要用的是nextJS 进行服务端渲染,服务端采用的是nodeJS服务运行
28、你都做过哪些Vue的性能优化
1、v-if和v-for不能连用 2、页面采用keep-alive缓存组件 3、合理使用v-if和v-show 4、key保证唯一 5、使用路由懒加载、异步组件、组件封装 6、防抖、节流 7、第三方模块按需导入 8、图片懒加载 9、精灵图的使用 10、代码压缩
29、Vue-router 路由有哪些模式
一般有两种模式:
1、hash 模式:后面的 hash 值的变化,浏览器既不会向服务器发出请求,浏览器也不会刷新,每次 hash 值的变化会触发 hashchange 事件。
2、history 模式:利用了 HTML5 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
30、Vuex 是什么?有哪几种属性?
1、Vuex 是专为Vue设计的状态管理工具,采用集中式储存管理 Vue 中所有组件的状态。
2、属性
(1)state属性:基本数据
(2)getters属性:从 state 中派生出的数据
(3)mutation属性:更新
store 中数据的唯一途径,其接收一个以 state 为第一参数的回调函数 (4)action 属性:提交 mutation 以更改
state,其中可以包含异步操作,数据请求
(5)module 属性:用于将 store分割成不同的模块。
31、axios封装请求拦截器和响应拦截器
interceptors:【ɪntərˈsɛptərz】 1、项目中会在utils文件中,封装一个request.js文件 2、通过axios.create()配置baseURL,并得到一个request实例 3、通过request.interceptors.request.use来配置请求拦截 4、通过request.interceptors.response.use来配置响应拦截
32、webpack在项目中的常见配置
1、 配置兼容编译ES6转成ES5
用babel来编译,npm i babel-core babel-loader babel-preset-env babel-polyfill babel-plugin-transform-runtime --save-dev
2、配置跨域代理服务
用proxy进行代理,在devServer里面配置,proxy:{'/api':{target:代理的地址}}
3、配置打包路径
publicPath:'/'
4、配置打包出去文件
outputDir: 'dist'
5、配置执行环境变量
启动的端口 const port = process.env.port || process.env.npm_config_port || 9528
OUTH 面试题
32、setTimeout和Promise区别(宏任务和微任务)
| setTimeout | Promise |
|---|---|
| 宏任务有Event Table、Event Queue, | 微任务有Event Queue |
| 宏任务:包括整体代码; script,setTimeout,setInterval、I/O、UI 交互事件、setImmediate(Node.js 环境); | 微任务:Promise、MutaionObserver、process.nextTick(Node.js 环境) |
(1)1、代理模式;2、构造函数模式;3、工厂模式;4、单例模式;5、策略模式;6、订阅发布模式(观察者模式);7、迭代器模式等等。 (2)常用的前端开发设计模式有:模块模式,构造函数模式,工厂模式,混合模式,单例模式以及订阅-发布模式。 (3) (4)模块模式:在立即执行函数表达式中定义的变量和方法在外界是访问不到的,只能通过其向外部提供的接口,"有限制"地访问.通过函数作用域解决了属性和方法的封装问题. (5)迭代器模式: es6中提供了Iterator ,用于遍历容器,并访问容器中的元素 1:提供一致的遍历各种数据结构的方式,而不用了解数据的内部结构。2:提供遍历容器(集合)的能力而无需改变容器的接口
33、 ES6常用
(1)Es6常用的有,常量const、变量let; (2)字符串新增扩展API(includes、startsWidth【表示参数字符串是否在原字符串的头部,返回的是boolean】、endsWith【表示参数字符串是否在原字符串的尾部,返回的是boolean】) (3)模板字符串、解构表达式(结构对象或者数组)、展位运算(合并数组使用)、箭头函数、mapreduce、
34、 事件委托以及优缺点
(1)优点:1、减少事件注册,节省内存。
(2)缺点:1、事件委托基于冒泡,对于不冒泡的事件不支持。2、层级过多,冒泡过程中,可能会被某层组织掉
35、this的各种情况
(1)以函数形式调用时,this永远都是window
(2)以方法的形式调用时,this是调用方法的对象
(3).以构造函数的形式调用时,this是新创建的那个对象
(4)使用call和apply调用时,this是指定的那个对象
(5)箭头函数:箭头函数的this看外层是否有函数
36、 原型链
每个对象都会在内部初始化的属性
prototype(原型),当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么就会去这个prototype上一级里面查询这个属性,没有在往上查询,一级一级的往上查询prototype。这就是原型链 原型链的顶端 null
37、JS里垃圾回收机制是什么,常用的是哪种,怎么处理的
1、JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。
2、JS中最常见的垃圾回收方式是标记清除。
工作原理:是当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。
工作流程: 垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记。 去掉环境中的变量以及被环境中的变量引用的变量的标记。
再被加上标记的会被视为准备删除的变量。 垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间
38、for in和for of的区别
| for…in | for…of |
|---|---|
| 推荐在循环对象属性的时候,使用for…in, | 在遍历数组的时候的时候使用for…of |
| for…in循环出的是key | for…of循环出的是value |
| for…of是ES6新引入的特性。修复了ES5引入的for…in的不足 | |
| for…of不能循环普通的对象,需要通过和Object.keys()搭配使用 |
39、Diff 算法的执行过程
1、在执行Diff算法的过程就是调用名为 patch 的函数,比较新旧节点。一边比较一边给真实的 DOM 打补丁。 patch 函数接收两个参数 oldVnode 和 Vnode,它们分别代表新的节点和之前的旧节点。这个patch函数会比较 oldVnode 和 vnode 是否是相同的, 即函数 sameVnode(oldVnode, vnode), 根据这个函数的返回结果分如下两种情况: True: 则执行 patchVnode False: 则用 vnode 替换 oldVnode 2、DIFF算法分为三大策略:tree diff | Component diff | Element diff
40、async/await和Promise区别
50、JS内存及垃圾回收、闭包的创建与回收



