总的来说 null和 undefined都代表空,主要区别在于 undefined表示尚未初始化的变量的值,而 null表示该变量有意缺少对象指向。
undefined这个变量从根本上就没有定义隐藏式 空值null这个值虽然定义了,但它并未指向任何内存中的对象声明式 空值MDN 中给出的定义null
值 null是一个字面量,不像 undefined,它不是全局对象的一个属性。null是表示缺少的标识,指示变量未指向任何对象。把 null作为尚未创建的对象,也许更好理解。在 API 中,null常在返回类型应是一个对象,但没有关联的值的地方使用。
undefinedundefined是 全局对象的一个属性。也就是说,它是全局作用域的一个变量。undefined的最初值就是原始数据类型 undefined。
一张神奇的图片接下来我们看一张比较经典的图片,该图来自 stackoverflow 的回答,本人没有找到准确的出处。
表现形式在更深入理解 null和 undefined的区别前,我们首先要知道 null和 undefined在 JS中有什么不同的表现形式,用以方便我们更好的理解 null和 undefined的区别。
typeoftypeofnull//objecttypeofundefined//undefinedObject.prototype.toString.call
typeofnull//[object Null]typeofundefined//[object Undefined]== 与 ===
null==undefined//truenull===undefined//false!!null===!!undefined//trueObject.getPrototypeOf(Object.prototype)
JavaScript中第一个对象的原型指向 null。
Object.getPrototypeOf(Object.prototype) // null+ 运算 与 Number()
leta = undefined+ 1// NaNletb = null+ 1// 1Number(undefined) // NaNNumber(null) // 0JSON
JSON.stringify({a: undefined}) // {}JSON.stringify({b: null}) // {b: null}JSON.stringify({a: undefined, b: null}) // {b: null}let undefiend = test
functiontest(n) { letundefined= testreturnn === undefined} test() // falsetest(undefined) // falsetest(test) // tureletundefined= test// Uncaught SyntaxError: Identifier undefined has already been declared深入探索
为什么 typeof null 是 object?
typeof null输出为 object其实是一个底层的错误,但直到现阶段都无法被修复。
原因是,在 JavaScript初始版本中,值以 32位存储。前 3位表示数据类型的标记,其余位则是值。
对于所有的对象,它的前 3位都以 000作为类型标记位。在 JavaScript早期版本中, null被认为是一个特殊的值,用来对应 C中的 空指针。但 JavaScript中没有 C中的指针,所以 null意味着什么都没有或者 void并以 全0(32个)表示。
因此每当 JavaScript读取 null时,它前端的 3位将它视为 对象类型,这也是为什么 typeof null返回 object的原因。
为什么 Object.prototype.toString.call(null) 输出 [object Null]toString()是 Object的原型方法,调用该方法,默认返回当前对象的 [[Class]]。这是一个内部属性,其格式为 [object Xxx],其中 Xxx就是对象的类型。
JavaScript 万物皆对象,为什么 xxx.toString() 不能返回变量类型?这是因为 各个类中重写了 toString的方法,因此需要调用 Object中的 toString方法,必须使用 toString.call()的方式调用。
对于 Object对象,直接调用 toString()就能返回 [object Object]。而对于其他对象,则需要通过 call / apply来调用才能返回正确的类型信息。
为什么 == 和 === 对比会出现 true 和 false ?很多文章说:undefined的布尔值是 false, null的布尔值也是 false,所以它们在比较时都转化为了 false,所以 undefined == null。
实际上并不是这样的。
ECMA在 11.9.3章节中明确告诉我们:
If xis
null
and yisundefined
, returntrue
.If xis
undefined
and yisnull
, returntrue
.
这是 JavaScript底层的内容了,至于更深入的内容,如果有兴趣可以扒一扒 JavaScript的源码。
为什么null + 1和undefined + 1表现不同?这涉及到 JavaScript中的隐式类型转换,在执行 加法运算前,隐士类型转换会尝试将表达式中的变量转换为 number类型。如:1 + 1会得到结果 11。
null转化为 number时,会转换成 0undefined转换为 number时,会转换为 NaN至于为什么执行如此的转换方式,我猜测是 JavaScript早期的一个糟糕设计。
从语言学的角度来看:
null意味着一个明确的没有指向的空值,而 undefined则意味着一个未知的值。
在某种程度上, 0意味着数字空值。
这虽然看起来有些牵强,但是我在这一阶段能所最能想到的可能了。
为什么 JSON.stringify 会将值为 undefined 的内容删除?其实这条没有很好的解释方式, JSON会将 undefined对应的 key 删除,这是 JSON自身的转换原则。
在 undefined的情况下,有无该条数据是没有区别的,因为他们在表现形式上并无不同:
letobj1 = { a: undefined} letobj2 = {} console.log(obj1.a) // undefinedconsole.log(obj2.a) // undefined
但需要注意的是,你可能在调用接口时,需要对 JSON格式的数据中的 undefied进行特殊处理。
为什么 let undefiend = test 可以覆盖掉 JavaScript 自身的 undefined?JavaScript对于 undefined的限制方式为全局创建了一个只读的 undefined,但是并没有彻底禁止局部 undefined变量的定义。
据说在 JavaScript高版本禁止了该操作,但我没有准确的依据。
请在任何时候,都不要进行 undefined变量的覆盖,就算是你的 JSON转换将 undefined转换为 。也不要通过该操作进行,这将是及其危险的行为。
总结关于使用 undefined 还是 null
这是一条公说公有理婆说婆有理的争议内容。
本人更倾向于使用 null,因为这是显示定义空值的方式。我并不能给出准确的理由。
但关于使用 undefined我有一条建议:
如果你需要使用 undefined定义空值,请不要采取以下两种方式:
let a;let a = undefined;进而采取下面这种方式显式声明 undefined:
let a = void 0;结语终于将 undefined和 null的基本区别搞定了。