Vue面试题
一、 vue-router 有哪些钩子函数(导航守卫)?
- 全局前置/钩子:beforeEach、beforeResolve、afterEach
- 路由独享的守卫:beforeEnter
- 组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
二、mvvm和mvc区别?它和其它框架(jquery)的区别是什么?哪些场景适合?
- mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
区别
:vue数据驱动,通过数据来显示视图层而不是节点操作。场景
:数据操作比较多的场景,更加便捷。
三、 vue.js的两个核心是什么?
- 数据驱动和组件化。
四、watch、methods 和 computed 的区别?
- watch 为了监听某个响应数据的变化。computed 是自动监听依赖值的变化,从而动态返回内容,主要目的是简化模板内的复杂运算。所以区别来源于用法,只是需要动态值,那就用 computed ;需要知道值的改变后执行业务逻辑,才用 watch。
- methods是一个方法,它可以接受参数,而computed 不能,computed 是可以缓存的,methods 不会。computed 可以依赖其他 computed,甚至是其他组件的 data。
- 小结:
当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed。如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化。
五、route 和 router 的区别是什么?
- route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
- router是“路由实例对象”,包括了路由的跳转方法(push、replace),钩子函数等。
六、说一下 Vue 和 React 的认识,做一个简单的对比
1.监听数据变化的实现原理不同
- Vue 通过 getter/setter 以及一些函数的劫持,能精确快速的计算出 Virtual DOM 的差异。这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
- React 默认是通过比较引用的方式进行的,如果不优化,每当应用的状态被改变时,全部子组件都会重新渲染,可能导致大量不必要的 VDOM 的重新渲染。
Vue 不需要特别的优化就能达到很好的性能,而对于 React 而言,需要通过 PureComponent/shouldComponentUpdate 这个生命周期方法来进行控制。如果你的应用中,交互复杂,需要处理大量的 UI 变化,那么使用 Virtual DOM 是一个好主意。如果你更新元素并不频繁,那么 Virtual DOM 并不一定适用,性能很可能还不如直接操控 DOM。
为什么 React 不精确监听数据变化呢?这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而 React 更强调数据的不可变
。
2.数据流的不同
- Vue 中默认支持双向绑定,组件与 DOM 之间可以通过 v-model 双向绑定。但是,父子组件之间,props 在 2.x 版本是单向数据流
- React 一直提倡的是单向数据流,他称之为 onChange/setState()模式。
不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。
3.模板渲染方式的不同
a.在表层上,模板的语法不同
- React 是通过 JSX 渲染模板
- 而 Vue 是通过一种拓展的 HTML 语法进行渲染
b.在深 层上,模板的原理不同,这才是他们的本质区别:
- React 是在组件 JS 代码中,通过原生 JS 实现模板中的常见语法,比如插值,条件,循环等,都是通过 JS 语法实现的
- Vue 是在和组件 JS 代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现
七、请说出vue.cli项目中src目录每个文件夹和文件的用法?
assets 文件夹是放静态资源;
components 是放组件;
route r是定义路由相关的配置;
view 视图;
app.vue 是一个应用主组件;
main.js 是入口文件
八、生命周期汇总
1.Vue 的生命周期
-
vue实例从创建到销毁的过程就是生命周期。
beforeCreate
和created
beforeMount
和mounted
beforeUpdate
和updated
beforeDestory
和destoryed
-
beforeCreate :初始化了部分参数,如果有相同的参数,做了参数合并,执行 beforeCreate ;
-
created :初始化了 Inject 、Provide 、 props 、methods 、data 、computed 和 watch,执行 created ;
-
beforeMount :检查是否存在 el 属性,存在的话进行渲染 dom 操作,执行 beforeMount ;
-
mounted :实例化 Watcher ,渲染 dom,执行 mounted ;
-
beforeUpdate :在渲染 dom 后,执行了 mounted 钩子后,在数据更新的时候,执行 beforeUpdate ;
-
updated :检查当前的 watcher 列表中,是否存在当前要更新数据的 watcher ,如果存在就执行 updated ;
-
beforeDestroy :检查是否已经被卸载,如果已经被卸载,就直接 return 出去,否则执行 beforeDestroy ;
-
destroyed :把所有有关自己痕迹的地方,都给删除掉;
-
activated: keep-alive组件激活时调用。
2.异步请求适合在哪个生命周期调用?
- 官方实例的异步请求是在mounted生命周期中调用的,而实际上也可以在created生命周期中调用。
3.第一次页面加载会触发哪几个钩子
- 第一次加载会触发beforeCreate、created、 beforeMount、 mounted。
4.DOM渲染在哪个周期中就已经完成
- DOM 渲染在
mounted
中就已经完成了。
八、为什么避免 v-if 和 v-for 用在一起
- 由于v-for的优先级比v-if高,所以导致每循环一次就会去v-if一次,而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。
- 解决办法:在v-for的外层或内层包裹一个元素来使用v-if
九、axios和ajax的区别
- 区别 axios是通过promise实现对ajax技术的一种封装,就像jQuery实现ajax封装一样。 简单来说: ajax技术实现了网页的局部数据刷新,axios实现了对ajax的封装。 axios是ajax ajax不止axios。
十、vue路由传参数
- 使用
query
方法传入的参数使用this.$route.query
接受 - 使用
params
方式传入的参数使用this.$route.params
接受
十一、v-for key的作用
- 当Vue用 v-for 正在更新已渲染过的元素列表是,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue将不是移动DOM元素来匹配数据项的改变,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。key属性的类型只能为 string或者number类型。
- key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
十二、axios的特点有哪些?
1、axios是一个基于promise的HTTP库,支持promise的所有API;
2、它可以拦截请求和响应;
3、它可以转换请求数据和响应数据,并对响应回来的内容自动转换为json类型的数据;
4、它安全性更高,客户端支持防御XSRF;
十三、Vuex 有哪几种属性?
- state:基本数据
- getters:从基本数据派生的数据
- mutations:提交更改数据的方法,同步
- actions:像一个装饰器,包裹 mutations,使之可以异步
- modules:模块化 Vuex
十四、vue-cli 工程中常用的 npm 命令有哪些?
- npm install:下载 node_modules 资源包的命令
- npm run dev:启动 vue-cli 开发环境的 npm 命令
- npm run build:vue-cli 生成生产环境部署资源的 npm 命令
十五、Vue 打包命令是什么?Vue 打包后会生成哪些文件?
- npm run build :Vue 打包命令
- Vue 打包后会在当前工作目录下生成一个 dist 文件夹,文件夹中会有 static 静态文件以及 index.html 初始页面
十六、Vue 如何优化首屏加载速度?
- 异步路由加载
- 不打包库文件
- 关闭 sourcemap
- 开启 gzip 压缩
十七、vue父子组件之间的传值方式
1.父组件给子组件传值
a.子组件写法
b.父子件写法
注意
:如果想传递动态值:
父组件给子组件传值小结:
- 子组件在props中创建一个属性,用以接收父组件传过来的值
- 父组件中注册子组件
- 在子组件标签中添加子组件props中创建的属性
- 把需要传给子组件的值赋给该属性
2.子组件向父组件传值
a.子组件
b.父组件
子组件向父组件传值小结:
- 子组件中需要以某种方式例如点击事件的方法来触发一个自定义事件
- 将需要传的值作为$emit的第二个参数,该值将作为实参传给响应自定义事件的方法
- 在父组件中注册子组件并在子组件标签上绑定对自定义事件的监听
- 在通信中,无论是子组件向父组件传值还是父组件向子组件传值,他们都有一个共同点就是有中间介质,子向父的介质是自定义事件,父向子的介质是props中的属性。抓准这两点对于父子通信就好理解了
十八、 v-show和v-if指令的共同点和不同点
- v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏;
- v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果;
- 使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。
十九、谈一下你对MVVM原理的理解
二十、Vue-Router有两种传参方式
- 通过在router.js文件中配置path的地方动态传递参数 eg: path: ‘/detail/:id’ 然后在组件内通过this.$route.params.id即可获取
- 在router-link标签中传递参数
<router-link :to={
params: {
x: 1
}
} />
注意:这里通过router-link传递参数的方式是隐式传参
二十一、Vue-Router 跳转方式
1. this.$router.push
//跳转到不同的url,但这个方法会向history栈添加一个记录,点击后退会返回到上一个页面。
this.$router.push({path: '/home/sort/detail',query:{id: 'abc'}})
//获取参数 {{this.$route.query.userId}}
//this.$router.push({name: 'detail',params:{id: 'abc'}})
获取参数:{{this.$route.params.userId}}
2.query和params 的区别
- query要name和path都可以引入,params要用name来引入;query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
3. this.$router.replace
- 同样是跳转到指定的url,但是这个方法不会向history里面添加新的记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的。
4. this.$router.go
- 相对于当前页面向前或向后跳转多少个页面,类似 window.history.go(n)。n可为正数可为负数。正数返回上一个页面
5. router-link标签使用
-
- 根据路由路径(/home/sort/detail)跳转
<router-link :to="{path: '/home/sort/detail', query:{id: 'abc'}}">
点击查看子页面</router-link>
- 根据路由路径(/home/sort/detail)跳转
-
- 根据路由名称(detail)跳转
<router-link :to="{name: 'detail', params:{id: 'abc'}}">
点击查看子页面</router-link> :to=""
可以实现绑定动态的路由和参数
- 根据路由名称(detail)跳转
二十二、 Vue 中 v-html 会导致什么问题
- 在网站上动态渲染任意 HTML,很容易导致 XSS 攻击。所以只能在可信内容上使用 v-html,且永远不能用于用户提交的内容上。
JS
一、创建对象有几种方法
方式一:字面量
var obj11 = {name: ‘qianguyihao’};
var obj12 = new Object(name: ‘qianguyihao’); //内置对象(内置的构造函数)
上面的两种写法,效果是一样的。因为,第一种写法,obj11会指向Object。
第一种写法是:字面量的方式。
第二种写法是:内置的构造函数
方式二:通过构造函数
var M = function (name) {
this.name = name;
}
var obj3 = new M(‘smyhvae’);
方法三:Object.create
var p = {name:‘smyhvae’};
var obj3 = Object.create§; //此方法创建的对象,是用原型链连接的
第三种方法,很少有人能说出来。这种方式里,obj3是实例,p是obj3的原型(name是p原型里的属性),构造函数是Objecet 。
二、继承的几种方式
方式一:借助构造函数
function Parent1() {
this.name = 'parent1 的属性';
}
function Child1() {
Parent1.call(this); //【重要】此处用 call 或 apply 都行:改变 this 的指向
this.type = 'child1 的属性';
}
console.log(new Child1);
方法二:通过原型链实现继承
/*
通过原型链实现继承
*/
function Parent() {
this.name = 'Parent 的属性';
}
function Child() {
this.type = 'Child 的属性';
}
Child.prototype = new Parent(); //【重要】
console.log(new Child());
组合的方式:构造函数 + 原型链
/*
组合方式实现继承:构造函数、原型链
*/
function Parent3() {
this.name = 'Parent 的属性';
this.arr = [1, 2, 3];
}
function Child3() {
Parent3.call(this); //【重要1】执行 parent方法
this.type = 'Child 的属性';
}
Child3.prototype = new Parent3(); //【重要2】第二次执行parent方法
var child = new Child3();
三、sort中升序还是降序的问题
//根据return为1的判断条件决定,按下面的例子来说,意味着a>b的时候换位,就是将大的数字换到后面,所以就是升序排序。
function compare(a, b) {
if (a < b ) { // 按某种排序标准进行比较, a 小于 b
return -1;
}
if (a > b ) {
return 1;
}
// a must be equal to b
return 0;
}
四、伪数组转化为真数组
slice()
// 方式1
array = Array.prototype.slice.call(arrayLike);
// 方式2
array = [].slice.call(arrayLike);
ES6
array = Array.from(arrayLike);
……