在Store構造函數中html
// bind commit and dispatch to self const store = this; const { dispatch, commit } = this; this.dispatch = function boundDispatch (type, payload) { return dispatch.call(store, type, payload) }; this.commit = function boundCommit (type, payload, options) { return commit.call(store, type, payload, options) };
const { dispatch, commit } = this
這裏的commit指向的是Store.prototype.commit;
因此其實咱們在實例中調用commit的時候傳的參數通過一層中轉,實際調用Store的原型對象的方法,
因此咱們能夠看到$store
對象中有個commit方法,__proto__中也有一個commit方法,兩個的差異僅僅是隻傳遞參數的不一樣實際調用的是構造函數的原型對象的方法即$store.__proto__.commit方法vue
咱們通常的commit使用方法第一個參數爲字符串,第二個參數是咱們即將修改的數據vuex
store.commit('increment', { amount: 10 })
而官方文檔還提供一種方式:對象風格的提交方式
提交 mutation 的另外一種方式是直接使用包含type
屬性的對象:數組
store.commit({ type: 'increment', amount: 10 })
爲何能這麼調用呢ide
先粗略的看下原型對象的commit方法函數
commit (_type, _payload, _options) { // check object-style commit const { type, payload, options } = unifyObjectStyle(_type, _payload, _options); const mutation = { type, payload }; const entry = this._mutations[type]; if (!entry) { { console.error(`[vuex] unknown mutation type: ${type}`); } return } this._withCommit(() => { entry.forEach(function commitIterator (handler) { handler(payload); }); }); this._subscribers.forEach(sub => sub(mutation, this.state)); if ( options && options.silent ) { console.warn( `[vuex] mutation type: ${type}. Silent option has been removed. ` + 'Use the filter functionality in the vue-devtools' ); } }
在調用commit方法的時候使用了unifyObjectStyle方法,就是將這兩種傳參轉換成同一種格式來使用ui
function unifyObjectStyle (type, payload, options) { if (isObject(type) && type.type) { options = payload; payload = type; type = type.type; } { assert(typeof type === 'string', `expects string as the type, but found ${typeof type}.`); } return { type, payload, options } }
最終返回的對象type是一個字符串,payload是荷載若是以對象風格的提交方式,通過轉換後就是跟咱們普通的提交荷載方式格式同樣。
對於options的做用暫時還不瞭解,暫時沒法分析。this
接下來看下const entry = this._mutations[type];
這裏的_mutations將咱們在store對象中寫的mutations以數組的格式,存在_mutations對象對應的值上。例如在spa
{ mutations: { addCount(state, payload) { state.count = state.count + 1; } } }
那麼this._mutations('addCount')中就指向一個數組,數組中有addCount方法。prototype
this._withCommit(() => { entry.forEach(function commitIterator (handler) { handler(payload); }); });
因此調用的時候用forEach遍歷數據,而後執行將載荷payload傳入handler
那爲何要在_withCommit中調用方法呢,
_withCommit (fn) { const committing = this._committing; this._committing = true; fn(); this._committing = committing; }
在提交時候講this._commiting置爲true,待執行完了fn,再將this._commiting = commiting
這裏須要注意一個地方就是fn函數必須爲同步函數,這樣才能保證fn方法徹底執行完了,纔將this._committing置爲false,這也是爲何官方文檔中說到mutation-必須是同步函數。由於當 mutation 觸發的時候,回調函數尚未被調用,devtools 不知道何時回調函數實際上被調用——實質上任何在回調函數中進行的狀態的改變都是不可追蹤的
那麼這個_committing的做用是什麼
function enableStrictMode (store) { store._vm.$watch(function () { return this._data.$$state }, () => { { assert(store._committing, `do not mutate vuex store state outside mutation handlers.`); } }, { deep: true, sync: true }); }
經過這段代碼的提示,大概能夠推斷出其做用,當store的數據被修改,會觸發上面的代碼,若是經過commit方法改變數據,_committing此時是爲ture的,而若是是直接修改store上面的數據,此時_committing仍是false,經過_committing標識咱們能夠判斷他是否是經過commit的方式進行修改的。
官方文檔說過更改 Vuex的store中的狀態的惟一方法是提交 mutation
,這其實只是一個約定,只有這樣數據的變化均可以在mutation中找到待完善。。