『 Vue小Case 』- Vue Prop中的 null vs undefined

前言:本文將引入兩個 Vue 中比較特殊的使用場景,帶領你們熟悉一下nullundefined的區別,而後再分析一下 Vue 中是怎麼對 Props 作校驗的,最後給出大佬是怎麼解釋的。html

一直以來,筆者在使用 Vue 時,習慣於在須要表示 prop 屬性未定義時,使用undefined,而不是null。由於「undefined纔是沒有值,null是有值,可是值爲空的對象(注意不是空對象{}」。vue

基於這一習慣,筆者規避掉了不少問題,對此也沒有深究。git

直到最近,參與項目的一些同窗習慣於指定null爲初始值,我也沒有強制性統一。根本緣由是,我本身也以爲沒什麼,每一個人都有本身的習慣,只要大的風格不出誤差就能夠接受,畢竟項目緊嘛。github

直到今天遇到了下面的場景,我才發現,原來這麼作會有一些奇怪的小問題。瀏覽器

1、場景再現

1.1 場景一:prop 的值是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生效了。

1.2 場景二:prop 設置了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,你會發現依然行不通,會有相似的錯誤。

好了,至此,咱們已經看完了我所想展現的示例。能夠總結爲如下兩個疑問:

  1. 當值爲null的時候,爲何default中定義的值沒有生效?(顯然,當值爲 undefined 的時候,默認值是會生效的)
  2. 當值爲null/undefined的時候,爲何required: ture的校驗彷佛經過了,可是類型校驗反倒沒有經過?(顯然,required: false的時候,nullundefined是都能經過類型校驗的。這點文檔中有提到。)

在詳細解釋爲何以前,咱們先來熟悉下一個歷史悠久的問題:「nullundefined的區別是什麼?」

2、null 和 undefined 的區別

在設計之初,JavaScript 是這樣區分的:null是一個表示"無"的對象,轉爲數值時爲0undefined是一個表示"無"的原始值,轉爲數值時爲NaN

Number(null) // 0 5 + null // 5 複製代碼Number(undefined) // NaN 5 + undefined // NaN

不得不吐槽,真是坑呀

但後來被證實這並不可行。目前,nullundefined基本是同義的,只有一些細微的差異。

null表示沒有對象,即此處不該該有值。雖然其表示不該該有值,但它是有值的,值是一個空的對象(注意不是{})。用法以下:

  1. 做爲函數的參數,表示該函數的參數不是對象。
  2. 做爲對象原型鏈的終點。
Object.getPrototypeOf(Object.prototype)
// null
複製代碼

undefined表示缺乏值,就是此處應該有一個值,可是尚未定義

  1. 變量被聲明瞭,但沒有賦值時,就等於undefined
  2. 調用函數時,應該提供的參數沒有提供,該參數等於undefined
  3. 對象沒有賦值的屬性,該屬性的值爲undefined
  4. 函數沒有返回值時,默認返回undefined

var i; i // undefined

function f(x){console.log(x)} f() // undefined

var obj = new Object(); obj.p // undefined

複製代碼var ret = f(); ret // undefined

3、Vue 中的 Prop 校驗

好了,咱們已經再次熟悉了一下nullundefined的區別。下面就讓咱們一塊兒看下,Vue 中是如何進行 Prop 校驗以及如何對待nullundefined

筆者閱讀了 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時,nullundefined都會經過校驗。其餘狀況,則都會進行類型校驗。這解釋了第一部分兩個奇怪現象的第二個。

代碼片斷以下:

// 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 源碼中的邏輯解釋了爲何會出現第一部分中的奇怪現象。但可能仍是沒有理解爲何。下面咱們繼續來看一下大佬們的解釋。

4、大佬們的解釋

引用一下尤雨溪在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 neither null or undefined are allowed (unless a default is used)

required: true表示在 default 沒有應用的狀況下,nullundefined都不容許。

注意:還有一個小前提,就是給屬性指定了類型

(此外,這句話隱式包含了 required 和 default 是能夠共存的,先應用 default,再判斷required: true

在這一評論中,尤雨溪還解釋了爲何要這麼設計。雖然這樣存在歧義,可是這和nullundefined在語言自己中的含義是統一的,若是改變的會形成更多的混亂。

5、總結

比較贊同尤雨溪的解釋,雖然 JavaScript 語言自己存在必定的設計缺陷,但咱們對這些缺陷表示知道,並不輕易 hack,否則就會出現更多的混淆。與語言自己保持統一是一種更好的方式。

最後,雖然本文標題是《Vue Prop 中的 null vs undefined》,但其中頻繁涉及到了 required 和 default 這兩個概念。因此想借此機會和你們一塊兒明確一下 Vue 中這兩個值的具體含義。

  1. required: true表示要求傳入該屬性,即 template 中要有該屬性。只要有,無論值是什麼,均可校驗經過(沒經過是類型校驗的事情)。
  2. default 會在 value 值爲undefined時生效,不論是由於沒有傳入屬性仍是屬性的值就是undefined。因此當你但願觸發默認值的時候,必定要使用undefined

參考連接

  1. undefined 與 null 的區別
  2. 「Vue Issue #7720」- Vue warns about missing required prop that has a default value
  3. 「Vue Issue #6768」- No warning when string property value is null 
  4. Vue Prop 校驗源碼

相關文章
相關標籤/搜索