【Vue原理】Mixins
如果你覺得排版難看,請點選 下面連結 或者 拉到 下面關注公眾號也可以吧
今天探索的是 mixins 的原始碼,mixins 根據不同的選項型別會做不同的處理
篇幅會有些長,你知道的,有很多種選項型別的嘛,但不是很難。只是涉及原始碼難免會有些煩,
不過這篇文章也不是給你直接看的,是為了可以讓你學習原始碼的時候提供微薄幫助而已
如果不想看原始碼的,可以看我的白話版
我們也是要帶著兩個問題開始
1、什麼時候開始合併
2、怎麼合併
如果你覺得排版難看,請點選下面原文連結 或者 關注公眾號【神仙朱】
什麼時候合併
合併分為兩種
1、全域性mixin 和 基礎全域性options 合併
這個過程是先於你呼叫 Vue 時發生的,也是必須是先發生的。這樣mixin 才能合併上你的自定義 options
Vue.mixin = function(mixin) {
this.options = mergeOptions(
this.options, mixin
);
return this
};
基礎全域性options 是什麼?
就是 components,directives,filters 這三個,一開始就給設定在了 Vue.options 上。所以這三個是最先存在全域性options
Vue.options = Object.create(null);
['component','directive','filter'].forEach(function(type) {
Vue.options[type + 's'] = Object.create(null);
});
這一步,是呼叫 Vue.mixin 的時候就馬上合併了,然後這一步完成 以後,舉個栗子
全域性選項就變成下面這樣,然後每個Vue例項都需要和這全域性選項合併
2、全域性options和 自定義options合併
在呼叫Vue 的時候,首先進行的就是合併
function Vue(options){ vm.$options = mergeOptions( { 全域性component, 全域性directive, 全域性filter 等....}, options , vm ); // ...處理選項,生成模板,掛載DOM 等.... }
options 就是你自己傳進去的物件引數,然後跟 全域性options 合併,全域性options 是哪些,也已經說過了
怎麼合併
上面的程式碼一直出現一個函式 mergeOptions,他便是合併的重點
來看原始碼
1、mergeOptions
function mergeOptions(parent, child, vm) {
// 遍歷mixins,parent 先和 mixins 合併,然後在和 child 合併
if (child.mixins) {
for (var i = 0, l = child.mixins.length; i < l; i++) {
parent = mergeOptions(parent, child.mixins[i], vm);
}
}
var options = {}, key;
// 先處理 parent 的 key,
for (key in parent) {
mergeField(key);
}
// 遍歷 child 的key ,排除已經處理過的 parent 中的key
for (key in child) {
if (!parent.hasOwnProperty(key)) {
mergeField(key);
}
}
// 拿到相應型別的合併函式,進行合併欄位,strats 請看下面
function mergeField(key) {
// strats 儲存著各種欄位的處理函式,否則使用預設處理
var strat = strats[key] || defaultStrat;
// 相應的欄位處理完成之後,會完成合並的選項
options[key] = strat(parent[key], child[key], vm, key);
}
return options
}
這段程式碼看上去有點繞,其實無非就是
1、先遍歷合併 parent 中的key,儲存在變數options
2、再遍歷 child,合併補上 parent 中沒有的key,儲存在變數options
3、優先處理 mixins ,但是過程跟上面是一樣的,只是遞迴處理而已
在上面例項初始化時的合併, parent 就是全域性選項,child 就是元件自定義選項,因為 parent 權重比 child 低,所以先處理 parent 。
“公司開除程式猿,也是先開始作用較低。。”
重點其實在於 各式各樣的處理函式 strat,下面將會一一列舉
2、defaultStrats
這段函式言簡意賅,意思就是優先使用元件的options
元件options>元件 mixin options>全域性options
var defaultStrats= function(parentVal, childVal) {
return childVal === undefined ?
parentVal :
childVal
};
3、data
我們先預設 data 的值是一個函式,簡化下原始碼 ,但是其實看上去還是會有些複雜
不過我們主要了解他的工作過程就好了
1、兩個data函式 組裝成一個函式
2、合併 兩個data函式執行返回的 資料物件
strats.data = function(parentVal, childVal, vm) {
return mergeDataOrFn(
parentVal, childVal, vm
)
};
function mergeDataOrFn(parentVal, childVal, vm) {
return function mergedInstanceDataFn() {
var childData = childVal.call(vm, vm)
var parentData = parentVal.call(vm, vm)
if (childData) {
return mergeData(childData, parentData)
} else {
return parentData
}
}
}
function mergeData(to, from) {
if (!from) return to
var key, toVal, fromVal;
var keys = Object.keys(from);
for (var i = 0; i < keys.length; i++) {
key = keys[i];
toVal = to[key];
fromVal = from[key];
// 如果不存在這個屬性,就重新設定
if (!to.hasOwnProperty(key)) {
set(to, key, fromVal);
}
// 存在相同屬性,合併物件
else if (typeof toVal =="object" && typeof fromVal =="object) {
mergeData(toVal, fromVal);
}
}
return to
}
4、生命鉤子
把所有的鉤子函式儲存進陣列,重要的是陣列子項的順序
順序就是這樣
[
全域性 mixin - created,
元件 mixin-mixin - created,
元件 mixin - created,
元件 options - created
]
所以當陣列執行的時候,正序遍歷,就會先執行全域性註冊的鉤子,最後是 元件的鉤子
function mergeHook(parentVal, childVal) {
var arr;
arr = childVal ?
// concat 不只可以拼接陣列,什麼都可以拼接
( parentVal ?
// 為什麼parentVal 是個陣列呢
// 因為無論怎麼樣,第一個 parent 都是{ component,filter,directive}
// 所以在這裡,合併的時候,肯定只有 childVal,然後就變成了陣列
parentVal.concat(childVal) :
( Array.isArray(childVal) ? childVal: [childVal] )
) :
parentVal
return arr
}
strats['created'] = mergeHook;
strats['mounted'] = mergeHook;
// ... 等其他鉤子
5、component、directives、filters
我一直覺得這個是比較好玩的,這種型別的合併方式,我是從來沒有在專案中使用過的
原型疊加
兩個物件並沒有進行遍歷合併,而是把一個物件直接當做另一個物件的原型
這種做法的好處,就是為了保留兩個相同的欄位且能訪問,避免被覆蓋
學到了學到了.....反正我是學到了
strats.components=
strats.directives=
strats.filters = function mergeAssets(
parentVal, childVal, vm, key
) {
var res = Object.create(parentVal || null);
if (childVal) {
for (var key in childVal) {
res[key] = childVal[key];
}
}
return res
}
就是下面這種,層層疊加的原型
6、watch
watch 的處理,也是合併成陣列,重要的也是合併順序,跟 生命鉤子一樣
這樣的鉤子
[
全域性 mixin - watch,
元件 mixin-mixin - watch,
元件 mixin - watch,
元件 options - watch
]
按照正序執行,最後執行的 必然是元件的 watch
strats.watch = function(parentVal, childVal, vm, key) {
if (!childVal) {
return Object.create(parentVal || null)
}
if (!parentVal) return childVal
var ret = {};
// 複製 parentVal 到 ret 中
for (var key in parentVal) {
ret[key] = parentVal[key];
}
for (var key$1 in childVal) {
var parent = ret[key$1];
var child = childVal[key$1];
if (!Array.isArray(parent)) {
parent = [parent];
}
ret[key$1] = parent ? parent.concat(child) :
( Array.isArray(child) ? child: [child] );
}
return ret
};
7、props、computed、methods
這幾個東西,是不允許重名的,合併成物件的時候,不是你死就是我活
重要的是,以誰的為主?必然是元件options 為主了
比如
元件的 props:{ name:""}
元件mixin 的 props:{ name:"", age: "" }
那麼 把兩個物件合併,有相同屬性,元件的 name 會替換 mixin 的name
trats.props =
strats.methods =
strats.inject =
strats.computed = function(parentVal, childVal, vm, key) {
if (!parentVal) return childVal
var ret = Object.create(null);
// 把 parentVal 的欄位 複製到 ret 中
for (var key in parentVal) {
ret[key] = parentVal[key];
}
if (childVal) {
for (var key in childVal) {
ret[key] = childVal[key];
}
}
return ret
};
其實在白話版裡面,就已經測試了很多例子,整個執行的流程也描述很清楚了,這裡就是放個原始碼供參考
相關推薦
【Vue原理】Mixins
如果你覺得排版難看,請點選 下面連結 或者 拉到 下面關注公眾號也可以吧 【Vue原理】Mixins - 原始碼版 今天探索的是 mixins 的原始碼,mixins 根據不同的選項型別會做不同的處理 篇幅會有些長,你知道的,有很多種選項型別的嘛,但不是很難。只是涉及原始碼難免會有些煩, 不過這篇文
【Vue原理】Watch
如果你覺得排版難看,請點選 下面連結 或者 拉到 下面關注公眾號也可以吧 【Vue原理】Watch - 原始碼版 今天繼續探索 Watch 原始碼,廢話不多說了 帶著我的幾個疑問開始 1、什麼時候初始化 2、怎麼確定監聽哪些值 3、深度監聽怎麼回事 4、怎麼觸發我的函式 這些問題的答案會摻
【Vue原理】Props
如果你覺得排版難看,請點選 下面連結 或者 拉到 下面關注公眾號也可以吧 【Vue原理】Props - 原始碼版 今天記錄 Props 原始碼流程,哎,這東西,就算是研究過了,也真是會隨著時間慢慢忘記的。 幸好我做了詳細的文章,忘記了什麼的,回憶起來必然是很快的。 好的,回到正題,Props 請你
【Vue原理】依賴更新
如果你覺得排版難看,請點選 下面連結 或者 拉到 下面關注公眾號也可以吧 【Vue原理】依賴更新 - 原始碼版 如果對依賴收集完全沒有概念的同學,可以先看我這篇白話版 響應式原理 - 白話版 我們已經講過了 依賴收集 【Vue原理】依賴收集 - 原始碼版之基本資料型別 【Vue
【Vue原理】VNode
如果你覺得排版難看,請點選 下面連結 或者 拉到 下面關注公眾號也可以吧 【Vue原理】VNode - 原始碼版 今天就來探索 VNode 的原始碼,VNode 是 Vue2 渲染機制中很重要的一部分,是深入Vue 必須瞭解的部分 我們以4個問題來開始我們的探索 1、vnode 是什麼及其作用
【Vue原理】Event
如果你覺得排版難看,請點選 下面連結 或者 拉到 下面關注公眾號也可以吧 【Vue原理】Event - 原始碼版 之 自定義事件 Vue 的自定義事件很簡單,就是使用 觀察者模式 進行事件的監聽和分發 Vue 封裝的這個觀察者模式,可以說是很完善了,這個可以獨立抽取出來的在其他專案中使用的程式碼,
【Vue原理】NextTick
寫文章不容易,點個讚唄兄弟 專注 Vue 原始碼分享,文章分為白話版和 原始碼版,白話版助於理解工作原理,原始碼版助於瞭解內部詳
【Vue原理】Render
寫文章不容易,點個讚唄兄弟 專注 Vue 原始碼分享,文章分為白話版和 原始碼版,白話版助於理解工作原理,原始碼版助於瞭解內部詳
【Vue原理】Diff
寫文章不容易,點個讚唄兄弟 <br> <br> 專注 Vue 原始碼分享,文章分為白話版和 原始碼版,
【vue.js】入門
emp 寫到 logs 組件 images href one mooc 渲染 慕課網視頻學習筆記:http://www.imooc.com/learn/694 1.將html、js、css寫到一個後綴名.vue的文件中,區分這三種類型是通過<template>、
【底層原理】四位計算機的原理及其實現
一點 led燈 waiting lean div rm2 src and nvt 你是否想過,計算機為什麽會加減乘除?或者更直接一點,計算機的原理到底是什麽? Waitingforfriday有一篇詳細的教程,講解了如何自己動手,制作一臺四位計算機。從中可以看到,二進制、數
【計算機原理】程序執行過程
進程 cnblogs div 空間 時間片 chat 內存管理 tro alt 本章主要介紹程序執行過程中操作系統、CPU都幹了什麽 運行前 程序在運行前,只是在硬盤上待著,此時就是一堆二進制代碼而已,沒有任何作用。 程序只有進入了內存才能運行,但是要進入內存,則需要服從操
【計算機原理】CPU部分.md
工作 信號 通過 臃腫 流水線 處理 2.6 操作 ade 本文由CPU阿甘改編而得,主要講的是系統啟動和程序執行時CPU做的工作。 CPU的構成 中央處理器(CPU,Central Processing Unit)由運算器、控制器、Cache等。 控制器:主要是對指令進
【組成原理】第一章 計算機系統概述
表示 運算 傳遞 intro 指令 掌握 周期 style 主存 重點掌握:MAR和MDR的含義,主存容量大小、CPU執行時間的計算,性能指標CPI、MIPS、主頻等等。 1. 存儲單元:CPU訪問存儲器的基本單位,每個單元有一個地址。通常是字節大小的整數倍。 2. CPU
【編譯原理】c++實現自下而上語法分析器
不可 acm times style size PC -i 表達式 鏈接 寫在前面:本博客為本人原創,嚴禁任何形式的轉載!本博客只允許放在博客園(.cnblogs.com),如果您在其他網站看到這篇博文,請通過下面這個唯一的合法鏈接轉到原文! 本博客全網唯一合法URL:ht
【計數原理】【UVA11538】 Chess Queen
put typename return col nbsp 題意 putchar cst putc 傳送門 Description 給你一個n*m的棋盤,在棋盤上放置一黑一白兩個皇後,求兩個皇後能夠互相攻擊的方案個數 Input 多組數據,每組數據包括:
MongoDB 復制集 第 二 部 之【選舉原理】
command primary red and 優先權 mongo mongodb 主機 set 目錄: 1·復制與選舉的原理與驗證2·oplog 日誌調整3·配置復制集的優先級4·部署認證的復制5·總結 復制與選舉的原理: 上一篇文章搭建了多臺實例,部署成復制集,
Memcached 主主復制 + Keepalived 高可用架構【附上原理】
ima pki nag ali event 主服務器 figure tel outer 目錄: 1·Memcached 主主復制概念2·Memcached 高可用的實現3·案例部署4·總結 Memcached 主主復制概念 (1)主主復制概念: Memcached
【Windows原理】非同步IO-_APC(非同步過程呼叫)
// 同步IO的缺點是, 在讀寫檔案時, 如果檔案太大, 或者讀寫的時間太長, 就會在讀寫函式中 // 阻塞住. // 非同步IO解決了這個問題, 非同步IO讀寫檔案時, 檔案再大也不會阻塞住 // 但是非同步IO要完成這樣的特性是有一點付出的 // 非同步讀寫檔案後, 需要通過一些方式
【Windows原理】IO非同步-等待事件物件
/* 同步IO的缺點是, 在讀寫檔案時, 如果檔案太大, 或者讀寫的時間太長, 就會在讀寫函式中 阻塞住. 非同步IO解決了這個問題, 非同步IO讀寫檔案時, 檔案再大也不會阻塞住 但是非同步IO要完成這樣的特性是有一點付出的 非同步讀寫檔案後, 需要通過一些方式才能知道檔案讀寫(IO