検索
ホームページウェブフロントエンドjsチュートリアルVueX のソースコード内容の簡単な分析

Vuex は、Vue.js アプリケーション専用に開発された状態管理パターンです。 Vuex は、多数のコンポーネントと複雑な対話を含む単一ページ アプリケーションの場合、コンポーネント間のデータ共有と変更を容易にする、便利で正確かつ予測可能な状態管理方法を提供します。

ファイル構造は以下の通りです

  • /module/module

  • /plugins

  • helpers.js

  • index.esm.js

  • index.js

  • store.js

  • util.js

util.js

先从最简单的工具函数开始。

find函数

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

find函数的测试用例

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

解析:

  • 先用断言函数f过滤列表list,最后取过滤后列表的第一个元素。

deepCopy函数

/**
 * 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
}

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)
  })

解析:

  • 功能:支持循环引用的深克隆函数

  • 第一个if判断obj === null || typeof obj !== 'object'判断如果不是引用类型直接返回(基本类型是值拷贝),也是递归的一个出口。

  • 第二个判断hit是判断是不是循环引用,由于是循环引用,在cache中应该有缓存到一份拷贝,直接取cache的,避免再次重复拷贝一份。

  • 什么是循环引用看测试用例第三个original.circular = original,循环引用和被引用的内容是一样的,用缓存就是避免重复的克隆(内容一样)

  • original.circular是循环引用,original是被循环引用

  • 先把cope放到cache中,是在递归的时候,如果遇到循环引用,要确保cache中有一份被循环引用的copy,但是copy必须是引用类型。

  • 为什么cope必须是引用类型?循环引用保存的是引用不是内容(这时候还没拷贝完),在递归的时候并未完成拷贝,只有递归跑完了才完成拷贝,这样未来被循环引用的内容改变时(拷贝完),循环引用的内容同步改变

  • 所以const copy = Array.isArray(obj) ? [] : {}必须是引用类型。

  • 最后Object.keys可以遍历对象和数组的所有键名(只返回实例的属性,不包含原型链和Symbol),实现递归克隆。

  • 一共两个出口,一个是基本类型,另一个是循环引用。

forEachValue

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

测试用例

  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)
  })

解析:

  • 一个遍历对象的函数(支持对象和数组)

  • fn(value, key)但是回调函数第一个参数是值,第二个参数是键值

isObject

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

测试用例

  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)
  })

解析:

  • 判断是不是对象,这里没有判断是不是原生对象,数组也是通过的。

  • 由于typeof null === 'object'要先判断是不是null

isPromise

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

测试用例

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

解析:

  • 判断是不是Promise

  • 首先判断val不是undefined,然后才可以判断val.then,避免报错

  • 判断依据是val.then是不是函数

assert

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

测试用例:

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

解析:

  • 断言函数,断言不通过抛出一个自定义错误信息的Error

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
}

解析:

  • 区别就是index.esm.jsindex.js多了个一个导入模式

  • import Vuex, { mapState } from 'index.esm.js':有两种方式导入

  • 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
    }
  }
}

解析:

  • 为什么每个组件都拥有(store属性,也即每个组件都能拿到)store

  • Vue2直接用mixin和钩子函数beforeCreate,Vue1用外观(装饰者)模式重写Vue._init函数。

  • vuexInit

  • /plugins

    helpers.js 🎜🎜🎜 🎜index.esm.js🎜🎜🎜🎜index.js🎜🎜🎜🎜store.js🎜🎜🎜🎜util.js🎜🎜

util.js

🎜最も単純なユーティリティ関数から始めます。 🎜🎜🎜find関数🎜🎜rrreee🎜find関数のテストケース🎜rrreee🎜分析: 🎜🎜🎜🎜最初にassert function fを使用してlist listをフィルタリングし、最後にフィルタリングされたリストの最初の要素。 🎜🎜🎜🎜deepCopy関数🎜🎜rrreee🎜deepCopyのテストケース🎜rrreee🎜分析:🎜🎜🎜🎜機能:循環参照をサポートするディープクローニング機能🎜🎜🎜🎜First if判定obj = == null || typeof obj !== 'object' 参照型でない場合は、直接返されます (基本型は値のコピーです)。これは再帰の出口でもあります。
🎜🎜🎜🎜 2 番目の hit は、循環参照であるかどうかを判断します。循環参照なので、キャッシュにキャッシュされているコピーがあるはずです。再度同じことを繰り返さないように、重複したコピーを作成します。 🎜🎜🎜🎜 循環参照とは何ですか? 3 番目のテスト ケース original.circular =original を参照してください。 キャッシュは、複製の繰り返しを避けるために使用されます。同じ)🎜 🎜🎜🎜original.circular は循環参照、original は循環参照です 🎜🎜🎜🎜まず cope に入れます>キャッシュ、再帰時に循環参照が発生した場合は、キャッシュ内に循環参照される <code>copy があることを確認してください。ただし、copy は参照型。 🎜🎜🎜🎜なぜ cope は参照型でなければならないのですか? 循環参照 は、コンテンツではなく参照を保存します (この時点ではコピーは完了していません)。この場合、コピーは再帰が完了した後でのみ完了します。ちなみに、 は将来循環参照されます の内容が変更されると (コピーが完了すると)、<code>循環参照 の内容も同時に変更されます🎜🎜🎜🎜ので const copy = Array.isArray(obj) ? [] : {} code> は参照型である必要があります。 🎜🎜🎜🎜最後に、<code>Object.keys は、オブジェクトと配列のすべてのキー名を走査して (プロトタイプ チェーンとシンボルを除く、インスタンスの属性のみを返します)、再帰的クローン作成を実装します。 🎜🎜🎜🎜出口は合計 2 つあり、1 つは基本タイプ、もう 1 つは循環参照です。 🎜🎜🎜🎜forEachValue🎜🎜rrreee🎜テストケース🎜rrreee🎜分析: 🎜🎜🎜🎜オブジェクトを走査する関数(オブジェクトと配列をサポート)🎜🎜🎜🎜fn(value, key) code>しかし、コールバック関数の最初のパラメータは値であり、2 番目のパラメータはキー値です🎜🎜🎜🎜isObject🎜🎜rrreee🎜テストケース🎜rrreee🎜分析: 🎜🎜🎜🎜オブジェクトです。ここには何もありません。ネイティブ オブジェクトかどうかを判断するために、配列も渡します。 🎜🎜🎜🎜typeof null === 'object' はまず null かどうかを判断する必要があるため🎜🎜🎜🎜isPromise🎜🎜rrreee🎜テストケース🎜rrreee🎜分析: 🎜🎜🎜🎜お約束🎜🎜🎜 🎜最初にvalが未定義ではないかどうかを判断し、次にval.thenを判断してエラーの報告を避けることができます🎜🎜🎜🎜判断の根拠はval.thenが関数であるかどうかです🎜🎜🎜🎜assert 🎜🎜rrreee🎜テストケース: 🎜rrreee🎜分析: 🎜🎜🎜🎜Assert関数、カスタムエラーメッセージError🎜🎜<h4> <code>index.jsおよびindex.esm.js code> 🎜index.js🎜rrreee🎜index.esm.js🎜rrreee🎜分析: 🎜🎜🎜🎜違いは、index.esm.js には index.js よりもインポート モードが 1 つ多いことです🎜🎜🎜🎜import Vuex、{mapState} from 'index.esm.js ': 2 つあります インポートする方法は 1 つだけです 🎜🎜🎜🎜import Vuex from 'index.js': インポートする方法は 1 つだけです 🎜🎜mixin.jsrrreee🎜分析: 🎜🎜 🎜🎜なぜすべてのコンポーネントには 🎜(ストア属性、つまり、すべてのコンポーネントが取得できる) があるのですか🎜store🎜🎜🎜🎜Vue2 は、Create の前に mixin とフック関数を直接使用します。 , 一方、Vue1 は、_init 関数を使用して Vue を書き換えます。 🎜🎜🎜🎜vuexInit は、コンポーネントを作成する前に、グローバルに登録されたストアを現在のコンポーネントに挿入します🎜🎜🎜🎜🎜(オプションは `new Vue(options)` のオプションです)🎜オプションがありますお店🎜
  • beforeCreateVue のサイクル フックであるため、this は現在のコンポーネント インスタンスを指しているため、this.$store ストアは現在のコンポーネントに直接注入できます<code>beforeCreateVue的周期钩子,this指向当前组件实例,所以this.$store可以把store直接注入当前组件

  • 所有组件都是继承于一个全局Vue的,全局mixin组件周期钩子beforeCreate,这样每个组件都能自动注入store,也即每个组件都能直接通过$store拿到全局Vuenew Vue({ el: 'app', store, router })store


  • 相关推荐:

    谈谈我对vuex的理解

    すべてのコンポーネントはグローバル Vue、グローバル ミックスイン コンポーネント サイクル フック beforeCreate から継承されるため、各コンポーネントは自動的にストアを注入できますつまり、すべてのコンポーネントは、$ を介してグローバル Vue<code>new Vue({ el: 'app', store, router })store を直接取得できます。ストア

    🎜🎜関連の推奨事項: 🎜🎜vuex についての私の理解について話します🎜🎜🎜🎜Vue.js vuex (状態管理)🎜🎜

    以上がVueX のソースコード内容の簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

    Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

    Python vs. JavaScript:コミュニティ、ライブラリ、リソースPython vs. JavaScript:コミュニティ、ライブラリ、リソースApr 15, 2025 am 12:16 AM

    PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

    C/CからJavaScriptへ:すべてがどのように機能するかC/CからJavaScriptへ:すべてがどのように機能するかApr 14, 2025 am 12:05 AM

    C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

    JavaScriptエンジン:実装の比較JavaScriptエンジン:実装の比較Apr 13, 2025 am 12:05 AM

    さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

    ブラウザを超えて:現実世界のJavaScriptブラウザを超えて:現実世界のJavaScriptApr 12, 2025 am 12:06 AM

    現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

    next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)Apr 11, 2025 am 08:23 AM

    私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

    next.jsを使用してマルチテナントSaaSアプリケーションを構築する方法(フロントエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する方法(フロントエンド統合)Apr 11, 2025 am 08:22 AM

    この記事では、許可によって保護されたバックエンドとのフロントエンド統合を示し、next.jsを使用して機能的なedtech SaaSアプリケーションを構築します。 FrontEndはユーザーのアクセス許可を取得してUIの可視性を制御し、APIリクエストがロールベースに付着することを保証します

    JavaScript:Web言語の汎用性の調査JavaScript:Web言語の汎用性の調査Apr 11, 2025 am 12:01 AM

    JavaScriptは、現代のWeb開発のコア言語であり、その多様性と柔軟性に広く使用されています。 1)フロントエンド開発:DOM操作と最新のフレームワーク(React、Vue.JS、Angularなど)を通じて、動的なWebページとシングルページアプリケーションを構築します。 2)サーバー側の開発:node.jsは、非ブロッキングI/Oモデルを使用して、高い並行性とリアルタイムアプリケーションを処理します。 3)モバイルおよびデスクトップアプリケーション開発:クロスプラットフォーム開発は、反応および電子を通じて実現され、開発効率を向上させます。

    See all articles

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    AI Hentai Generator

    AI Hentai Generator

    AIヘンタイを無料で生成します。

    ホットツール

    WebStorm Mac版

    WebStorm Mac版

    便利なJavaScript開発ツール

    EditPlus 中国語クラック版

    EditPlus 中国語クラック版

    サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

    Dreamweaver Mac版

    Dreamweaver Mac版

    ビジュアル Web 開発ツール

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    SAP NetWeaver Server Adapter for Eclipse

    SAP NetWeaver Server Adapter for Eclipse

    Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。