vue面试题总结

tech2025-04-28  6

v-model

v-model用于表单数据的双向绑定的语法糖,这个背后就做了两个操作:

1. v-bind: 响应式地绑定一个data属性

2. v-on:给当前元素绑定事件

说一下vue2.x中如何监测数组变化

针对数组的变化,Object.defineProperty 不能很好的支持,所以在Vue 中,采取了函数劫持的方法,data.__proto__本来是指向Array.prototype所指对象的,现在改变它的this指向,将data中的数组的原型指向了自己定义的方法。这样当调用数组push,splice,unshift等api时,对新添加的数据进行监控,可以更新依赖。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控。这样就实现了监测数组变化。 由于原来的方法不能正常对数组进行数据劫持,所以我们要对data的数据类型进行区分,所以我们需要改写Observer类:

class Observer { constructor(data) { // data === vm._data // 将用户的数据使用 Object.defineProperty重新定义 if (Array.isArray(data)) { // 对数组方法进行劫持, 让数组通过链来查找我们自己改写的原型方法 data.__proto__ = arrayMethods; } else { this.walk(data); } } // ... }

通过使用data.__proto__将数组原型上的方法换成我们改写的原型方法 arrayMethods,我们新建一个array.js来重写我们的数组方法。

/** * 拦截用户调用的push、shift、unshift、pop、reverse、sort、splice数组方法,因为这些方法会改变原数组 */ // 获取老的数组方法 let oldArrayProtoMethods = Array.prototype; // 拷贝新的对象,用来查找老的方法, 不修改原型上的方法 export let arrayMethods = Object.create(oldArrayProtoMethods); let methods = [ 'push', 'pop', 'unshift', 'shift', 'sort', 'splice' ]; methods.forEach(method => { arrayMethods[method] = function(...args) { // 函数劫持 let result = oldArrayProtoMethods[method].apply(this, args); console.log('调用数组更新方法'); let inserted; + switch (method) { + case 'push': + case 'unshift': + inserted = args; + break; + case 'splice': + inserted = args.slice(2); // 获取splice(start, deleteCount, [])新增的内容 + default: + break; + } + if(inserted) observerArray(inserted); //对新增加的元素进行监测 return result; return result; } });

其中observerArray()

+export function observerArray(inserted) { + for (let i = 0; i < inserted.length; i++){ + observe(inserted[i]); // 对数组里面的内容递归进行深度观测 + } +}

其中observe()

export function observe(data) { + let isObj = isObject(data); + if(!isObj){ return } return new Observer(data) +}

created与mounted的区别?

created阶段的ajax请求与mounted请求的区别:前者还未进行模板编译、挂载等,页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态。 请求接口一般放在mounted中,但服务端渲染不支持mounted,需要放在created中 你在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。原因是什么呢,原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。

vue的生命周期

初始化组件时,仅执行了beforeCreate/Created/beforeMount/mounted四个钩子函数 当改变data中定义的变量(响应式变量)时,会执行beforeUpdate/updated钩子函数 当切换组件(当前组件未缓存)时,会执行beforeDestory/destroyed钩子函数 初始化和销毁时的生命钩子函数均只会执行一次,beforeUpdate/updated可多次执行

computed与watch的区别

computed:

computed支持缓存,dom更新之后不会重新计算,依赖的数据发生变化后,标记为dirty,用到的时候重新进行计算并缓存。不支持异步操作 watch:不支持缓存,数据变化,会执行操作支持异步操作 data:{ user:{ name:xiaoming } } watch:{ 'user.name':function(){ console.log('name变了') } }

什么是路由?前端路由中hash与history模式

路由是一种映射关系,根据不同的url地址来显示不同的页面或内容的功能。 hash 模式: · #后面 hash 值的变化,不会导致浏览器向服务器发出请求,浏览器不发出请求,就不会刷新页面 · 通过监听 hashchange 事件可以知道 hash 发生了哪些变化,然后根据 hash 变化来更新页面。 history 模式: history 模式的实现,主要是 HTML5 标准发布的两个 API,pushState 和 replaceState,这两个 API 可以在改变 url,但是不会发送请求。这样就可以监听 url 变化来实现更新页面。 区别 · url 展示上,hash 模式有“#”,history 模式没有 · 刷新页面时,浏览器向服务端发送请求,只会把#前的链接发送给服务端。History模式请求服务器的时候发送一整条url, 如果服务器不认识 就会报错404,所以需要后端同学配合一下。 · 兼容性,hash 可以支持低版本浏览器和 IE。

链接:路由懒加载是否放弃了前端路由不刷新页面的加载方式 后端路由:

浏览器向服务器发出请求。服务器监听到80端口,如果有请求过来,那么就解析url地址。服务器根据客户端的路由配置,然后就返回相应的信息(比如html字符串、json数据或图片等)。浏览器根据数据包的 Content-Type来决定如何解析数据

后端路由有一个很大的缺点就是每次路由切换的时候都需要去刷新页面,然后发出ajax请求,然后将请求数据返回回来,那么这样每次路由切换都要刷新页面对于用户体验来说就不好了。因此为了提升用户体验,我们前端路由就这样产生了。前端路由不需要刷新页面。 url中的#号有两种情况,一个是上面说的路由,一个是锚点 锚点就是改变#后面的值,让页面滚动到某个位置,因此也就不会刷新页面。这里的#和css里面的#是一个意思,它可以使对应的id元素显示在可视区域内。

function hashAndUpdate () { // todo 匹配 hash 做 dom 更新操作 } window.addEventListener('hashchange', hashAndUpdate); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>伪锚点</title> <style> #anchor1, #anchor2{width:100px;height:100px;margin-top:2000px;margin-bottom:2000px;} #anchor1{background:red;} #anchor2{background:green;} </style> </head> <body> <p> <a href="#anchor1">锚点1</a> </p> <p> <a href="#anchor2">锚点2</a> </p> <div id="anchor1" > 锚点1 </div> <div id="anchor2" > 锚点2 </div> </body> </html>

data为什么是函数

不要较真了,看了好多文章,源码也没懂,就简单点吧! 当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

最新回复(0)