Heim  >  Artikel  >  Web-Frontend  >  Eine kurze Analyse des Quellcodeinhalts von VueX

Eine kurze Analyse des Quellcodeinhalts von VueX

不言
不言Original
2018-07-20 15:30:471821Durchsuche

Vuex ist ein Zustandsverwaltungsmuster, das speziell für Vue.js-Anwendungen entwickelt wurde. Für einseitige Anwendungen mit vielen Komponenten und komplexen Interaktionen bietet Vuex eine praktische, genaue und vorhersehbare Methode zur Zustandsverwaltung, um den Datenaustausch und die Änderung zwischen Komponenten zu erleichtern.

Die Dateistruktur ist wie folgt

  • /module

  • /plugins

  • helpers.js

  • index.esm.js

  • index.js

  • store.js

  • util.js

util.js

Beginnen Sie mit der einfachsten Utility-Funktion .

Suchfunktion

/**
 * Get the first item that pass the test
 * by second argument function
 *
 * @param {Array} list
 * @param {Function} f
 * @return {*}
 */
export function find (list, f) {
  return list.filter(f)[0]
}

Testfall für Suchfunktion

it('find', () => {
  const list = [33, 22, 112, 222, 43]
  expect(find(list, function (a) { return a % 2 === 0 })).toEqual(22)
})

Analyse:

  • Zuerst verwenden断言函数fFilter列表list und nehmen Sie schließlich das erste Element der gefilterten Liste.

DeepCopy-Funktion

/**
 * Deep copy the given object considering circular structure.
 * This function caches all nested objects and its copies.
 * If it detects circular structure, use cached copy to avoid infinite loop.
 *
 * @param {*} obj
 * @param {Array<Object>} cache
 * @return {*}
 */
export function deepCopy (obj, cache = []) {
  // just return if obj is immutable value
  if (obj === null || typeof obj !== &#39;object&#39;) {
    return obj
  }

  // if obj is hit, it is in circular structure
  const hit = find(cache, c => c.original === obj)
  if (hit) {
    return hit.copy
  }

  const copy = Array.isArray(obj) ? [] : {}
  // put the copy into cache at first
  // because we want to refer it in recursive deepCopy
  cache.push({
    original: obj,
    copy
  })

  Object.keys(obj).forEach(key => {
    copy[key] = deepCopy(obj[key], cache)
  })

  return copy
}

Testfall von deepCopy

  // 普通结构
  it(&#39;deepCopy: nornal structure&#39;, () => {
    const original = {
      a: 1,
      b: &#39;string&#39;,
      c: true,
      d: null,
      e: undefined
    }
    const copy = deepCopy(original)

    expect(copy).toEqual(original)
  })
  
  // 嵌套结构
  it(&#39;deepCopy: nested structure&#39;, () => {
    const original = {
      a: {
        b: 1,
        c: [2, 3, {
          d: 4
        }]
      }
    }
    const copy = deepCopy(original)

    expect(copy).toEqual(original)
  })
  
  // 循环引用结构
  it(&#39;deepCopy: circular structure&#39;, () => {
    const original = {
      a: 1
    }
    original.circular = original

    const copy = deepCopy(original)

    expect(copy).toEqual(original)
  })

Analyse:

  • Funktion: Deep-Cloning-Funktion, die Zirkelverweise unterstützt

  • Die erste if-Beurteilungobj === null || typeof obj !== 'object'beurteilt, dass, wenn es sich nicht um einen Referenztyp handelt, direkt zurückgegeben wird (der Basistyp ist ein Wert). copy), was ebenfalls ein rekursiver Exit ist.

  • Das zweite Urteil hit besteht darin, zu beurteilen, ob es sich um einen Zirkelverweis handelt. Es sollte eine Kopie im Cache vorhanden sein Vermeiden Sie die erneute Erstellung doppelter Kopien.

  • Was ist ein Zirkelverweis? original.circular = original Der Zirkelverweis und der referenzierte Inhalt sind identisch, um wiederholtes Klonen (gleicher Inhalt) zu vermeiden.

  • original.circular ist ein Zirkelverweis, und original ist ein Zirkelverweis

  • zuerst cope in cache einfügen , es ist in Wenn Sie bei der Rekursion auf einen Zirkelverweis stoßen, stellen Sie sicher, dass sich eine Kopie von 被循环引用的copy im Cache befindet, aber copy muss ein Referenztyp sein.

  • Warum muss cope ein Referenztyp sein? 循环引用 speichert die Referenz und nicht den Inhalt (das Kopieren ist zu diesem Zeitpunkt noch nicht abgeschlossen). Das Kopieren wird erst abgeschlossen, wenn der Inhalt von 被循环引用 abgeschlossen ist Änderungen in der Zukunft (Kopieren ist abgeschlossen), ändert sich synchron zu 循环引用

  • , daher muss

    ein Referenztyp sein. const copy = Array.isArray(obj) ? [] : {}

  • Schließlich kann

    alle Schlüsselnamen von Objekten und Arrays durchlaufen (es werden nur die Attribute der Instanz zurückgegeben, mit Ausnahme der Prototypenkette und des Symbols), um rekursives Klonen zu implementieren. Object.keys

  • Es gibt zwei Ausgänge, einer ist ein Basistyp und der andere ist ein Zirkelverweis.

forEachValue

/**
 * forEach for object
 */
export function forEachValue (obj, fn) {
  Object.keys(obj).forEach(key => fn(obj[key], key))
}

Testfall

  it(&#39;forEachValue&#39;, () => {
    let number = 1

    function plus (value, key) {
      number += value
    }
    const origin = {
      a: 1,
      b: 3
    }

    forEachValue(origin, plus)
    expect(number).toEqual(5)
  })

Parsing:

  • A Funktionen zum Durchlaufen von Objekten (unterstützende Objekte und Arrays)

  • Aber der erste Parameter der Rückruffunktion ist der Wert und der zweite Parameter ist der Schlüsselwertfn(value, key)

isObject

export function isObject (obj) {
  return obj !== null && typeof obj === &#39;object&#39;
}

Testfall

  it(&#39;isObject&#39;, () => {
    expect(isObject(1)).toBe(false)
    expect(isObject(&#39;String&#39;)).toBe(false)
    expect(isObject(undefined)).toBe(false)
    expect(isObject({})).toBe(true)
    expect(isObject(null)).toBe(false)
    expect(isObject([])).toBe(true)
    expect(isObject(new Function())).toBe(false)
  })

Analyse:

  • Bestimmen Sie, ob es sich um ein Objekt handelt . Hier gibt es kein Urteil, es handelt sich nicht um ein natives Objekt, und es werden auch Arrays übergeben.

  • Weil typeof null === 'object' zuerst feststellen muss, ob es null ist

isPromise

export function isPromise (val) {
  return val && typeof val.then === &#39;function&#39;
}

Testfall

  it(&#39;isPromise&#39;, () => {
    const promise = new Promise(() => {}, () => {})
    expect(isPromise(1)).toBe(false)
    expect(isPromise(promise)).toBe(true)
    expect(isPromise(new Function())).toBe(false)
  })

Analyse:

  • Bestimmen Sie, ob es sich um ein Versprechen handelt

  • Beurteilen Sie zunächst diesen Wert ist nicht undefiniert, und dann können Sie val.then beurteilen, um Meldefehler zu vermeiden

  • Die Grundlage für die Beurteilung ist, ob val.then eine Funktion ist

assert

export function assert (condition, msg) {
  if (!condition) throw new Error(`[vuex] ${msg}`)
}

Testfall:

  it(&#39;assert&#39;, () => {
    expect(assert.bind(null, false, &#39;Hello&#39;)).toThrowError(&#39;[vuex] Hello&#39;)
  })

Analyse:

  • Assert-Funktion, Behauptung eines Fehlers beim Auslösen eines benutzerdefinierten Fehlers Meldung Fehler

und index.jsindex.esm.js

index.js

import { Store, install } from &#39;./store&#39;
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from &#39;./helpers&#39;

export default {
  Store,
  install,
  version: &#39;__VERSION__&#39;,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}

index.esm.js

import { Store, install } from &#39;./store&#39;
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from &#39;./helpers&#39;

export default {
  Store,
  install,
  version: &#39;__VERSION__&#39;,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}

export {
  Store,
  install,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}

Analyse:

  • Der Unterschied besteht darin, dass

    einen Importmodus mehr hat als index.esm.jsindex.js

  • : Es gibt zwei Möglichkeiten, import Vuex, { mapState } from 'index.esm.js'

  • : Es gibt nur eine Möglichkeit,

    import Vuex from 'index.js'

  • mixin.js
export default function (Vue) {
  const version = Number(Vue.version.split(&#39;.&#39;)[0])

  if (version >= 2) {
    Vue.mixin({ beforeCreate: vuexInit })
  } else {
    // override init and inject vuex init procedure
    // for 1.x backwards compatibility.
    const _init = Vue.prototype._init
    Vue.prototype._init = function (options = {}) {
      options.init = options.init
        ? [vuexInit].concat(options.init)
        : vuexInit
      _init.call(this, options)
    }
  }

  /**
   * Vuex init hook, injected into each instances init hooks list.
   */

  function vuexInit () {
    const options = this.$options
    // store injection
    if (options.store) {
      this.$store = typeof options.store === &#39;function&#39;
        ? options.store()
        : options.store
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store
    }
  }
}

zu importieren. Parsen:

    Warum jede Komponente beide hat
  • (Store-Attribut, das heißt, jede Komponente kann es bekommen)

    Store

  • Vue2 verwendet direkt Mixin und Die Hook-Funktion beforeCreate, Vue1 verwendet den Erscheinungsmodus (Decorator), der die Vue._init-Funktion überschreibt.
  • besteht darin, den global registrierten Speicher in die aktuelle Komponente einzufügen, bevor die Komponente erstellt wird

    vuexInit

  • (Optionen sind ` neue Vue(Optionen)`s Optionen,)

    Optionen haben Store

  • Da beforeCreate der Cycle-Hook von Vue ist und this auf die aktuelle Komponenteninstanz zeigt, kann this.$store den Store direkt in die aktuelle Komponente

  • injizieren
  • Alle Komponenten erben von einem globalen Vue, dem globalen Mixin-Komponentenzyklus-Hook beforeCreate, sodass jede Komponente automatisch in den Speicher eingefügt werden kann, dh jede Komponente kann den globalen Vue direkt über $storenew Vue({ el: 'app', store, router })store


相关推荐:

谈谈我对vuex的理解

Vue.js's vuex (Zustandsverwaltung)

Das obige ist der detaillierte Inhalt vonEine kurze Analyse des Quellcodeinhalts von VueX. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn