Vuex是一個專門為Vue.js應用程式開發的狀態管理模式。針對組件繁多互動複雜的單一頁面應用,Vuex提供了一種便利、準確和可預測的狀態管理方式,方便組件之間的資料共享和修改。
檔案架構如下
/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 !== 'object') { 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('deepCopy: nornal structure', () => { const original = { a: 1, b: 'string', c: true, d: null, e: undefined } const copy = deepCopy(original) expect(copy).toEqual(original) }) // 嵌套结构 it('deepCopy: nested structure', () => { const original = { a: { b: 1, c: [2, 3, { d: 4 }] } } const copy = deepCopy(original) expect(copy).toEqual(original) }) // 循环引用结构 it('deepCopy: circular structure', () => { 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('forEachValue', () => { 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 === 'object' }測試案例
it('isObject', () => { expect(isObject(1)).toBe(false) expect(isObject('String')).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 === 'function' }測試案例
it('isPromise', () => { 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('assert', () => { expect(assert.bind(null, false, 'Hello')).toThrowError('[vuex] Hello') })解析:
- #斷言函數,斷言不透過拋出一個自訂錯誤訊息的Error
#index.js和
index.esm.js
#index.js##<pre class='brush:php;toolbar:false;'>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
}</pre>
<pre class='brush:php;toolbar:false;'>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
}</pre>
解析:
- #差異就是
- index.esm.js
比
index. 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('.')[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 === 'function' ? 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
是將全域註冊的store注入到目前元件中,在建立該元件之前
# #\(options是`new Vue(options)`的options,\) - options中有store
由於
beforeCreate
是Vue
的週期鉤子,this
指向目前元件實例,所以this.$store
可以把store直接注入目前元件-
所有元件都是繼承於一個全域Vue的,全域mixin元件週期鉤子
beforeCreate
,這樣每個元件都能自動注入store,也也就是每個元件都能直接透過$store
拿到全域Vuenew Vue({ el: 'app', store, router })
的store
相關推薦:
以上是淺析VueX的原始碼內容的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3漢化版
中文版,非常好用

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),