vue--面试题第一部分

核心


什么是MVVM?

model-view-viewModel(MVVM) 是一个软件架构设计模式,能够实现前端开发和后端业务逻辑的分离,其中 model 指数据模型,负责后端业务逻辑处理,view 指视图层,负责前端整个用户界面的实现,viewModel 则负责 view层 和 model层 的交互。

Vue 的双向数据绑定原理是什么?

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的 settergetter ,在数据变动时发布消息给订阅者,触发相应的监听回调。

$nextTick 是什么?

$nextTick 是 Vue.js 中的一个核心方法,用于在下次 DOM 更新循环结束之后执行延迟回调 。它确保代码在 DOM 更新后执行,常用于操作更新后的 DOM 或依赖 DOM 状态的逻辑。
使用场景

javascript 复制代码
// 1. 操作更新后的 DOM
//   修改数据后立即操作 DOM 可能无法获取最新状态,`$nextTick` 可确保 DOM 已更新。
this.message = '更新后的值';
this.$nextTick(() => {
  console.log(document.getElementById('text').innerHTML); // 获取更新后的 DOM 内容
});

//  2. 依赖 DOM 的第三方库初始化 
//    某些库(如图表库)需要在 DOM 渲染完成后初始化。
this.dataLoaded = true;
this.$nextTick(() => {
  new Chart(document.getElementById('chart'), options);
});

实现原理
$nextTick 利用了 JavaScript 的事件循环机制。Vue 将回调函数推入一个队列,在当前的同步任务和 DOM 更新完成后异步执行。默认优先使用微任务(如 Promise),降级到宏任务(如 setTimeout)。

setTimeout 的区别

特性 $nextTick setTimeout
执行时机 DOM 更新后立即执行 延迟固定时间后执行
优先级 微任务优先 宏任务
与 Vue 生命周期关联 确保在下次渲染周期前完成 无关

Vue 3.0 使用 Proxy API 替代 defineProperty 的原因

  • 性能优化
    • Proxy API 直接代理整个对象,无需递归遍历对象属性进行劫持。defineProperty 需要对每个属性单独设置 getter/setter,初始化时性能开销较大。
    • Proxy 的拦截操作在运行时动态处理,defineProperty 需要在初始化阶段静态定义所有响应式属性。
  • 完整对象监听
    • Proxy 可以检测到对象属性的新增、删除操作,而 defineProperty 只能监听已存在的属性变化。对于动态添加的属性,defineProperty 需要额外调用 Vue.set 方法。
    • Proxy 支持对数组变化的全面监听,包括 push/pop/shift/unshift 等原生方法操作。defineProperty 需要重写数组原型方法实现类似功能。
  • 代码简化
    • Proxy 提供统一的拦截器(handler)处理各种操作,包括 get/set/deleteProperty 等。defineProperty 需要为每个属性单独编写 getter/setter 逻辑。
    • Proxy 支持对嵌套对象的自动代理,defineProperty 需要手动处理嵌套结构的响应式转换。
  • 功能扩展
    • Proxy 可以拦截更多操作类型,如 in 操作符、Object.keys() 等。defineProperty 仅限于属性读写操作的拦截。
    • Proxy 支持对 ES6+ 特性(如 Map、Set)的代理,defineProperty 主要针对普通对象设计。

示例对比

javascript 复制代码
// defineProperty 实现
const obj = {}
Object.defineProperty(obj, 'foo', {
  get() {
    console.log('get foo')
    return this._foo
  },
  set(val) {
    console.log('set foo')
    this._foo = val
  }
})

// Proxy 实现
const handler = {
  get(target, key) {
    console.log(`get ${key}`)
    return target[key]
  },
  set(target, key, value) {
    console.log(`set ${key}`)
    target[key] = value
    return true
  }
}
const proxy = new Proxy({}, handler)

这种改进使 Vue 3.0 的响应式系统更高效、功能更全面,同时减少了框架内部的复杂性。

watch、method、computed 的区别?

watch
watch 用于观察和响应 Vue 实例上的数据变化。适用于需要在数据变化时执行异步或开销较大的操作。

  • 特性:

    • 监听特定的数据属性,当属性变化时触发回调函数。
    • 支持深度监听(deep: true)和立即执行(immediate: true)。
    • 适合处理异步任务或复杂逻辑。
  • 示例

    javascript 复制代码
    watch: {
      someProperty(newVal, oldVal) {
        // 数据变化时执行的操作
      }
    }

method
method 是 Vue 实例中定义的方法,通过调用执行逻辑。适用于需要手动触发的操作。

  • 特性:

    • 通过事件绑定或直接调用触发。
    • 每次调用都会重新执行函数体。
    • 适合处理用户交互或需要灵活调用的逻辑。
  • 示例:

    javascript 复制代码
    methods: {
      doSomething() {
        // 执行某些操作
      }
    }

computed
computed 是计算属性,基于依赖的响应式数据动态计算值。适用于需要缓存结果的场景。

  • 特性:

    • 依赖的数据变化时自动重新计算,否则返回缓存值。
    • 必须返回一个值,适合模板中频繁使用的复杂逻辑。
    • 不支持异步操作。
  • 示例:

    javascript 复制代码
    computed: {
      fullName() {
        return this.firstName + ' ' + this.lastName;
      }
    }

核心区别

  • 缓存computed 缓存结果,依赖不变时直接返回缓存;method 每次调用重新计算;watch 无缓存。
  • 用途computed 用于派生数据;method 用于事件或主动调用;watch 用于响应数据变化执行副作用。
  • 异步支持watch 支持异步;computedmethod 通常不推荐异步操作。

选择建议

  • 需要派生数据且依赖其他响应式数据时,用 computed
  • 需要主动触发或传递参数时,用 method
  • 需要在数据变化时执行异步或复杂逻辑时,用 watch

生命周期


说说Vue的生命周期,什么时候被调用?

阶段 钩子函数 说明
创建阶段 beforeCreate 在实例初始化之后调用,此时 data、methods 等选项尚未初始化,无法访问数据或方法。
created 实例创建完成,data 和 methods 已初始化,可访问数据并调用方法。但 DOM 未挂载,无法操作 DOM 元素。
挂载阶段 beforeMount 在挂载开始之前调用,此时模板编译完成,但尚未将虚拟 DOM 渲染为真实 DOM。
mounted 实例挂载到 DOM 后调用,可操作 DOM 元素。通常用于发起异步请求或初始化第三方库。
更新阶段 beforeUpdate 数据变化触发虚拟 DOM 重新渲染之前调用,此时可获取更新前的 DOM 状态。
updated 虚拟 DOM 重新渲染并应用更新后调用,此时可操作更新后的 DOM。避免在此钩子中修改数据,可能导致无限循环。
销毁阶段 beforeDestroy 实例销毁之前调用,此时实例仍完全可用。适合清理定时器、取消事件监听等操作。
destroyed 实例销毁后调用,所有绑定和监听被移除,子实例也被销毁。
其他 activated 用于 <keep-alive> 缓存的组件,在组件激活时触发。
deactivated 用于 <keep-alive> 缓存的组件,在组件停用时触发。

什么阶段(生命周期)才能访问操作DOM? 为什么

在钩子函数 mounted() 中才能开始访问操作dom,因为 mounted() 生命周期前,dom刚好渲染好,但还未挂载到页面,如果在这之前进行dom操作,将找不到dom节点。

路由


$route$router 的区别?

$route$router 是 Vue Router 提供的两个核心对象,它们在路由管理中扮演不同的角色。
$route 是一个当前激活的路由信息对象,包含以下关键属性:

  • path:当前路由的路径(如 /user/1)。
  • params:动态路由参数(如 { id: '1' })。
  • query:URL 查询参数(如 ?name=foo 解析为 { name: 'foo' })。
  • hash:URL 的哈希值(如 #section)。
  • fullPath:完整 URL(如 /user/1?name=foo#section)。
  • matched:匹配的路由配置数组(包含嵌套路由信息)。
  • meta:路由元信息(如权限标识)。

$router 是 Vue Router 的实例,提供路由操作方法:

  • push(location):导航到新路由(记录历史栈)。
  • replace(location):替换当前路由(不记录历史)。
  • go(n):在历史栈中前进/后退(如 go(-1) 返回上一页)。
  • back():等同于 go(-1)
  • forward():等同于 go(1)
  • resolve(location):解析目标路由的完整信息。
$route $router
功能差异 $route 是只读的路由信息对象,用于获取当前路由状态。 $router 是路由操作实例,用于主动控制导航。
使用场景 需要读取参数或监听路由变化时使用 $route 需要编程式导航(如跳转、返回)时使用 $router

关系: $router 修改路由后,$route 会自动更新反映最新状态。例如调用 push() 后,$route.path 会同步变化。
注意事项: 避免直接修改 $route 的属性(如 $route.query = {}),应通过 $router 的方法更新。 路由守卫(如 beforeEach)中通过 tofrom 参数访问 $route 信息。

路由导航守卫有哪些?

类型 名称 说明
全局 全局前置守卫(beforeEach) 在路由跳转前触发,常用于权限验证或登录状态检查。接收tofromnext参数,需调用next()才能继续导航。
全局解析守卫(beforeResolve) 在导航被确认前触发,适合处理需要等待异步操作完成的场景(如数据预加载)。同样接收tofromnext参数。
全局后置钩子(afterEach) 在导航完成后触发,无next参数。常用于页面统计或日志记录,不影响导航结果。
独享 路由独享守卫(beforeEnter) 在路由配置中单独定义,仅对特定路由生效。用法与全局前置守卫类似,适用于某个路由的特定逻辑(如动态权限校验)。
组件内 beforeRouteEnter 在组件渲染前调用,此时组件实例未创建。可通过next(vm => {})访问实例。
beforeRouteUpdate 当前路由改变但组件复用时触发(如动态参数变化)。可访问组件实例this
beforeRouteLeave 在离开当前路由前触发,常用于阻止用户未保存离开(如表单填写)。需调用next()next(false)

执行顺序示例

  1. 导航触发 → 调用失活组件的beforeRouteLeave
  2. 调用全局beforeEach
  3. 调用复用的beforeRouteUpdate(如存在)
  4. 调用目标路由的beforeEnter
  5. 解析异步路由组件
  6. 调用目标组件的beforeRouteEnter
  7. 调用全局beforeResolve
  8. 导航确认 → 调用全局afterEach

代码示例

javascript 复制代码
// 全局前置守卫
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isAuthenticated()) next('/login')
  else next()
})

// 路由独享守卫
const routes = [
  {
    path: '/admin',
    component: AdminPanel,
    beforeEnter: (to, from, next) => {
      checkAdminRole() ? next() : next('/403')
    }
  }
]

// 组件内守卫
export default {
  beforeRouteLeave(to, from, next) {
    if (this.hasUnsavedChanges) {
      confirm('未保存更改,确定离开?') ? next() : next(false)
    } else next()
  }
}

指令


v-if 与 v-show 的区别?

相同点: v-show 和 v-if 都能控制元素的显示和隐藏。
不同点:

  1. 实现本质方法不同:v-show 本质就是通过设置 css 中的 display 设置为 none 来控制隐藏。而 v-if 是动态的向 DOM 树内添加或者删除 DOM 元素;
  2. 编译不同: v-show 都会编译,初始值为 false,只是将 display 设置为 none, 但它也编译了; v-if 初始值为 false 时,就不会被编译。
    总结: v-show 只编译一次,后面其实就是控制 css, 而 v-if 不停的销毁和创建,如果要频繁切换某节点时,v-show 性能更好一点。

Vuex


Vuex有哪些属性?

核心属性 说明
state 存储应用状态数据,所有组件共享的单一状态树。通过 this.$store.state 访问。
getters 计算派生状态,类似组件的计算属性。通过 this.$store.getters 调用。支持传递参数和嵌套访问其他 getter。
mutations 唯一修改 state 的方法,必须是同步函数。通过 commit 触发,例如 this.$store.commit('mutationName', payload)
actions 处理异步操作或复杂逻辑,通过 dispatch 触发。可调用多个 mutation,例如 this.$store.dispatch('actionName', payload)
modules 将 store 分割成模块,每个模块拥有独立的 state、getters、mutations 和 actions。通过 namespaced: true 启用命名空间隔离。

Vuex 和 localStorage 的区别?

Vuex 是 Vue.js 的官方状态管理库,专为 Vue 应用程序设计,用于集中管理组件间的共享状态。
localStorage 是浏览器提供的 Web Storage API,用于在客户端持久化存储数据。

  • Vuex 是内存中的响应式状态管理工具,适合短期、动态数据。
  • localStorage 是持久化存储方案,适合长期、静态数据。
  • 实际项目中可结合使用,例如用 Vuex 管理运行时状态,用 localStorage 持久化部分状态。

以下是两者的主要区别:

特性 Vuex localStorage
数据存储位置与生命周期 * 数据存储在内存中,仅在当前页面会话期间有效。 * 刷新页面或关闭浏览器后数据丢失。 * 适合管理动态的、临时的应用状态(如用户界面状态、表单数据)。 * 数据存储在浏览器本地,即使关闭浏览器或重启设备也会保留。 * 需手动清除(通过代码或浏览器设置)才会失效。 * 适合持久化存储(如用户偏好设置、登录令牌)。
数据访问与响应性 * 数据是响应式的,状态变化会自动触发视图更新。 * 通过 commitdispatch 修改状态,确保可追踪性。 * 支持模块化和插件扩展(如时间旅行调试)。 * 数据非响应式,需手动监听或触发更新(如通过 window.addEventListener('storage', callback))。 * 直接通过 setItemgetItem 操作,无状态管理机制。 * 存储的数据类型仅限于字符串,需手动序列化(如 JSON.stringify)。
使用场景 * 组件间共享复杂状态(如购物车、全局弹窗控制)。 * 需要中间件处理异步逻辑(如 API 请求)。 * 需要状态快照或回滚功能。 * 长期保存用户配置(如主题、语言)。 * 离线缓存数据(如草稿、历史记录)。 * 存储简单键值对且无需响应式更新。
性能与安全性 * 内存操作速度快,但频繁大量数据可能影响内存占用。 * 数据仅在当前标签页有效,无法跨标签页共享。 * 读写速度较慢(涉及磁盘 I/O),存储容量较大(通常 5MB)。 * 需注意敏感数据的安全问题(如避免存储未加密的密码)。

Vuex 状态管理

javascript 复制代码
// 定义状态
const store = new Vuex.Store({
  state: { count: 0 },
  mutations: {
    increment(state) { state.count++; }
  }
});

// 组件中触发更新
this.$store.commit('increment');

localStorage 操作

javascript 复制代码
// 存储数据
localStorage.setItem('count', JSON.stringify(10));

// 读取数据
const count = JSON.parse(localStorage.getItem('count'));

其他


GET 和 POST 的区别?

GET 用来获取数据(参数在 URL),POST 用来提交数据(参数在 Body);前者可缓存、可书签、长度有限,后者无大小限制、不在历史中、可传文件。

核心语义区别(HTTP 规范定义)

  • GET :请求获取 指定的资源。不应有其他作用(即幂等、安全)。
  • POST :请求服务器处理所附实体(如表单数据)。通常会产生状态变化(如新建资源)。

技术细节对比

特性 GET POST
数据传输位置 放在 URL 的查询字符串中(?key=value 放在请求体(Body)中
数据长度限制 受 URL 长度限制(浏览器/服务器限制,通常 2K-8K) 无理论限制(由服务器配置决定)
编码类型 仅支持 URL 编码(application/x-www-form-urlencoded 支持多种(multipart/form-data 用于文件,application/json 等)
缓存 可被浏览器/CDN 主动缓存 默认不缓存(除非特殊配置)
历史记录 保留在浏览器历史中 不保留
书签 可以保存为书签 不可以
后退/刷新行为 无害(重新请求页面) 浏览器通常会弹窗提示"重新提交表单"
HTTP 包结构 只有请求行 + 头部(没有 Body) 有请求行 + 头部 + Body

常见误区澄清

  1. "POST 比 GET 安全" 说法不准确。两者都是明文传输(HTTP 下)。HTTPS 中两者均加密。区别仅在于:GET 的 URL 会留在浏览器历史、服务器日志中(可能泄露敏感数据);POST 参数不在 URL 中,相对少一处暴露点。 更准确的说法:GET 请求应避免传递密码等敏感信息。
  2. "POST 传输数据量远大于 GET" 说法不准确。POST 本身无大小限制,限制来自服务器(如 nginx client_max_body_size)或 PHP 配置。但现代 API 中,POST 传几 MB 很正常;而 GET 受 URL 长度限制,不适合大体积数据。
  3. "POST 不能缓存" 说法不完全正确。通过设置 Cache-ControlExpires 头,POST 响应也可被缓存,但极少这么用(违背语义)。

实际开发中的选择原则

场景 推荐方法
查询数据、搜索、分页列表、获取详情 GET(可缓存、可分享链接)
登录、提交订单、发帖、上传文件、新增数据 POST(有副作用、数据量大或敏感)
删除资源 通常用 DELETE(RESTful)
更新整个资源 PUT
局部更新 PATCH

基本概念

Cookie 是存储在用户浏览器中的小型文本文件,用于保存用户信息。每次请求时,浏览器会自动将 Cookie 发送到服务器。

Session 是服务器端存储的用户会话数据,通常通过唯一的 Session ID 标识。Session ID 可能通过 Cookie 或 URL 传递给服务器。

特性 Cookie Session
存储位置差异 Cookie 数据存储在客户端浏览器中,用户可以直接查看或修改。 Session 数据存储在服务器端,用户无法直接访问。
安全性对比 Cookie 由于存储在客户端,可能存在安全风险,如被窃取或篡改。 Session 存储在服务器端,安全性较高,但需注意 Session ID 的传输安全。
生命周期管理 Cookie 可以设置过期时间,即使关闭浏览器也可能保留。 Session 通常依赖于会话活动,浏览器关闭后可能失效(取决于服务器配置)。
数据容量限制 单个 Cookie 大小通常限制为 4KB 左右,浏览器对域名下的 Cookie 数量也有限制。 Session 存储在服务器端,理论上容量更大,但需考虑服务器资源。
使用场景选择 Cookie 适合存储不敏感的小型数据,如用户偏好设置。 Session 适合存储敏感或临时数据,如登录状态、购物车信息。
性能影响 Cookie 每次请求都会发送,可能增加网络流量。 Session 数据存储在服务器,可能增加服务器内存负担,需合理管理。
相关推荐
nibabaoo2 小时前
前端开发攻略---H5页面手机获取摄像头权限回显出画面并且同步到PC页面
javascript·websocket·实时音视频·实时同步·录制
早起傻一天~G2 小时前
vue2+element-UI表格封装
javascript·vue.js·ui
这儿有一堆花2 小时前
深入解析 Video.js:现代 Web 视频播放的工程实践
前端·javascript·音视频
烤麻辣烫3 小时前
JS基础
开发语言·前端·javascript·学习
IT_陈寒3 小时前
Vue的响应式把我坑惨了,原来问题出在这
前端·人工智能·后端
2603_953527993 小时前
WordPress Finale Lite 插件高危漏洞检测与利用工具 (CVE-2024-30485)
前端·python·安全·web3·xss
2601_949818094 小时前
头歌答案--爬虫实战
java·前端·爬虫
猫猫不是喵喵.4 小时前
layui表单项次大数据量导入并提交
前端·javascript·layui