關於vue中如何監聽數組變化

前言

前段時間學習了關於vue中響應式數據的原理,(並做了學習筆記vue響應式原理),實際上是經過Object.defineProperty控制getter和setter,並利用觀察者模式完成的響應式設計。那麼數組有一系列的操做方法,這些方法並不會觸發數組的getter和setter方法。那麼vue中針對數組的響應式設計是如何實現的呢...那麼咱們一塊兒去學習下吧~html

源碼部分

https://github.com/vuejs/vue/blob/dev/src/core/observer/array.jsvue

從哪開始第一步學習呢

Emmmm...
我以爲要先把Vue中的數據響應式原理弄清楚,這樣對於理解vue中是如何檢測數組的變化才比較好,因此,能夠去網上找下文章而後配合源碼進行閱讀,相信你必定會理解的。推薦下我以前看的一篇博客,還有我看事後本身寫的學習記錄吧,哈哈。git

好的,先看看這個吧。哈哈!github

從圖開始

我們先看下下面的圖,先了解下vue中實現的思路,這樣接下來再看源碼的實現,會一清二楚,明明白白。
image.pngsegmentfault

看到這個圖而後思考一下,是否是大體瞭解了~數組

  • 首先判斷瀏覽器是否支持__proto__指針
  • 重寫數組的這7個方法,而後根據是否支持__proto__,將改寫後的數組指向數組的prototype。

是否是很簡單!!!瀏覽器

看看源碼吧

瞭解了實現原理,那麼咱們再看看源碼吧,看下源碼主要是更深刻的瞭解做者是如何實現的,也能夠看下優秀的代碼編碼方式,加以學習。緩存

關於一些解釋我就寫在下面的代碼塊中了哈!app

//https://github.com/vuejs/vue/blob/dev/src/core/observer/array.js


//def方法是基於Object.defineProperty封裝的一層方法,很簡單,我會在下面把代碼貼出來,省得你們去找了。
import { def } from '../util/index' 

//保存下原生的數組原型對象
const arrayProto = Array.prototype

//進行原型鏈接,將arrayMethods的原型指向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]
  def(arrayMethods, method, function mutator (...args) {
    var args = [], 
    len = arguments.length;
    while (len--) args[len] = arguments[len];
    const result = original.apply(this, args) // 原來的數組方法執行結果
    const ob = this.__ob__ // 這個__ob__就是Observe的實例~~~~
    let inserted
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted) // 若是數組有變化,則從新調用observeArray
    // notify change
    ob.dep.notify()  //
    return result
  })
})

這個是關於Observe的代碼:學習

var Observer = function Observer(value) {
    this.value = value;
    this.dep = new Dep();
    this.vmCount = 0;
    def(value, '__ob__', this);  //這裏會看到在每一個對象數據上都會綁定一個Observe的實例,因此上面代碼中的this.__ob__就是這個
    if (Array.isArray(value)) { // 這裏判斷是不是數組類型的數據,若是是的話就走observeArray
      if (hasProto) {
        protoAugment(value, arrayMethods);
      } else {
        copyAugment(value, arrayMethods, arrayKeys);
      }
      this.observeArray(value); //這裏就是處理數組類型的數據,以下
    } else {
      this.walk(value);
    }
  };

以下是observeArray的實現:

Observer.prototype.observeArray = function observeArray(items) {
    for (var i = 0, l = items.length; i < l; i++) {
      observe(items[i]); // 這個observe方法以下
    }
  };

在這裏咱們看下observe這個方法:

function observe(value, asRootData) {
    if (!isObject(value) || value instanceof VNode) {
      return
    }
    var ob;
    if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
      ob = value.__ob__;
    } else if (
      shouldObserve &&
      !isServerRendering() &&
      (Array.isArray(value) || isPlainObject(value)) &&
      Object.isExtensible(value) &&
      !value._isVue
    ) {
      ob = new Observer(value);
    }
    if (asRootData && ob) {
      ob.vmCount++;
    }
    return ob
  }

這個是關於def方法的實現,很簡單我就不說了哈:

function def (obj, key, val, enumerable) {
    Object.defineProperty(obj, key, {
      value: val,
      enumerable: !!enumerable,
      writable: true,
      configurable: true
    });
}

就這麼多吧...也沒講什麼,大體看下整理出來的核心代碼,應該就能夠了解它實現的思路了吧...等我研究透了再更新下,就這樣吧..

相關文章
相關標籤/搜索