vue源码笔记:array.js

前端这点事 57 0

在vue中,只有预先在data中定义的属性才能是响应式的属性。如果是新增或者删除,数据改变但是页面却没有改变。

所以在vue中重写了数组中涉及数组项的新增、删除或者位置变化的方法。包括七种,'push','pop','shift','unshift','splice','sort','reverse'。

源码的位置就在src/core/observer/array.js中。下面我们来看一下。

import { def } from '../util/index'

const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)

这里利用Object.creat方法创建一个新对象,而新对象的原型是数组的原型。相当于copy了一份原生数组对象的原型。目的是防止污染原生数组对象的原型。

先来看一个工具函数。作用是定义对象的属性。下面要用到。

/**
 * Define a property.
 */
export function def (obj: Object, key: string, val: any, enumerable?: boolean) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  })
}

继续回到array.js中。

[
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
.forEach(function (method) {
  // cache original method
  // 将数组的原生方法缓存起来,后面要调用
  const original = arrayProto[method]
  // 修改新数组对象的属性,这里的属性是数组方法。
  def(arrayMethods, method, function mutator () {
    // avoid leaking arguments:
    //这里定义的属性的值是一个mutator函数。
    //执行数组方法后的value值用函数来返回,返回之前添加observe响应
    // 避免泄露参数 参数是执行数组方法时括号中的参数
    // http://jsperf.com/closure-with-arguments
    let i = arguments.length
    const args = new Array(i)
    while (i--) {
      args[i] = arguments[i]
    }
     //调用原生的数组方法
    const result = original.apply(this, args)
   //执行数组方法的当前数组的属性有__ob__属性,因为当前数组初始化时已经变成响应式属性。
    const ob = this.__ob__ 
    //数组新插入的元素需要重新进行observe才能响应式
    let inserted
    switch (method) {
      case 'push':
        inserted = args
        break
      case 'unshift':
        inserted = args
        break
      case 'splice':
       ////splice 方法第三个参数开始才是新增的元素
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted)
    // notify change
    //dep通知所有注册的观察者进行响应式处理
    ob.dep.notify()
    //返回原生的数组处理结果
    return result
  })
})

 

标签: Vue

发表评论 (已有0条评论)

还木有评论哦,快来抢沙发吧~