常见面试题

  • Vue 如何监控数组
  • defineProperty 真的不能监测数组变化吗?

Vue 是如何追踪数据发生变化

在 Vue 中当我们把一个普通的 JS 对象作为 data 传入 Vue 实例,Vue2.x 对这个数据初始化时将遍历这个对象所有的属性,并使用 JS 的原生特性 Object.defineProperty 把这些属性全部转为 getter\setter。这些 getter\setter 对用户来说是不可见的,他们可以在属性被访问和修改时通知变更。同时每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

Vue 如何更新数组

// 方法一: 使用 Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// 方法二: 使用 Vue 可监测的数组变异方法: Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

为什么有些数组的数据变更不能被 Vue 监测到

简单来说,我们操作数组的一些动作 arr[2] = 'xxx' / arr.length = 2 或者是调用 Array.prototype 上挂载的部分方法并不能触发这个属性的 setter。

在数组的更新中有提到,可以使用 Vue 可监测的数组变异方法: Array.prototype.splice, 哪为什么这个方法可以触发状态的更新了。 这是因为 Vue2.x 将数组的 7 个常用方法 push、pop、shift、unshift、splice、sort、reverse 进行了重写,所以通过调用包装之后的数组方法就能够被 Vue 监测到。

// Vue 2.6.14 
// src/core/observer/array.js
import { def } from '../util/index'
 
// 记录原始 Array 未重写之前的 API 原型方法
const arrayProto = Array.prototype
// 深拷贝一份上面的原型出来
export const arrayMethods = Object.create(arrayProto)
 
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
 
/**
 * Intercept mutating methods and emit events
 * 拦截上边数组中列出的变异方法, 并发出事件通知
 */
methodsToPatch.forEach(function (method) {
  // cache original method
  // 缓存 Array.prototype 中的同名原始方法
  const original = arrayProto[method]
  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 为什么不能通过下标操作数组或者改变数组的长度来触发视图更新

那 Vue2.x 监测数组变更的两条限制:不能监听利用索引直接设置一个数组项,不能监听直接修改数组的长度,是因为 defineProperty 的限制么?

答案:是的

Object.defineProperty 对于数组变化监听的表现与 Vue2.x 还是有不同的,比如 Object.defineProperty 可以监听到通过索引直接修改数组项,当然也不是说 Object.defineProperty 可以完全监听数组的变化,像直接修改数组的长度或者 push\pop 之类的方法还是不能触发 setter 的。

这里就会出现一个新的问题?

为什么 Object.defineProperty 明明能监听到数组值的变化,而 Vue 却没有实现呢?

这是因为 Vue 是对数组元素进行了监听,而没有对数组本身的变化进行监听。

var Observer = function Observer (value) {
    this.value = value;
    this.dep = new Dep();
    this.vmCount = 0;
    def(value, '__ob__', this);
    // 区分对象和数组,对象和数组走不通的响应式方案
    if (Array.isArray(value)) {
      // 判断是否支持__proto__属性,根据不同的请求来添加数组的拦截方法
      if (hasProto) {
        protoAugment(value, arrayMethods);
      } else {
        copyAugment(value, arrayMethods, arrayKeys);
      }
      // 循环数组的元素,再次调用observe方法,
      this.observeArray(value);
    } else {
      // 如果是对象,循环对象属性,为对象属性添加getter,setter方法,将属性变成响应式
      this.walk(value);
    }
  };

这其实是出于性能原因的考量,给每一个数组元素绑定上监听,实际消耗很大而受益并不大

其实还有一些考虑是:对数据的操作更常用的操作数组的方法是使用数组原型上的一些方法如 push、shift 等来操作数组。Object.defineProperty是对象上的方法,用来对数组的下标进行检测,会改变数据本来的性质。

总结来说:三点原因

  • 性能原因的考量
  • 对数据的操作更常用的操作数组的方法是使用数组原型上的一些方法如 push、shift 等来操作数组。
  • Object.defineProperty是对象上的方法,用来对数组的下标进行检测,会改变数据本来的性质。

当然最重要的就是性能问题。

Vue 3.0 是如何处理的?

Vue3 不再采用 defineProperty 的方式来进行监听而是采用 Proxy 的方式。下面我引用了 MDN 上对于 proxy 的介绍: Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。 当异步触发 Model 里的数据变化时,都会经过 Proxy 这一层,在这里则可以监听数组以及各种数据类型的变化,无论是数组下标赋值引起变化还是数组方法引起变化,都可以被监听到,也可以避开监听数组每个属性下造成的性能问题。

参考

  • cn.vuejs.org/v2/guide/re…
  • www.jianshu.com/p/fc8da283c…
  • baijiahao.baidu.com/s?id=163912…
  • blog.csdn.net/XH_jing/art…
  • developer.mozilla.org/zh-CN/docs/…

到此这篇关于Vue  监控数组的示例详解的文章就介绍到这了,更多相关Vue  监控数组内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

关于Vue 监控数组的问题的更多相关文章

  1. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  2. html5使用canvas实现弹幕功能示例

    这篇文章主要介绍了html5使用canvas实现弹幕功能示例的相关资料,需要的朋友可以参考下

  3. 前端实现弹幕效果的方法总结(包含css3和canvas的实现方式)

    这篇文章主要介绍了前端实现弹幕效果的方法总结(包含css3和canvas的实现方式)的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. H5 canvas实现贪吃蛇小游戏

    本篇文章主要介绍了H5 canvas实现贪吃蛇小游戏,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. ios – parse.com用于键,预期字符串的无效类型,但是得到了数组

    我尝试将我的数据保存到parse.com.我已经预先在parse.com上创建了一个名为’SomeClass’的类.它有一个名为’mySpecialColumn’的列,其数据类型为String.这是我尝试使用以下代码保存数据的代码:如果我运行这个我得到:错误:密钥mySpecialColumn的无效类型,预期字符串,但得到数组这就是我在parse.com上的核心外观:有谁知道我为什么会收到这个错误?

  6. ios – 上下文类型’NSFastEnumeration’不能与数组文字一起使用

    斯威夫特3,你会这样做吗?解决方法正如您所发现的,您不能使用as-casting将数组文字的类型指定为NSFastEnumeration.您需要找到一个符合NSFastEnumeration的正确类,在您的情况下它是NSArray.通常写这样的东西:

  7. ios – 获取资产目录文件夹中所有图像的数组

    在iOS中,是否可以获取资产目录文件夹中的图像数组?我不确定为什么会对此进行投票.我真的不知道从哪里开始.我的另一种方法是创建文件夹中所有文件的plist,但它似乎是多余的.我无法添加任何代码,因为我会添加什么?

  8. ios – 来自调试器的消息:由于内存问题而终止

    我的应用程序使用Geojson文件.我使用MapBoxSDK将MGLpolyline添加到地图中.但问题是我的文件太大,以至于应用程序崩溃并收到错误:来自调试器的消息:由于内存问题而终止.我在第一次循环时面对66234个对象.我试图将数组块化为新数组,但没有成功.请帮我解决问题.这是我在地图上绘制的代码,这里是我的testprojectongithubuseXcode8.1如果有任何不同的第三方可

  9. ios – Swift – 使用字典数组从字典访问数据时出错

    我有一个非常简单的例子,说明我想做什么基本上,我有一个字典,其值包含[String:String]字典数组.我把数据填入其中,但当我去访问数据时,我收到此错误:Cannotsubscriptavalueoftype‘[([String:String])]?’withanindexoftype‘Int’请让我知道我做错了什么.解决方法您的常量数组是可选的.订阅字典总是返回一个可选项.你必须打开它.更

  10. ios – 在Swift中使用“Map”创建两个数组的超集

    假设我有两个数组:我想组合两个数组,以便我得到一个输出我该怎么做呢?

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部