2019 前端面试题 (Vue)
1.谈谈你对MVVM开发模式的理解。
MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。
2.Vue有哪些指令?
v-if v-show v-for v-html 等
3.v-if 和 v-show 有什么区别?
v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。
4.简述Vue的响应式原理
当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。
每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
5.Vue中如何在组件内部实现一个双向数据绑定?
假设有一个输入框组件,用户输入时,同步父组件页面中的数据
具体思路:父组件通过 props 传值给子组件,子组件通过 $emit 来通知父组件修改相应的props值,具体实现如下:
import Vue from 'vue'
const component = {
props: ['value'],
template: `
<div>
<input type="text" @input="handleInput" :value="value">
</div>
`,
data () {
return {
}
},
methods: {
handleInput (e) {
this.$emit('input', e.target.value)
}
}
}
new Vue({
components: {
CompOne: component
},
el: '#root',
template: `
<div>
<comp-one :value1="value" @input="value = arguments[0]"></comp-one>
</div>
`,
data () {
return {
value: '123'
}
}
})
可以看到,当输入数据时,父子组件中的数据是同步改变的:
我们在父组件中做了两件事,一是给子组件传入props,二是监听input事件并同步自己的value属性。那么这两步操作能否再精简一下呢?答案是可以的,你只需要修改父组件:
template: `
<div>
<!--<comp-one :value1="value" @input="value = arguments[0]"></comp-one>-->
<comp-one v-model="value"></comp-one>
</div>
`
v-model 实际上会帮我们完成上面的两步操作。
6.Vue中如何监控某个属性值的变化?
比如现在需要监控data中,obj.a 的变化。Vue中监控对象属性的变化你可以这样:
watch: {
obj: {
handler (newValue, oldValue) {
console.log('obj changed')
},
deep: true
}
}
deep属性表示深层遍历,但是这么写会监控obj的所有属性变化,并不是我们想要的效果,所以做点修改:
watch: {
'obj.a': {
handler (newName, oldName) {
console.log('obj.a changed')
}
}
}
还有一种方法,可以通过computed 来实现,只需要:
computed: {
a1 () {
return this.obj.a
}
}
7.Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?
<template>
<div>
<ul>
<li v-for="value in obj" :key="value">
{{value}}
</li>
</ul>
<button @click="addObjB">添加obj.b</button>
</div>
</template>
<script>
export default {
data () {
return {
obj: {
a: 'obj.a'
}
}
},
methods: {
addObjB () {
this.obj.b = 'obj.b'
console.log(this.obj)
}
}
}
</script>
<style></style>
点击button会发现,obj.b 已经成功添加,但是视图并未刷新:
原因在于在Vue实例创建时,obj.b并未声明,因此就没有被Vue转换为响应式的属性,自然就不会触发视图的更新,这时就需要使用Vue的全局api $set():
addObjB () {
// this.obj.b = 'obj.b'
this.$set(this.obj, 'b', 'obj.b')
console.log(this.obj)
}
$set()方法相当于手动的去把obj.b处理成一个响应式的属性,此时视图也会跟着改变了:
8. delete和Vue.delete删除数组的区别
delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。
Vue.delete直接删除了数组 改变了数组的键值。
var a=[1,2,3,4]
var b=[1,2,3,4]
delete a[1]
console.log(a)
this.$delete(b,1)
console.log(b)
9.如何优化SPA应用的首屏加载速度慢的问题?
- 将公用的JS库通过script标签外部引入,减小app.bundel的大小,让浏览器并行下载资源文件,提高下载速度;
- 在配置 路由时,页面和组件使用懒加载的方式引入,进一步缩小 app.bundel 的体积,在调用某个组件时再加载对应的js文件;
- 加一个首屏 loading 图,提升用户体验;
10. 前端如何优化网站性能?
1. 减少HTTP请求数
一个完整的请求都需要经过DNS存址、与服务器建立连接、发送数据、等待服务器响应、接收数据这样一个漫长而复杂的过程。资源上由于每个请求都要携带数据,因此每个请求都需要占用带宽。另外,由于浏览器进行并发请求的请求数是有上限的,因此请求数多了以后,浏览器需要分批进行请求,因此会增加用户的等待时间,会给用户造成站点速度慢这样一个印象,即使可能用户能看到的第一屏的资源都已经请求完了,但是浏览器的进度条会一直存在。
减少HTTP请求数的主要途径包括:
(1)从设计实现层面简化页面
如果你的页面想百度首页那样简单,那么接下来的规则基本上都用不着了。
(2)合理设置HTTP缓存
缓存可以大大减少第二次访问时的请求数,但是如果是F5刷新的话,请求数一样。
怎样才算合理设置?能缓存越多越好,能缓存越久越好。例如,很少变化的图片资源可以直接通过HTTP Header中的Expires设置一个很长的过期头;变化不频繁而又可能会变的资源可以使用Last-Modified来做请求验证。尽可能的让资源能够在缓存中待得更久。
(3)资源合并与压缩
如果可以的话,尽可能的将外部的脚本、样本进行合并,多个合为一个。另外,CSS、JavaScript、Image都可以用相应的工具进行压缩,压缩后往往能省下不少空间。
(4)CSS Sprites
合并CSS图片,减少请求数的有一个好办法。
(5)Inline Images
使用data:URL scheme的方式将图片嵌入到页面或者CSS中,如果不考虑资源管理上的问题,不失为一个好办法。如果是嵌入页面的话换来的是增大页面的体积,而无法利用浏览器缓存。使用在CSS中的图片更为理想一些。
(6)Lazy Load Images
使页面刚加载的时候只加载第一屏,当用户继续往后滚屏的时候才加载后续的图片。
2. 将css文件放在head头,JS脚本放在页面信息后面
外链脚本会在加载时阻塞其他资源。
3. 异步执行inline脚本(保证脚本在页面内容后面加载)
inline脚本在执行的时候一样会阻塞并发请求。除此之外,由于浏览器在页面处理方面是单线程的,当inline脚本在页面渲染之前执行时,页面的渲染工作则会被推迟。
因此,建议将执行时间较长的inline脚本进行异步执行,例如使用setTimeout或者HTML5中的Web Worker。
4. Lazy Load JavaScript
(1)利用min版JS框架
(2)YUI,最初只加载核心模块,其他模块可以等到需要使用的时候才加载。
5. 将CSS放在Head中
使页面在开始渲染之前先加载css资源
6. 异步请求callback
7. 减少不必要的HTTP挑转
8. 避免重复的资源请求
9. 合并CSS属性值
如border-style: solid;
border-width:1px;
border-color:red;
变成border: 1px solid red;
10. 为文件头指定Expires或者Cache-Control
11.网页从输入网址到渲染完成经历了哪些过程?
大致可以分为如下7步:
- 输入网址;
- 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
- 与web服务器建立TCP连接;
- 浏览器向web服务器发送http请求;
- web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地 址);
- 浏览器下载web服务器返回的数据及解析html源文件;
- 生成DOM树,解析css和js,渲染页面,直至显示完成;
12. jQuery获取的dom对象和原生的dom对象有何区别?
js原生获取的dom是一个对象,jQuery对象就是一个数组对象,其实就是选择出来的元素的数组集合,所以说他们两者是不同的对象类型不等价.
- 原生DOM对象转jQuery对象:
var box = document.getElementById('box');
var $box = $(box);
- jQuery对象转原生DOM对象:
var $box = $('#box');
var box = $box[0];
13. jQuery如何扩展自定义方法
(jQuery.fn.myMethod=function () {
alert('myMethod');
})
// 或者:
(function ($) {
$.fn.extend({
myMethod : function () {
alert('myMethod');
}
})
})(jQuery)
使用:
$("#div").myMethod();
目前来看公司面试的问题还是比较基础的,但是对于某些只追求会用并不研究其原理的同学来说可能就没那么容易了。所以大家不仅要追求学习的广度,更要追求深度。