Home > Web Front-end > JS Tutorial > body text

A brief analysis of the source code content of VueX

不言
Release: 2018-07-20 15:30:47
Original
1836 people have browsed it

Vuex is a state management pattern developed specifically for Vue.js applications. For single-page applications with many components and complex interactions, Vuex provides a convenient, accurate and predictable state management method to facilitate data sharing and modification between components.

The file structure is as follows

  • /module

  • /plugins

  • helpers.js

  • ##index.esm.js

  • index.js

  • store.js

  • util.js

util.js

Start with the simplest tool function.

find function

/**
 * 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]
}
Copy after login

Test case for find function

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

Analysis:

    ##Use first
  • Assertion function f

    Filters list list, and finally takes the first element of the filtered list.

deepCopy function

/**
 * 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
}
Copy after login
test case of 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)
  })
Copy after login

Analysis:

    Function: Deep cloning function that supports circular references
  • The first if judgment
  • obj === null || typeof obj !== 'object'

    Judgment If it is not a reference type and is returned directly (the basic type is a value copy), it is also an exit from recursion.

  • The second judgment
  • hit

    is to judge whether it is a circular reference. Since it is a circular reference, there should be a copy cached in the cache, directly Get it from the cache to avoid making a duplicate copy again.

  • What is a circular reference? See the third test case
  • original.circular = original

    . The circular reference and the referenced content are the same. Caching is used to avoid duplication. Clone (the content is the same)

  • original.circular

    is a circular reference, original is a circular reference

  • First put
  • cope

    into cache. When recursing, if you encounter a circular reference, make sure there is a copy of the circularly referenced copy in the cache. , but copy must be a reference type.

  • Why
  • cope

    must be a reference type? Circular reference What is saved is the reference, not the content (the copy has not been completed at this time). The copy is not completed during the recursion. The copy is completed only after the recursion is completed, so that will be circularly referenced in the future## When the content of # changes (copying is completed), the content of circular reference changes simultaneously

    So
  • const copy = Array.isArray(obj) ? [] : {}
  • must be a reference type.

    Finally
  • Object.keys
  • You can traverse all key names of objects and arrays (only the properties of the instance are returned, excluding the prototype chain and Symbol) to implement recursive cloning.

    There are two exits, one is a basic type and the other is a circular reference.
  • ##forEachValue
/**
 * forEach for object
 */
export function forEachValue (obj, fn) {
  Object.keys(obj).forEach(key => fn(obj[key], key))
}
Copy after login

Test case

  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)
  })
Copy after login
Analysis:

A Function that traverses objects (supports objects and arrays)

  • fn(value, key)
  • But the first parameter of the callback function is the value, and the second parameter is the key Value
  • isObject
export function isObject (obj) {
  return obj !== null && typeof obj === &#39;object&#39;
}
Copy after login

Test Case

  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)
  })
Copy after login
Resolution:

Determine whether it is an object. There is no judgment here whether it is a native object. Arrays also pass.

  • Because typeof null === 'object' must first determine whether it is null

  • ##isPromise

  • export function isPromise (val) {
      return val && typeof val.then === &#39;function&#39;
    }
    Copy after login
Test case

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

Determine whether it is a Promise

  • First determine whether val is not undefined, and then You can judge val.then to avoid reporting errors

  • The basis for judgment is whether val.then is a function

  • assert

  • export function assert (condition, msg) {
      if (!condition) throw new Error(`[vuex] ${msg}`)
    }
    Copy after login
Test case:

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

Assertion function, assertion does not pass an Error

that throws a custom error message
  • index.js

    and
  • index.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
}
Copy after login

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
}
Copy after login

Analysis:

The difference is that

index.esm.js

is better than
    index. js
  • There is an additional import mode

    import Vuex, { mapState } from 'index.esm.js'

    : There are two ways to import
  • import Vuex from 'index.js'

    : There is only one way to import
  • ##mixin.js<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">export default function (Vue) { const version = Number(Vue.version.split(&amp;#39;.&amp;#39;)[0]) if (version &gt;= 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 === &amp;#39;function&amp;#39; ? options.store() : options.store } else if (options.parent &amp;&amp; options.parent.$store) { this.$store = options.parent.$store } } }</pre><div class="contentsignin">Copy after login</div></div>Analysis: </p> <h4>Why every component has </h4>\(store attribute, that is, every component can get\)<p>store</p> <ul class=" list-paddingleft-2"> <li><p>Vue2 directly uses the mixin and hook function beforeCreate, and Vue1 uses the appearance (decorator) mode to rewrite the Vue._init function. <span class="math inline"></span></p></li> <li>vuexInit<p> is to inject the globally registered store into the current component, before creating the component</p> </li> <li> <p><code>\(options are options of `new Vue(options)`,\)There is store

    in options
  • Since beforeCreate is the cycle hook of Vue, this points to the current component instance, so this.$storeThe store can be directly injected into the current component

  • All components are inherited from a global Vue, the global mixin component cycle hookbeforeCreate, so that each component Can be automatically injected into the store, that is, each component can get the global Vuenew Vue({ el: 'app', store, router }) directly through $store #store


Related recommendations:

Talk about me Understanding of vuex

Vue.js-vuex (state management)

The above is the detailed content of A brief analysis of the source code content of VueX. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template