在JavaScript中,null和undefined之间有什么区别?

1645
在JavaScript中,nullundefined有什么区别?

32
我一直认为:null 表示你有意将其设置为空,而 undefined 是因为没有被设置而为空。或者说 null 是故意设置为空,而 undefined 则仍然为空。基本上这展示了意图。 - Muhammad Umer
64
看看这个。console.log(null-undefined)。null和undefined的区别是NaN。(请注意,这是一次幽默尝试,不要因为误解问题而批评我。) - Ivan
了解undefined及其与作用域的关系 https://codepen.io/grumpy/post/undefined-scope-in-javascript - AL-zami
1
值得一提的是,尽管“null”的发明者Tony Hoare称其为他的“十亿美元错误”,JavaScript却愉快地将这个错误乘以了2。祝你调试愉快! - Chris Collett
显示剩余5条评论
39个回答

1561

undefined表示一个变量已被声明但尚未被赋值:

var testVar;
console.log(testVar); //shows undefined
console.log(typeof testVar); //shows undefined

null是一种赋值值。它可以分配给变量,作为没有值的表示:

var testVar = null;
console.log(testVar); //shows null
console.log(typeof testVar); //shows object

从上面的例子可以清楚地看出,undefinednull 是两种不同的类型:undefined 是一种类型本身(未定义),而 null 是一个对象。

证明:

console.log(null === undefined) // false (not the same type)
console.log(null == undefined) // true (but the "same value")
console.log(null === null) // true (both type and value are the same)

null = 'value' // Uncaught SyntaxError: invalid assignment left-hand side
undefined = 'value' // 'value'

451
在《Professional JS For Web Developers (Wrox)》一书中有这样一句话:"您可能会想知道为什么 typeof 运算符返回 null 值的类型为 'object'。实际上,这是 JavaScript 最初实现时的错误,然后被 ECMAScript 复制了。如今,理论上,null 被视为对象的占位符,尽管从技术上讲它是一种原始值。" - Captain Sensible
53
该变量完全可以不定义。例如: console.log(typeof(abc)); undefined - Nir O.
28
来自Nir O.的评论非常重要。如果我想要一个一开始没有值的变量,我会写"... = null",例如"myvar = null"。这样,当我误键"if (myxar == null) {...}"时,if块不会被执行。但是,对于undefined,我就没有这个优势:myvar = undefined; myvar = 4; if (typeof myxar == "undefined") {...}。 - Wolfgang Adamec
19
@Wolfgang Adamec,无错误编程不仅仅是关于打错字。 - Jorge Fuentes González
17
基本上,null值表示变量已明确设置为(无值 = null)或已初始化并定义为空。而未定义则意味着它可能从未被初始化过,或者如果它曾经被初始化过,那么它从未被定义过。 - Muhammad Umer
显示剩余17条评论

701

这种差异可以用马桶纸架来解释:

  • 非零值就像是一个装有卷筒马桶纸的架子,且还有纸留在卷筒上。

  • 零值就像是一个空的马桶纸筒放在架子上。

  • Null 值就像是一个甚至没有纸筒的架子。

  • 未定义的值类似于架子本身丢失了。


19
请您包含图片来源的归属声明。 - Vega
11
很抱歉,我不记得这是从哪里得到的,除了知道它可能来自imgur.com上的一个转发,而不是原始来源。甚至这里嵌入的链接也没有任何提示是谁发布了这个版本,所以我也无法进行搜索。 - Sebastian Norr
54
“我不记得这个信息是从哪里得到的,除了在imgur.com的某个地方以外。” -> 那么在这种情况下它是 undefined 还是 null - Erowlin
103
let toiletPaperIn2020 = undefined; 可以翻译为:在2020年,厕纸的数量未定义。 - Rain
10
如果 holder 代表变量,那么 undefined 不能是一个空的容器。在这种表示中,undefined 是一个空的容器,而 null 是带有“空”便利贴的空容器(为了让不幸的用户知道向清洁女工要厕纸是毫无意义的)。这也解释了为什么很多开发人员感到困惑:我应该在未初始化的变量上贴上“空”便利贴,还是每个人都会理解“空”意味着真正的?例如,缺乏卫生纸是故意的还是不经意的? - Stefaan Vandevelde
显示剩余6条评论

89

这段内容是从这里获取的。

未定义(undefined)是一种原始值,当变量没有被赋值时使用。

空值(null)是一种原始值,表示空、不存在或未设置引用。

当你通过var声明一个变量但不给它赋值时,它的值为undefined。单独使用这个值时,如果尝试WScript.Echo()或alert(),将看不到任何东西。然而,如果给它附加一个空字符串,它就会出现:

var s;
WScript.Echo(s);
WScript.Echo("" + s);

你可以声明一个变量,将其设置为null,此时的行为与将其设置为undefined相同,只是你会看到打印出来的值是"null"而不是"undefined"。这确实是一个小差异。

你甚至可以比较一个未定义的变量和null或相反的情况,条件会被判定为真:

undefined == null
null == undefined

然而,它们被认为是两种不同的类型。虽然undefined是一个独立的类型,但null被认为是一种特殊的对象值。您可以通过使用typeof()函数来查看这一点,该函数返回表示变量通用类型的字符串:

var a;
WScript.Echo(typeof(a));
var b = null;
WScript.Echo(typeof(b));

运行上述脚本将产生以下输出:

undefined
object
无论它们是不同类型的,如果您尝试访问任何一个成员,它们都会表现相同,即抛出异常。在WSH中,您将看到可怕的“'varname'为null或不是对象”,这还算幸运(但这是另一篇文章的主题)。
您可以明确地将变量设置为undefined,但我强烈建议您不要这样做。我建议仅将变量设置为null,并将未定义的值留给您忘记设置的变量。同时,我真的鼓励您始终设置每个变量。 JavaScript具有与C风格语言不同的作用域链,即使是经验丰富的程序员也很容易混淆,并且将变量设置为null是防止基于此出现错误的最佳方法。
另一个您将看到undefined出现的情况是使用delete运算符时。我们从C世界来的人可能会错误地将其解释为销毁对象,但实际上并非如此。此操作的作用是从数组中删除下标或从对象中删除成员。对于数组,它不会影响长度,而是将该下标视为undefined。
var a = [ 'a', 'b', 'c' ];
delete a[1];
for (var i = 0; i < a.length; i++)
WScript.Echo((i+".) "+a[i]);
上述脚本的结果是:
0.) a
1.) undefined
2.) c

当尝试读取一个不存在的下标或成员时,你也会得到 undefined 的返回值。

null 和 undefined 的区别在于:JavaScript 永远不会将任何东西设置为 null,通常我们自己这样做。虽然我们可以将变量设置为 undefined,但我们更喜欢 null,因为它不是 JavaScript 自动设置的值。在调试时,这意味着任何设置为 null 的东西都是你自己设置的,而不是由 JavaScript 设置的。除此之外,这两个特殊值几乎是相等的。


9
确实是个好答案。但是需要指出的是,当你检查 "undefined == null" 时,类型检查不是严格的,因此它返回了 "true"。如果你检查 "undefined === null",它会返回 false。 - wOlVeRiNe
4
值得注意的是,虽然这个评论在2011年是正确的,但随着可选函数参数的出现、类型检查系统(如Flow)的出现以及React的普及(所有这些都对undefined和null有不同的处理方式),通常使用null而不是undefined的旧智慧不再那么严格适用。在许多情况下,如果您想明确使用默认值(例如对于可选参数或可选的React属性),undefined实际上比null更可取。 - 0x24a537r9
在我看来,最好不要使用null,而是优先使用undefined。 - Michael Freidgeim

67
请仔细阅读以下内容。它应该能够解除你对JavaScript中nullundefined之间区别的所有疑惑。此外,你可以使用本答案末尾的实用函数获取更具体类型的变量。
在JavaScript中,我们可以有以下类型的变量:
1. 未声明的变量 2. 声明但未赋值的变量 3. 赋值为字面量undefined的变量 4. 赋值为字面量null的变量 5. 赋值为除undefinednull以外的任何其他东西的变量
以下逐一解释每种情况:
1. 未声明的变量 - 只能使用typeof运算符检查,它返回字符串'undefined' - 无法使用松散等式运算符(== undefined),更不用说严格等式运算符(=== undefined), 以及if语句三元运算符? :)——这些会抛出引用错误。
2. 声明但未赋值的变量 - typeof 返回字符串'undefined' - 使用null检查的==返回true - 使用undefined检查的==返回true - 使用null检查的===返回false - 使用undefined检查的===返回true - 对if语句三元运算符? :)为falsy 3. 赋值为字面量undefined的变量 - 这些变量与声明但未赋值的变量完全相同。
4. 赋值为字面量null的变量
  • typeof 返回字符串 'object'
  • ==null 比较返回 true
  • ==undefined 比较返回 true
  • ===null 比较返回 true
  • ===undefined 比较返回 false
  • if语句三元运算符(? :)中被认为是falsy
变量赋值除了 undefinednull 之外,
  • typeof 返回下列字符串之一: 'bigint', 'boolean', 'function', 'number', 'object', 'string', 'symbol'
以下是正确检查变量类型的算法:
  1. 获得我们变量的 typeof 并返回该值,如果它不是 'object'
  2. 检查 null,因为typeof null 也会返回 'object'
  3. 使用 switch 语句评估 Object.prototype.toString.call(o),以返回更精确的值。对于本机/宿主对象,ObjecttoString 方法返回类似于'[object ConstructorName]'的字符串。对于所有其他对象(用户定义的对象),它始终返回'[object Object]'
  4. 如果最后一个部分是这种情况(变量的字符串版本为'[object Object]'),并且参数returnConstructorBooleantrue,它将尝试通过 toString提取构造函数的名称来获取它的名称。如果无法访问构造函数,则像往常一样返回'object'。如果字符串不包含其名称,则返回'anonymous'

(支持 ECMAScript 2020 的所有类型)

function TypeOf(o, returnConstructorBoolean) {
  const type = typeof o

  if (type !== 'object') return type
  if (o === null)        return 'null'

  const toString = Object.prototype.toString.call(o)

  switch (toString) {
    // Value types: 6
    case '[object BigInt]':            return 'bigint'
    case '[object Boolean]':           return 'boolean'
    case '[object Date]':              return 'date'
    case '[object Number]':            return 'number'
    case '[object String]':            return 'string'
    case '[object Symbol]':            return 'symbol'

    // Error types: 7
    case '[object Error]':             return 'error'
    case '[object EvalError]':         return 'evalerror'
    case '[object RangeError]':        return 'rangeerror'
    case '[object ReferenceError]':    return 'referenceerror'
    case '[object SyntaxError]':       return 'syntaxerror'
    case '[object TypeError]':         return 'typeerror'
    case '[object URIError]':          return 'urierror'

    // Indexed Collection and Helper types: 13
    case '[object Array]':             return 'array'
    case '[object Int8Array]':         return 'int8array'
    case '[object Uint8Array]':        return 'uint8array'
    case '[object Uint8ClampedArray]': return 'uint8clampedarray'
    case '[object Int16Array]':        return 'int16array'
    case '[object Uint16Array]':       return 'uint16array'
    case '[object Int32Array]':        return 'int32array'
    case '[object Uint32Array]':       return 'uint32array'
    case '[object Float32Array]':      return 'float32array'
    case '[object Float64Array]':      return 'float64array'
    case '[object ArrayBuffer]':       return 'arraybuffer'
    case '[object SharedArrayBuffer]': return 'sharedarraybuffer'
    case '[object DataView]':          return 'dataview'

    // Keyed Collection types: 2
    case '[object Map]':               return 'map'
    case '[object WeakMap]':           return 'weakmap'

    // Set types: 2
    case '[object Set]':               return 'set'
    case '[object WeakSet]':           return 'weakset'

    // Operation types: 3
    case '[object RegExp]':            return 'regexp'
    case '[object Proxy]':             return 'proxy'
    case '[object Promise]':           return 'promise'

    // Plain objects
    case '[object Object]':
      if (!returnConstructorBoolean)
        return type

      const _prototype = Object.getPrototypeOf(o)
      if (!_prototype)              
        return type

      const _constructor = _prototype.constructor
      if (!_constructor)            
        return type

      const matches = Function.prototype.toString.call(_constructor).match(/^function\s*([^\s(]+)/)
        return matches ? matches[1] : 'anonymous'

    default: return toString.split(' ')[1].slice(0, -1)
  }
}

43

null是一个特殊的关键字,表示值的缺失。

可以将其视为一种值,例如:

  • "foo" 是字符串,
  • true 是布尔值,
  • 1234 是数字,
  • null 是未定义的。

undefined 属性表示变量未被赋值,包括 null 。

var foo;

定义的空变量是数据类型为undefinednull


它们都代表一个没有值的变量

并且null不代表没有值的字符串,即空字符串。


例如:

var a = ''; 
console.log(typeof a); // string 
console.log(a == null); //false 
console.log(a == undefined); // false 

现在,如果

var a;
console.log(a == null); //true
console.log(a == undefined); //true 

但是

var a; 
console.log(a === null); //false 
console.log(a === undefined); // true

因此每个人都有自己使用的方式

undefined用于比较变量的数据类型

null用于清空变量的值

var a = 'javascript';
a = null ; // will change the type of variable "a" from string to object 

2
null也是一种数据类型。undefined和null都是数据类型和值。 - danwellman
15
“null”绝对是一种数据类型:msdn.microsoft.com/en-us/library/ie/7wkd9z69(v=vs.94).aspx 。虽然typeof null返回“对象”,但这实际上是早期ECMAScript版本中已知并记录的一个bug,为了保持向后兼容性而保留至今。您在评论中实际发布的链接在页面中间部分就指出了:“typeof null // object (bug in ECMAScript, should be null)”!因此,在对下降票进行评论之前,请显示一些搜索努力。 - danwellman
2
定义相互矛盾:“没有值”与“尚未分配值”。这不是一样的吗? - Zon
4
我不同意这个答案。null和undefined是两种不同的数据类型。null是空值类型,而undefined是未定义类型。只有在使用真值运算符(==)时,我们才会看到JavaScript说它是true,但是严格比较运算符(===)会产生false。 - alaboudi
1
直到今天,“null is undefined”仍然是错误的。 - Sebastian Simon

27

null:变量的值不存在;undefined:变量本身不存在。

..其中变量是与一个值相关的符号名称。

虽然JavaScript可以很友善地使用null隐式初始化新声明的变量,但它并没有这样做。


34
var a = {}; a.n = undefined;' then ..a.hasOwnProperty('n') == true` ...所以说 变量本身的缺失 不再正确。 - Muhammad Umer
这是一个非常简洁的定义,但它并不准确 - 因为你提到的原因。一个已定义的变量以值 undefined 开始。 - Steve Bennett
即使这个答案发布了这么多年,我认为我同意这个答案。undefined的意图是变量不存在,而null的意图是变量存在但没有值。人们通过检查变量的typeof进入实现特定的细节,但错过了理解计算机科学中最强大的术语之一——“抽象”。 - Aman Godara

17

理解它们之间的区别最好的方法是先把JavaScript内部的工作原理澄清,只需了解以下术语的含义即可:

let supervisor = "None"
    // I have a supervisor named "None"

let supervisor = null
    // I do NOT have a supervisor. It is a FACT that I do not.

let supervisor = undefined
    // I may or may not have a supervisor. I either don't know
    // if I do or not, or I am choosing not to tell you. It is
    // irrelevant or none of your business.

这三种情况有不同的含义,JavaScript使用nullundefined两个不同的值来区分后两种情况。您可以自由地显式使用这些值来传达这些含义。

那么,由于这一哲学基础,会出现哪些特定于JavaScript的问题呢?

  1. A declared variable without an initializer gets the value undefined because you never said anything about the what the intended value was.

    let supervisor;
    assert(supervisor === undefined);
    
  2. A property of an object that has never been set evaluates to undefined because no one ever said anything about that property.

    const dog = { name: 'Sparky', age: 2 };
    assert(dog.breed === undefined);
    
  3. null and undefined are "similar" to each other because Brendan Eich said so. But they are emphatically not equal to each other.

    assert(null == undefined);
    assert(null !== undefined);
    
  4. null and undefined thankfully have different types. null belongs to the type Null and undefined to the type Undefined. This is in the spec, but you would never know this because of the typeof weirdness which I will not repeat here.

  5. A function reaching the end of its body without an explicit return statement returns undefined since you don't know anything about what it returned.

顺便提一下,在JavaScript中还有其他形式的 "nothingness"(学过哲学很有好处....)

  • NaN
  • Using a variable that has never been declared and receiving a ReferenceError
  • Using a let or const defined local variable in its temporal dead zone and receiving a ReferenceError
  • Empty cells in sparse arrays. Yes these are not even undefined although they compare === to undefined.

    $ node
    > const a = [1, undefined, 2]
    > const b = [1, , 2]
    > a
    [ 1, undefined, 2 ]
    > b
    [ 1, <1 empty item>, 2 ]
    

最佳答案!大多数答案忽略了一个事实,即您可以将变量的值定义为“undefined”,就像在let supervisor = undefined的情况下一样。 - J. Bruni
谢谢,没错,那个误解认为只有未声明或未被赋值的变量才是 undefined,是相当流行的,而且真的很难向人们解释清楚(虽然我一直在努力)。很多人因JavaScript同时拥有nullundefined这两个值而对它进行了诟病,但是这些值确实有完全不同的含义,并且大部分时候它们都能很好地使用其预定的含义(当然这是我的看法)。 - Ray Toal

17

你可能认为undefined表示系统级别的意外或错误缺失值,而null表示程序级别的正常或预期缺失值。

via JavaScript:权威指南


我真的很喜欢这个描述。 - aradalvand
这也是我认为我要使用的。如果我收到一个null,我知道这个值是有意设置为null的。 - Stevenfowler16

17
许多“技术性”答案已经给出,它们大多从JS作为一种编程语言的有限角度来看都是正确的。然而,我想补充以下想法,尤其是在你将TypeScript代码作为更大项目/(企业)应用程序的一部分编写时: - 当与某种后端通信时,你很可能会收到JSON。 - 虽然一些后端正确地避免在其JSON中使用“null”(删除这些属性),但其他人则不这样做。 - 现在,“null”可能意味着故意缺少该值,但更常见的情况是它没有传达这个意思。 大多数数据库之所以使用“null”只是因为它们没有“未定义”类型。 但实际上含义就是“未定义”。 - 因此,您永远无法知道“null”值是否真正意味着有意的缺失。 因此,“null”实际上不能表示“缺失值”的有意选择。 它在一般情况下是无法判断的。 - 因此,在实践中,“null”和“undefined”在语义上是完全相同的。因此,为了协调一切,我严格反对在代码中使用“null”,并鼓励您停止使用“null”。这比你想象的要容易得多。别误会我的意思。我不是说不处理“null”值,而是要避免在代码中明确地使用它们。换句话说:您的代码仍应能够处理来自应用程序外部(例如通过第三方库如Angular或第三方后端)的意外传递的“null”值。 以下是使其成为可能的准则: - 避免直接使用未定义类型的守卫(例如 if (value === undefined) { ... }) - 相反,使用间接类型守卫(也称为真值检查),例如if (value) { ... } - 每当0或空字符串具有意义时,请使用以下方法之一 - 使用显式帮助程序方法,例如Lodash的isNil,或在比较中包含有意义的值(例如if (!value && value !== 0) { ... }) - 考虑使用lint规则禁止使用null

这是一个有趣的观点,我认为它可以扩展;这就是为什么我发表这个评论的原因。现在C#已经实现了非空类型,如果你愿意这样说的话,就有了一种“进步”,向着我会这样表述的理解方向迈进:如果你请求数据库中没有的键,则返回未定义,因为该键未定义;但如果你请求它拥有的键,则对于任何不为空的值,你返回null —— 在那里你不返回未定义。所以我想知道是否有人注意到了某些趋势或者你们称之为什么? - Steven Coco
2
我完全同意这个观点。更重要的是,我们需要考虑整个生态系统的情况,通常你不能保证你的数据源以与JavaScript编程语言相同的方式区分未知和Null。事实上,这很少发生。因此,您不能假定null是有意的,出于这个原因,您必须对它们进行相同的处理。特别是当我们讨论从多个来源获取数据的程序或者您无法控制数据源的结构时,这一点尤其重要。在这种情况下,JavaScript的实际实现并不重要。 - jdmneon
1
同意 if (value)if (value == null) 更好。但如果函数遇到错误时,它会返回什么而不是一个对象呢?我认为 return null 是显而易见的选择,但在这种情况下,“停止在代码中使用‘null’”的建议并不清楚你在暗示什么。 - Nagev
@Nagev:你需要决定是要在函数中直接处理错误,还是让调用者处理。后者可以通过使函数实际抛出一个错误来轻松完成。前者可以通过仍然返回某种对象(可能只有默认值、空或未定义属性)来完成。或者,您可以只返回undefined,并将其作为除对象之外的有效返回值(例如,考虑TS签名(): YourType | undefined)。然后,调用者可以通过简单的真值检查if (...) {}轻松跳过undefined - NicBright
它们都是不错的选择,感谢澄清。我想这只是个人偏好的问题(除非当然由代码库或团队约定规定)。就个人而言,我喜欢尽量少地抛出异常,因为我觉得在每个东西中包装try ... catch很烦人。在许多情况下,返回自定义对象可能过于复杂。而且if (...)测试对于undefinednull同样适用,由于后者实际上是一个对象,所以当对象是返回类型时,使用null是有意义的。该函数的含义是:抱歉,无法给您想要的对象,这里提供null代替。 - Nagev
显示剩余2条评论

15

null是一种特殊的值,表示"没有值"。 null是一个特殊的对象,因为typeof null返回'object'。

另一方面,undefined意味着变量未被声明或未被赋值。


3
需要注意的是,虽然undefined可能意味着一个变量没有被声明,但并不能保证如此。一个变量可以被声明为var thing;,它将等于undefined - Yura

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接