Vue 常见面试题汇总

举报
一览芳华 发表于 2021/12/27 19:33:04 2021/12/27
【摘要】 Vue 的优缺点优点1、创建单页面应用的轻量级Web应用框架2、简单易用3、双向数据绑定4、组件化的思想5、虚拟DOM6、数据驱动视图7、前后端分离缺点1、Vue在开发多页应时不够灵活,需要配置多入口2、不支持IE8SPA的理解SPA是 Single-Page-Application 的缩写,翻译过来就是单页应用。在WEB页面初始化时一同加载Html、Javascript、Css。一旦页面加...

Vue 的优缺点
优点

1、创建单页面应用的轻量级Web应用框架

2、简单易用

3、双向数据绑定

4、组件化的思想

5、虚拟DOM

6、数据驱动视图

7、前后端分离

缺点

1、Vue在开发多页应时不够灵活,需要配置多入口

2、不支持IE8

SPA的理解
SPA是 Single-Page-Application 的缩写,翻译过来就是单页应用。在WEB页面初始化时一同加载Html、Javascript、Css。一旦页面加载完成,SPA不会因为用户操作而进行页面重新加载或跳转,取而代之的是利用路由机制实现Html内容的变换。

优点

1、良好的用户体验,内容更改无需重载页面

2、SPA相对服务端压力更小

3、前后端职责分离,架构清晰

缺点

1、由于前端渲染,搜索引擎不会解析JS,只能抓取首页未渲染的模板,不利于SEO

2、单页面应用,在加载页面的时候将JavaScript、CSS统一加载,所以首次加载耗时更多

3、单页面应用需在一个页面显示所有的内容,默认不支持浏览器的前进后退(前端路由机制解决了该窘境,Hash模式中Hash变化会被浏览器记录,History模式利用 H5 新增的pushState和replaceState方法可改变浏览器历史记录栈)

MVVM的理解
MVVM是Model-View-ViewModel的缩写。Model 代表数据层,可定义修改数据、编写业务逻辑。View 代表视图层,负责将数据渲染成页面。ViewModel 负责监听数据层数据变化,控制视图层行为交互,简单讲,就是同步数据层和视图层的对象。ViewModel 通过双向绑定把 View 和 Model 层连接起来,且同步工作无需人为干涉,使开发人员只关注业务逻辑,无需频繁操作DOM,不需关注数据状态的同步问题。

对象

遍历对象,通过Object.defineProperty为每个属性添加 getter 和 setter,进行数据劫持。getter 函数用于在数据读取时进行依赖收集,在对应的 dep 中存储所有的 watcher;setter 则是数据更新后通知所有的 watcher 进行更新。

核心源码

function defineReactive(obj, key, val, shallow) {
  // 实例化一个 dep, 一个 key 对应一个 dep
  const dep = new Dep()
 
  // 获取属性描述符
  const getter = property && property.get
  const setter = property && property.set
  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key]
  }
 
  // 通过递归的方式处理 val 为对象的情况,即处理嵌套对象
  let childOb = !shallow && observe(val)
  
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    // 拦截obj.key,进行依赖收集
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      // Dep.target 是当前组件渲染的 watcher
      if (Dep.target) {
        // 将 dep 添加到 watcher 中
        dep.depend()
        if (childOb) {
          // 嵌套对象依赖收集
          childOb.dep.depend()
          // 响应式处理 value 值为数组的情况
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      // 获取旧值
      const value = getter ? getter.call(obj) : val
      // 判断新旧值是否一致
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
 
      if (getter && !setter) return
      // 如果是新值,用新值替换旧值
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      // 新值做响应式处理
      childOb = !shallow && observe(newVal)
      // 当响应式数据更新,依赖通知更新
      dep.notify()
    }
  })
}
数组

用数组增强的方式,覆盖原属性上默认的数组方法,保证在新增或删除数据时,通过 dep 通知所有的 watcher 进行更新。

核心源码

const arrayProto = Array.prototype
// 基于数组原型对象创建一个新的对象
export const arrayMethods = Object.create(arrayProto)
 
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
 
methodsToPatch.forEach(function (method) {
  const original = arrayProto[method]
  // 分别在 arrayMethods 对象上定义7个方法
  def(arrayMethods, method, function mutator (...args) {
    // 先执行原生的方法
    const result = original.apply(this, args)
    const ob = this.__ob__
    let inserted
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    // 针对新增元素进行响应式处理
    if (inserted) ob.observeArray(inserted)
    // 数据无论是新增还是删除都进行派发更新
    ob.dep.notify()
    return result
  })
})

单向数据流的理解
我们经常说 Vue 的双向绑定,其实是在单向绑定的基础上给元素添加 input/change 事件,来动态修改视图。Vue 组件间传递数据仍然是单项的,即父组件传递到子组件。子组件内部可以定义依赖 props 中的值,但无权修改父组件传递的数据,这样做防止子组件意外变更父组件的状态,导致应用数据流向难以理解。

如果在子组件内部直接更改prop,会遇到警告处理。

以下为2种定义依赖props中的值

1、通过 data 定义属性并将 prop 作为初始值

<script>
export default {
  props: ['userName'],
  data() {
    return {
      name: this.userName
    }
  }
}
</script>
2、 用 computed 计算属性去定义依赖 prop 的值

<script>
export default {
  props: ['userName'],
  computed: {
    helloName() {
      return "hello" + this.userName
    }
  }
}
</sciprt>
响应式原理
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

组件中的data为什么是一个函数
数据以函数返回值形式定义,当每复用一次组件,就会返回一份新的data。即给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。对象在栈中存储的都是地址,函数的作用就是属性私有化,保证组件修改自身属性时不会影响其他复用组件。

生命周期
生命周期    描述
beforeCreate    vue实例初始化后,数据观测(data observer)和事件配置之前。data、computed、watch、methods都无法访问。
created    vue实例创建完成后立即调用 ,可访问 data、computed、watch、methods。未挂载 DOM,不能访问 、ref。
beforeMount    在 DOM 挂载开始之前调用。
mounted    vue实例被挂载到 DOM。
beforeUpdate    数据更新之前调用,发生在虚拟 DOM 打补丁之前。
updated    数据更新之后调用。
beforeDestroy    实例销毁前调用。
destroyed    实例销毁后调用 。
调用异步请求可在created、beforeMount、mounted生命周期中调用,因为相关数据都已创建。在不涉及到DOM操作时,最好的选择是在created中调用。

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。