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

本文会同步发布在微信公众号歪码行空,欢迎关注交流~!html

前言:本文将引入两个Vue中比较特殊的使用场景,带领你们熟悉一下nullundefined的区别,而后再分析一下Vue中是怎么对Props作校验的,最后给出大佬是怎么解释的。vue

一直以来,笔者在使用Vue时,习惯于在须要表示prop属性未定义时,使用undefined,而不是null。由于“undefined才是没有值,null是有值,可是值为空的对象(注意不是空对象{}”。git

基于这一习惯,笔者规避掉了不少问题,对此也没有深究。github

直到最近,参与项目的一些同窗习惯于指定null为初始值,我也没有强制性统一。根本缘由是,我本身也以为没什么,每一个人都有本身的习惯,只要大的风格不出误差就能够接受,毕竟项目紧嘛。浏览器

直到今天遇到了下面的场景,我才发现,原来这么作会有一些奇怪的小问题。微信

1、场景再现

1.1 场景一:prop的值是null,会使用default的值吗?

阅读如下代码,你以为有问题吗?app

HTML:less

<div id="app">
  <list :items="null"></list>
</div>
复制代码

JS:函数

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。学习

好,咱们来看下示例代码,这段代码执行以后会报错(记得开启控制台查看错误,由于是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校验源码
相关文章
相关标签/搜索