Vue内部原理(三)| 小册免费学

简介: JavaScript中Array.prototype上有很多常用的方法,MDN上也给出了介绍,虽然方法众多,但是可以改变数组内容的只有7个(fill和copyWithin处于试验阶段,所以源码中没有适配),分别是:pop、push、shift、unshift、splice、sort、reverse。

1682512692(1).png

JavaScript中Array.prototype上有很多常用的方法,MDN上也给出了介绍,虽然方法众多,但是可以改变数组内容的只有7个(fill和copyWithin处于试验阶段,所以源码中没有适配),分别是:pop、push、shift、unshift、splice、sort、reverse。

这里的主要内容放在代码注释中,能够看得更清楚

Vue处理数组响应式的办法是劫持数组原型方法,将数组元素的原型替换为重写的数组原型方法

const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
// 列举出所有可以改变数组内容的方法名
const methods = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
methods.forEach(function (method) {
  // 原来数组的方法
  const original = arrayProto[method]
  // def工具,为对象设置函数属性
  def(arrayMethods, method, function mutator (...args) {
    // 执行原方法,指定this
    const result = original.apply(this, args)
    // 每个属性都维护一个子的观察者,后面会说到
    const ob = this.__ob__
    let inserted
    // 处理新加入的参数
    switch (method) {
      case 'push':
      case 'unshift':
        // push和unshift都会在这里处理,获取参数,参数也需要做响应式处理
        inserted = args
        break
      case 'splice':
        // splice的新加的参数是从第三位开始的,如arr.splice(2, 1, 'bar')
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted)
    // 通知更新,后面依赖收集会说到
    ob.dep.notify()
    // 将原方法执行的结果返回
    return result
  })
})
// util.js
export function def(obj, key, value, enumerable = false) {
  Object.defineProperty(obj, key, {
    value,
    enumerable,
    writable: true,
    configurable: true
  })
}
复制代码

上面这段代码有点长,来总结一下它的主要功能

  1. 开始先使用Object.create创建一个新的对象,原型是Array.prototype
  2. 然后列举能够改变数组的7个方法,遍历列举出来的数组方法,给创建出来的对象添加函数属性,期间执行原方法获取返回值,如果方法是可以传参的那就要对参数再进行观测,
  3. 然后通知视图更新,最后返回函数的返回值

现在具有响应式功能的数组方法已经重写完了,下一步就是将重写过的数组方法挂载到数组上了,这时候要将之前的Observer稍加改造,对要坚挺的数据进行类型检测,如果是数组元素就将重写的数组方法挂载到原型上

export default class Observer {
  constructor(value) {
    this.value = value
    // 用于维护依赖,后面会说
    this.dep = new Dep()
    def(value, '__ob__', this)
    // 类型检测
    if (Array.isArray(value)) {
      // 使用setPrototypeOf可以将第二个参数作为第一个参数__proto__
      Object.setPrototypeOf(value, arrayMethods)
      this.observeArray(value)
    } else {
      // 之前有observe的过滤,能够到这里的不是数组就是对象
      this.walk(value)
    }
  }
  walk(obj) {
    Object.keys(obj).forEach((key) => defineReactive(obj, key, obj[key]))
  }
  // 将数组元素遍历观察
  observeArray(arr) {
    arr.forEach((i) => observe(i))
  }
}
复制代码

到这里数据观察过程已经基本了解了,但是这里并不是最终版,这里可以在数据发生变化时通过setter来更新视图,但是如果数据并没有被页面引用呢,即便是引用了,任何一个数据变化都会导致页面更新,代价太大了,这就需要我们后面要说的依赖收集了。

相关文章
|
2天前
|
缓存 JavaScript 前端开发
《基础篇第4章:vue2基础》:使用vue脚手架创建项目
《基础篇第4章:vue2基础》:使用vue脚手架创建项目
12 3
|
5天前
|
JavaScript 前端开发 开发者
Vue v-for 进阶指南:in 与 of 的区别及应用场景 | 笔记
Vue.js 中的 v-for 是强大的遍历指令,但其中的 in 和 of 关键字往往被开发者忽视。尽管它们的用法相似,但适用的场景和数据结构却各有不同。本文将详细探讨 v-for 中 in 和 of 的区别、适用场景以及在实际开发中的最佳使用时机。通过理解它们的差异,你将能够编写更加高效、简洁的 Vue.js 代码,灵活应对各种数据结构的遍历需求。
40 6
|
2天前
|
缓存 JavaScript
Vue 中 computed 与 method 的区别
【10月更文挑战第15天】computed 和 method 是 Vue 中两个重要的选项,它们在功能和特点上存在着明显的区别。理解并合理运用它们的区别,可以帮助我们构建更高效、更具可维护性的 Vue 应用。在实际开发中,要根据具体情况灵活选择使用,以满足不同的需求。
5 2
|
2天前
|
JavaScript 搜索推荐 UED
vue的自定义指令
【10月更文挑战第14天】Vue 自定义指令为我们提供了一种强大的工具,使我们能够更灵活地控制和扩展 Vue 应用的行为。通过合理地使用自定义指令,可以提高开发效率,增强应用的功能和用户体验。
|
3天前
|
JavaScript
|
4天前
|
JavaScript UED
Vue + ElementUI 实现动态添加和删除表单项的多层嵌套表单
【10月更文挑战第5天】本示例展示了如何在 Vue.js 中使用 Element UI 组件实现动态添加和删除嵌套表单项。该表单包含设备信息、设备部位及其对应的任务列表,支持用户动态添加设备部位和任务,并提供相应的表单验证规则。
24 0
Vue + ElementUI 实现动态添加和删除表单项的多层嵌套表单
|
5天前
|
JavaScript
《进阶篇第9章》学习vuex知识点后练习:求和案例_纯vue版代码
《进阶篇第9章》学习vuex知识点后练习:求和案例_纯vue版代码
11 1
|
1天前
|
JavaScript 前端开发 Java
vue2知识点:Vue封装的过度与动画
vue2知识点:Vue封装的过度与动画
7 0
|
2天前
|
JavaScript UED
在 Vue 中使用自定义指令
【10月更文挑战第14天】通过合理地使用自定义指令,可以为 Vue 应用带来更多的灵活性和扩展性,提高开发效率和用户体验。
|
3天前
|
JavaScript 前端开发 容器
vue的哈希模式下乾坤微应用的使用
vue的哈希模式下乾坤微应用的使用