前言:本文将引入两个 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
。