目录
四、初中级面试题常见谈谈你对var、let、const的理解
前言
小滴课堂,旨在让编程不在难学,让技术与生活更加有趣。 随着互联网+的时代,在线教育技术越来越便捷,小滴课堂依托在线教育时间以及空间上的便利,为广大IT从业者提供了更为方便、快捷的学习交流途径、提供大量高质量的IT在线课程。更多教程请访问xdclass.net(添加VX:xdclass99)
一、Vue的生命周期详解
回答
(一)每个Vue实例都有⼀个完整的⽣命周期,当⾯试官提到让你谈谈对Vue的生命周期的理解时,如何回答才是⼀个令⼈满意的回答?
1、第⼀个问题:什么是
Vue
的生命周期?
通俗的来说,⼀个
Vue
实例从创建到销毁的这个过程,我们称之为
Vue
的生命周期。
2、整个流程?
(1)开始创建⼀个
Vue
实例
—>
初始化
Vue
实例内部数据
—>
模板开始编译
—>
挂载并渲染dom
(2)—>
更新数据
(
可能有这个过程
) —> Vue
实例开始销毁
—>
实例销毁完毕
(3)整个流程⼤概如上,这个流程⾥,
Vue
实例会触发⼀些钩⼦。谈到这,可能有童鞋会有问,什么是钩⼦?
3、什么是钩⼦?
钩⼦,其实是钩⼦函数的简称,说的简单点,就是
Vue
实例的生命周期里,自动会触发的函数,有的话就执⾏这个函数,这也就是我们常说的钩⼦。
(二)简单的概念和流程到此结束,那么Vue组件的⽣命周期⾥,这些钩⼦触发的时候,到底⼲了什么事情?
1、详解触发钩⼦时已完成的操作及建议的操作
(1)beforeCreate
①实例初始化,将
this
指向
Vue
实例,此时
data computed watch methods
上的方法和数据均不能访问
②可在此处加⼊
loading
事件
(2)created
①实例创建完成,完成数据
(data props computed)
的初始化 ,可访问其中的数据。
②此时未挂载
dom
,也不能访问
Vue
实例中的
$el
属性
③没有
dom
,也就是说
$ref
为空数组了
④可以对
data
数据进⾏操作,可进行⼀些请求,请求不易过多,避免⽩屏时间太⻓。
⑤若在此阶段进⾏的
DOM
操作⼀定要放在
Vue.nextTick()
的回调函数中,
dom
更新的时候,才会触发nextTick里
的回调函数。
⑥也可在此处结束
loading
(3)berofeMount
①此时
$el
挂载完毕,并且把
Vue
实例中
template
部分编译成
render
函数
,
或者直接执行render
函数
②使用
render
函数的结果和我们之前使⽤
template
解析出来的结果是⼀样的。
③render
函数是发⽣在
beforeMount
和
mounted
之间的,这也从侧面说明了,在beforeMount的时候,
$el
还只是我们在
HTML里面
写的节点,然后到
mounted
的时候,它就把渲染出来的内容挂载到了DOM
节点上。这中间的过程其实是执⾏了render函数的内容。
(4)mounted
①完成创建
vm.$el
,
dom
此时已经根据
template
编译的
render
函数,渲染完成
②有了
DOM
且完成了双向绑定 可访问
DOM
节点及
$ref
属性
(5)beforeUpdate(
更新数据时触发
)
数据更新之前,可在更新前访问现有的
DOM,
如⼿动移除添加的事件监听器
(6)updated
①完成虚拟
DOM
的重新渲染
②组件
DOM
已完成更新;
③可执行依赖的
dom
操作
④注意:不要在此函数中操作数据,会陷⼊死循环的。
(7)activated
在使用
vue-router
时,有时我们会使用
keep-alive
标签来保持组件的状态,避免频繁发送请求。此时,created
钩⼦就不会被重复调用了。因此,如果我们需要在组件每次加载的时候进⾏某些操作,可以在activated
这个钩⼦当中触发。
(8)deactivated
被
keep-alive
标签包住的组件,被移除时触发。
(9)beforeDestroy
①实例销毁之前调用。在这⼀步当中,实例仍然完全可用。
②可做⼀些删除提示,比如,
"
您确认离开此页面
"
③可⽤于销毁定时器,解绑全局事件或者销毁引⼊的插件对象
(10)destroyed
Vue
实例销毁后调用。此时
Vue
实例里的数据解除绑定,所有的事件监听器也被移
除了
2、最后丢⼀张官⽹的
Vue生
命周期图解给⼤家巩固下
二、Vue的双向绑定
回答
(一)核心
Object.defifineProperty()方
法
(二)原理
通过Object.defifineProperty()
来劫持各个属性的
setter
,
getter
,在数据发⽣变动时通知Vue
实例,触发相应的
getter
和
setter
回调函数。当把⼀个普通
Javascript
对象传给Vue 实例来作为它的
data
选项时,
Vue
将遍历它的属性,用
Object.defifineProperty
将它们转为 getter/setter
。⽤户看不到
getter/setter
,但是在内部它们让
Vue 追踪依赖,在属性被访问和修改时通知变化。
(三)特点
1、Vue
的数据双向绑定将
MVVM
作为数据绑定的入口,整合
Observer
,
Compile
和Watcher三者,通过
Observer
来监听⾃⼰的
model
的数据变化,通过
Compile
来解析编译模板指令(vue
中是用来解析
{{}}
),最终利用
watcher
搭起
observer
和
Compile
之间的通信桥梁,达到数据变化 —>
视图更新;视图交互变化(
input
)
—>
数据
model
变更双向绑定效果。
2、这就是通过数据劫持和发布
-
订阅者功能来实现的
(四)js的简单实现
<body>
<div id="app">
<input type="text" id="txt">
<p id="show"></p>
</div>
</body>
<script type="text/javascript">
var obj = {}
Object.defineProperty(obj, 'txt', {
get: function () {
return obj
},
set: function (newValue) {
document.getElementById('txt').value = newValue
document.getElementById('show').innerHTML = newValue
}
})
document.addEventListener('keyup', function (e) {
obj.txt = e.target.value
})
</script>
三、Vue中组件间通信有哪几种⽅式
回答
(一)父子组件
1、props/event
子组件有时需要与父组件进行沟通,沟通的方式就是子组件
$emit
传递⼀个自定义事件,父组件通过监听这个事件来做进⼀步动作。而父组件与子组件通信则使用 props
来传递⼀个绑定在子组件上的属性,这个属性值来源于父组件
2、parent/children
(1)父组件中
使用
$children
操作⼦组件。并在父组件通过
$children
访问到已经在在父组件当中引入了的子组件, $children
返回的是子组件列表,是⼀个数组。
(2)子组件中
子组件可通过
$parent
来访问父组件里的数据和定义的方法,如修改父组件中的$data
(3)ref
父组件中可为⼦组件定义⼀个
ref
属性,然后⽗组件⾥通过
$ref[
对象子组件上定义的属性名
]来访问子组件里的数据
(4)provide/inject
适用于祖先和后代关系的组件间的通信,祖先元素通过
provide
提供⼀个值,后代元素则通过 inject
获取到这个值。这个值默认是非响应的,如果是对象那么则是响应式的:
(二)兄弟组件
1、bus
(1)在
Vue . 2.x
中, 推荐使⽤⼀个空的
Vue
实例作为中央事件总线(
bus
),也就是⼀个中介。
(2)通信的组件必须都引⼊这个实例。
(3)通过
bus.$emit()
传递出⼀个⾃定义事件
(4)在需要进⾏操作的组件⾥,通过
bus.$on
监听这个自定义事件
,
进⾏操作
2、Vuex
(1)Vuex
是
Vue
推出的状态管理⼯具
(2)Vuex
就是把需要共享的变量全部存储在⼀个对象⾥⾯,然后将这个对象放在顶层组件中供其
他组件使用。这么说吧,将
vue
想作是⼀个
js文
件、组件是函数,那么
vuex
就是⼀个全局变量,只是这个“
全局变量
”
包含了⼀些特定的规则而已。
(3)通过
$store
这个对象访问数据和调⽤在
Vuex 里
定义的公共⽅法
(三)跨级组件
bus vuex provide inject
四、初中级面试题常见谈谈你对var、let、const的理解
回答
(一)var定义的变量,没有块的概念,可以跨块访问,不能跨函数访问,会造成变量提升
(二)let定义的变量,只能在块作⽤域⾥访问,不能跨块访问,也不能跨函数访问。不会造成变量提升
(三)const⽤来定义常量,使⽤时必须初始化(即必须赋值),只能在块作用域里访问,⽽且不能修改。不会造成变量提升
(四)也可以从另⼀个⻆度简单回答(var是ES6前⽤来定义变量,会造成变量提升。let和const书是ES6才出现的,⼀个⽤来定义变量,⼀个定义常量)
(五)如果上面的回答出来了,⼀般面试官可能会继续深挖
1、你说
const
是⽤来定义常量。使⽤时必须初始化且不能修改,那么下面这段代码运行会造成什么结果
function a () {
const b ={a:2}
b.a = 3
console.log(b)
}
a()
2、由于
const
这个时候定义的是⼀个对象,它的内存地址并没改变,所以这个改变内部的属性是允许的,这段代码可以正常运行。这里主要考察你是否是背答案和对复杂数据类型的操作的理解
3、额外知识点,数据存储
(1)存可以分为栈区和堆区
(2)栈区:⽤来存储用基本类型的数据 和 引用类型数据的地址。
(3)堆区:⽤来存储引用类型数据的数据
五、访问首页的速度很慢,有哪些方法可以提高访问速度?
回答
(一)组件懒加载
1、描述
懒加载也叫做延迟加载、按需加载,在非首屏展示的组件或者数据可以使用懒加载
2、特点
(1)减小接口请求个数,⻚⾯的渲染负担
(2)提高首页的展示速度,提升用户体验
(3)防止加载过多图片而影响其他资源文件的加载
3、实现
(1)通过
import() 方
法引⼊组件
import(./test.js).then(({fun})=>{fun()})
()=>import('./Test')
(2)通过监听用户的滚动事件触发来展示非首屏的图⽚
4、懒加载和预加载的区别
(1)懒加载也叫延迟加载,指的是在网页中延迟加载图片的时机,当用户需要访问时,再去加载,可以提高网站的首屏加载速度,提升用户的体验
(2)预加载指的是将所需的资源提前请求加载到本地,这样后⾯在需要用到时就直接从缓存取资源,通过预加载能够减少用户的等待时间,提高用户的体验
(二)非首屏的内容延时渲染实现(直接上代码)
// 定义⼀个异步的函数,当⽤户滑动时则不延时
const delayMS = (ms) => {
const p = new Promise((resolve) => {
setTimeout(resolve, ms);
});
// 如果⽤户开始滑动,则取消延期
const onTouchPromise = new Promise((resolve) => {
const handler = function () {
window.removeEventListener('touchstart', handler);
resolve();
};
window.addEventListener('touchstart', handler);
});
return Promise.race([p, onTouchPromise]);
};
// 引⽤
delayMS(2000).then(() => {
console.log(333); // 控制⾮⾸屏dom节点的渲染
});