前言:本文將引入兩個 Vue 中比較特殊的使用場景,帶領你們熟悉一下
null
和undefined
的區別,而後再分析一下 Vue 中是怎麼對 Props 作校驗的,最後給出大佬是怎麼解釋的。html
一直以來,筆者在使用 Vue 時,習慣於在須要表示 prop 屬性未定義時,使用undefined
,而不是null
。由於「undefined
纔是沒有值,null
是有值,可是值爲空的對象(注意不是空對象{}
)」。vue
基於這一習慣,筆者規避掉了不少問題,對此也沒有深究。git
直到最近,參與項目的一些同窗習慣於指定null
爲初始值,我也沒有強制性統一。根本緣由是,我本身也以爲沒什麼,每一個人都有本身的習慣,只要大的風格不出誤差就能夠接受,畢竟項目緊嘛。github
直到今天遇到了下面的場景,我才發現,原來這麼作會有一些奇怪的小問題。瀏覽器
null
,會使用 default 的值嗎?閱讀如下代碼,你以爲有問題嗎?markdown
HTML:app
<div id="app"> <list :items="null"></list> </div> 複製代碼
JS:less
函數
Vue.component('list', { template: '<div>{{ typeof items }} {{ items.join(',') }}</div>', props: { items: { type: Array, default() { return [1, 2, 3] }, } } }) 複製代碼new Vue({ el: '#app', });
上述的代碼執行以後有問題嗎?停頓 5s 思考一下,一、二、三、四、5。oop
好,咱們來看下示例代碼,這段代碼執行以後會報錯(記得開啓控制檯查看錯誤,由於是 JS 執行錯誤)。由於items
最終的值是null
,而因此無法對null
執行join()
拼接。那爲何 prop 值爲null
時,default
中指定的值沒有生效呢?
若是你願意,能夠把null
換成undefined
,你會發現正如你指望的那樣,default
生效了。
required
,傳null
能夠嗎?既然 prop 的值爲null
時,default
不會生效,那咱們可否經過required
強制 prop 必填呢?
HTML 保持場景一不變。JS 作以下改動:
Vue.component('list', { template: '<div>{{ typeof items }} {{ items.join(',') }}</div>', props: { items: { type: Array, required: true, } } }) 複製代碼new Vue({ el: '#app', });
一樣停頓 5s 思考一下,一、二、三、四、5,好。咱們看下 示例代碼,這段代碼執行時依然會報錯。
Vue 會給出警告,信息以下:
[Vue warn]: Invalid prop: type check failed for prop \"items\". Expected Array, got Null. (found in component <list>) 複製代碼
從警告內容能夠看出null
經過了required: true
的驗證,可是沒有經過類型校驗,最後瀏覽器執行報錯。若是這時候,你再次嘗試將null
改爲undefined
,你會發現依然行不通,會有相似的錯誤。
好了,至此,咱們已經看完了我所想展現的示例。能夠總結爲如下兩個疑問:
null
的時候,爲何default
中定義的值沒有生效?(顯然,當值爲 undefined 的時候,默認值是會生效的)null
/undefined
的時候,爲何required: ture
的校驗彷佛經過了,可是類型校驗反倒沒有經過?(顯然,required: false
的時候,null
和undefined
是都能經過類型校驗的。這點文檔中有提到。)在詳細解釋爲何以前,咱們先來熟悉下一個歷史悠久的問題:「null
和undefined
的區別是什麼?」
在設計之初,JavaScript 是這樣區分的:null
是一個表示"無"的對象,轉爲數值時爲0
;undefined
是一個表示"無"的原始值,轉爲數值時爲NaN
。
Number(null) // 0 5 + null // 5 複製代碼Number(undefined) // NaN 5 + undefined // NaN
不得不吐槽,真是坑呀
但後來被證實這並不可行。目前,null
和undefined
基本是同義的,只有一些細微的差異。
null
表示沒有對象,即此處不該該有值。雖然其表示不該該有值,但它是有值的,值是一個空的對象(注意不是{}
)。用法以下:
Object.getPrototypeOf(Object.prototype) // null 複製代碼
undefined
表示缺乏值,就是此處應該有一個值,可是尚未定義。
undefined
。undefined
。undefined
。undefined
。var i; i // undefinedfunction f(x){console.log(x)} f() // undefined
var obj = new Object(); obj.p // undefined
複製代碼var ret = f(); ret // undefined
好了,咱們已經再次熟悉了一下null
和undefined
的區別。下面就讓咱們一塊兒看下,Vue 中是如何進行 Prop 校驗以及如何對待null
和undefined
。
筆者閱讀了 Vue 中關於Prop 校驗的代碼,總結出了以下圖所示的校驗流程:
從圖中第三步能夠看出,只有 prop 的值爲undefined
時,纔會去獲取default
中的值。這解釋了第一部分兩個奇怪現象的第一個。
代碼片斷以下:
// check default value if (value === undefined) { value = getPropDefaultValue(vm, prop, key) // since the default value is a fresh copy, // make sure to observe it. const prevShouldObserve = shouldObserve toggleObserving(true) observe(value) toggleObserving(prevShouldObserve) } 複製代碼
從圖中第四步能夠看出,當required: true
時,只有不傳屬性時,纔會提示'Missing required prop
。當required:false
時,null
和undefined
都會經過校驗。其餘狀況,則都會進行類型校驗。這解釋了第一部分兩個奇怪現象的第二個。
代碼片斷以下:
// required爲true,且不傳屬性 if (prop.required && absent) { warn( 'Missing required prop: "' + name + '"', vm ) return } // required爲false,null和undefined校驗經過 if (value == null && !prop.required) { return } // 其餘狀況校驗type let type = prop.type // ... if (type) { // type校驗邏輯... } 複製代碼
好了,咱們經過 Vue 源碼中的邏輯解釋了爲何會出現第一部分中的奇怪現象。但可能仍是沒有理解爲何。下面咱們繼續來看一下大佬們的解釋。
引用一下尤雨溪在issue#6768 中的回答,部份內容及翻譯以下:
null
indicates the value is explicitly marked as not present and it should remain null.
null
表示顯式地標記值爲未指定(是個空值),因此咱們保留null
。(這裏解釋了爲何不對null
應用default
)
undefined
indicates the value is not present and a default value should be used if available.
undefined
表示值沒有指定,若是有默認值,則使用默認值。
required: true
indicates neithernull
orundefined
are allowed (unless a default is used)
required: true
表示在 default 沒有應用的狀況下,null
和undefined
都不容許。注意:還有一個小前提,就是給屬性指定了類型
(此外,這句話隱式包含了 required 和 default 是能夠共存的,先應用 default,再判斷
required: true
)
在這一評論中,尤雨溪還解釋了爲何要這麼設計。雖然這樣存在歧義,可是這和null
與undefined
在語言自己中的含義是統一的,若是改變的會形成更多的混亂。
比較贊同尤雨溪的解釋,雖然 JavaScript 語言自己存在必定的設計缺陷,但咱們對這些缺陷表示知道,並不輕易 hack,否則就會出現更多的混淆。與語言自己保持統一是一種更好的方式。
最後,雖然本文標題是《Vue Prop 中的 null vs undefined》,但其中頻繁涉及到了 required 和 default 這兩個概念。因此想借此機會和你們一塊兒明確一下 Vue 中這兩個值的具體含義。
required: true
表示要求傳入該屬性,即 template 中要有該屬性。只要有,無論值是什麼,均可校驗經過(沒經過是類型校驗的事情)。undefined
時生效,不論是由於沒有傳入屬性仍是屬性的值就是undefined
。因此當你但願觸發默認值的時候,必定要使用undefined
。