在JavaScript中,为什么要使用null而不是undefined?

168

我已经写了相当长时间的JavaScript,但我从未有理由使用null。似乎在编程中undefined始终更可取并具有相同的作用。那么使用null而不是undefined的一些实际原因是什么?


这可能是 https://dev59.com/yXRB5IYBdhLWcg3w77kn 的重复问题。 - lawnsea
有一些方法,比如document.getElementById()可以返回null但不是undefined,所以在这些情况下,为什么要测试返回值是否为undefined呢?(当然,如果你使用==而不是===,它也可以工作,但是,你为什么要故意测试错误的东西呢?) - nnnnnn
具有可预测的类型可以帮助我们更好地思考何时使用哪种类型。当对象始终按设计返回、所需或所想时,请使用 null 来表示假值结果(例如 document.getElementById('does-not-exist'))。变量 var a; 和函数返回值默认为 undefined。过去,null 在全局范围内,因此使用它会减慢执行速度,并导致我更喜欢其他假值类型(false、''、0)来释放引用。个人而言,除非有充分的理由,否则我会避免使用 null,因为我认为这样更简单,通常更好。 - jimmont
21个回答

115

我其实没有一个确切的答案,不过根据 Nicholas C. Zakas 在他的书籍"Web前端开发专业JavaScript"第30页所述:

当定义一个变量来保存对象时,建议将该变量初始化为null而不是其他任何值。这样,您可以明确检查值null以确定在稍后的时间点该变量是否已被填充了对象引用。


15
+1,我同意并且经常尝试记得将变量初始化为null。这样我(相当)确定undefined表示发生了灾难。仅代表个人看法。 - Pete Wilson
13
@Pete - 但它并没有告诉你有关“灾难”的任何信息,那意义何在呢?而且只有当你知道该函数遵循惯例时,才能做出这种假设。 - RobG
15
另一方面,你也可以使用 var myVar; 初始化变量,并显式地检查值是否为 undefined 以确定它是否在稍后填充了对象引用。我的观点是这完全是学术性的 -- 你可以两种方式都做,任何建议采用其中之一的人只是在推广自己的习惯而已。 - thdoan
7
这是唯一一个适用于 == 比较符(而非 ===)的情况:v == null(或 v == undefined)将检查是否为null或undefined。 - Rick Love
1
在 TypeScript 中,null 很烦人。 - Oscar Gardiazabal
显示剩余3条评论

102

归根结底,因为nullundefined强制转换为相同的值(Boolean(undefined) === false && Boolean(null) === false),因此您可以技术上使用任何一个来完成工作。但是,在我看来还是有正确的方法。

  1. 让JavaScript编译器处理undefined的使用。

    undefined用于描述不指向引用的变量。这是JS编译器会为您处理的内容。在编译时,JS引擎将所有提升变量的值设置为undefined。随着引擎遍历代码并且值变得可用,引擎将分配相应的值给相应的变量。对于那些没有找到值的变量,变量将继续保持对原始类型undefined的引用。

  2. 仅在明确要表示变量值为“无值”时使用null

    如@com2gz所述:null用于定义编程上空的东西。 undefined用于表示引用不存在。 null值具有对“nothing”的定义引用。如果您调用对象的不存在属性,则会获得undefined。如果我故意将该属性设置为空,则必须使用null以便您知道这是有意的。

简而言之:不要使用undefined原始类型。当你声��变量而没有赋值或者尝试访问对象无引用的属性时,JS编译器会自动为其设置一个值。另一方面,只有在有意让变量具有“无值”时才使用null


附注:个人而言,我避免将任何东西明确设置为undefined(在我与许多代码库/第三方库的交互中,我也没有遇到过这种模式)。此外,我很少使用null。我仅在想表示该函数参数值为无值时使用null,如下所示:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello

15
这应该是被选中的答案。 - alaboudi
7
多年来,我一直只使用“未定义(undefined)”,并假装“null”不存在,但现在我开始倾向于类似这个答案的东西。 - Dave Cousineau
在高使用率的应用程序中,当您想要清除内存时,应该使用哪个? - strix25

80

nullundefined本质上是两个表示相同含义的不同值。唯一的区别在于在你的系统中使用它们的约定方式不同。有些人使用null来表示“没有对象”,而在预期没有对象(或者出现错误)时则使用undefined。我的问题是这完全是任意的,也是完全没有必要的。

尽管如此,还是有一个重要的区别 - 未初始化的变量(包括函数参数,在其中没有传递任何参数等)始终是undefined

这就是为什么在我的代码中我永远不使用null,除非我无法控制某些返回null的东西(例如正则表达式匹配)。这样做的好处是可以简化很多事情。我从不必检查x === undefined || x === null,我只需要检查x === undefined。如果你习惯于使用==或者像if(x) ... 之类的简单写法,那就停止吧。

!x对于空字符串、0nullNaN等内容将评估为true - 这些可能不是你想要的。如果你想写出不可怕的JavaScript,那么请始终使用三个等号===而不要使用null(改用undefined)。这会让你的生活更轻松。


212
我不同意这个说法。Null用于定义程序上的空值,未定义是指该引用不存在。Null值有一个明确定义的“nothing”引用。如果您调用对象的不存在属性,则会得到undefined。如果我故意使该属性为空,则必须为null,以便您知道这是有意为之的。许多JavaScript库都是按照这种方式工作的。 - com2ghz
15
你所描述的是众多哲学之一。许多JS库确实是以此工作的,但也有许多不是这样的。在JavaScript中,你可以像使用null一样,在对象或数组中存储一个明确的undefined值。两者的含义完全取决于上下文。也就是说,它们意味着你想要的意思。 - B T
4
这就是为什么JS是一种可怕的语言。正如你所说,许多库有自己的哲学,但你在一个项目中包含了许多库。因此,你会遇到这些库的许多惯例。你需要多少次进行不同的假值检查。你可能会不止一次地将一个空对象连接到一个字符串中并得到一个"null"字符串,或者将0作为数字值传递,并想知道为什么IF语句将其视为false。 - com2ghz
4
@com2ghz问:JS是个糟糕的语言,因为它同时拥有null和undefined吗?我可以列举所有主要语言中数十个不好的语言决策,js在这方面也不例外。我从来不需要或想要在我的代码中使用假值检查,我总是使用===!==。如果你知道如何使用JS,它是一种非常富有表现力的语言。回复:JS并非仅因为同时拥有null和undefined而成为糟糕的语言。所有主要语言都会有许多不良的语言设计决策,JS也不例外。笔者从未需要或希望在代码中使用假值检查,而是总是使用===!==。如果您知道如何使用JS,它是一种非常具有表现力的语言。 - B T
7
好的。我刚学到了null/undefined二分法之所以必要,是因为JS的初始版本没有hasOwnPropertyin运算符。现在JS有了这些运算符,我不太理解为什么它们中的一个在ES6或我见过的任何ES7提案中没有被废除。 - Andy
显示剩余17条评论

18

undefined是指在该作用域中没有该事物的概念,它没有类型,且以前未被引用过;null是指已知该事物存在,但没有值。


5
如果尝试分配一个值但失败了,而undefined被分配了,你怎么知道这个情况发生了? - RobG

15

每个人都有自己的编程方式和内部语义,但多年来我发现这是我给那些问这个问题的人最直观的建议:当你不确定时,就按照JavaScript的方式做

比如说,您正在处理对象属性,例如jQuery插件的选项...问问自己,未定义属性的值在JavaScript中是什么--答案是undefined。因此,在这种情况下,我会使用“ undefined”初始化这些类型的东西,以与JavaScript保持一致(对于变量,您可以使用var myVar;而不是var myVar = undefined;)。

现在假设您正在进行DOM操作...JavaScript为不存在的元素赋予什么值?答案是null。如果您正在创建稍后将保存与DOM相关的元素、文档片段或类似物的占位符变量,则应使用此值进行初始化。

如果您正在使用JSON,则需要特殊处理:对于未定义的属性值,您应将它们设置为“”null,因为undefined的值不被认为是正确的JSON格式。

话虽如此,正如先前的帖子所表达的那样,如果您发现您经常使用nullundefined来初始化东西,那么也许您应该重新考虑如何编写应用程序。


虽然这是一个好的立场,但我想补充一下这个答案:https://dev59.com/L1oT5IYBdhLWcg3w8jJm#37980662 - Frederik Krautwald
@FrederikKrautwald,感谢提供链接 - 非常清晰明了的界定。 - thdoan

11

你可以采用这里建议的约定,但实际上没有充分的理由这样做。它没有被一致地使用,因此没有意义。

为了使这个约定有用,你首先必须知道调用的函数是否遵循这个约定。然后你必须显式地测试返回值并决定要做什么。如果你得到了undefined,你可以假设发生了某种错误被调用的函数知道了。但如果发生错误,并且函数知道它,同时将其发送到更广泛的环境中是有用的,那么为什么不使用错误对象呢?也就是说,抛出一个错误?

所以说,最终这个约定在除非是非常简单的环境中的非常小的程序中,几乎没有任何作用。


7
有些人说初试化对象为null是可以的,但我想指出的是使用 null 时解构参数默认值将不起作用。例如:
const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

这需要在调用函数之前执行null检查,这可能经常发生。


1
这是我在代码库中不使用 null 的几个原因之一。通常你会在函数内看到类似于 arg || defaultValue 的东西,如果你可以提供一个默认参数,那么 undefined 就有了更好的价值...同时也能减少代码量。 - Endless
不错,我想这与这篇文章相似https://medium.com/@hbarcelos/why-i-banned-null-from-my-js-code-and-why-you-should-too-13df90323cfa - Antoni4

3
“null”中具有的一个有用属性,而“undefined”不具备资格:
> null + 3
3
> undefined + 3
NaN

当我想要“关闭”数字值或初始化一些内容时,我会使用null。我最后一次使用它是操作CSS变换:
const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

不确定是否应该使用这个属性...

3

未知变量:undefined

已知变量但无值:null

  1. 您从服务器接收一个对象,server_object
  2. 您引用server_object.errj。它告诉您它是undefined。这意味着它不知道那是什么。
  3. 现在您引用server_object.err。它告诉您它是null。这意味着您正在引用一个正确的变量,但它是空的;因此没有错误。

问题在于当您声明一个没有值的变量名(var hello)时,js将其声明为undefined:这个变量不存在;而大多数程序员的意思是:“我还没有给它一个值”,这是null的定义。

因此,程序员的默认行为——声明一个没有值的变量为nothing——与js的行为相矛盾——声明它不存在。此外,!undefined!null都是true,所以大多数程序员将它们视为等效的。

当然,您可以确保始终执行var hello = null,但大多数人不会在故意松散类型的语言中这样污染他们的代码以确保类型的正确性,当他们和运算符将undefinednull都视为等效时。


2
在JavaScript中,null表示有意没有任何对象值的缺失。 null表示缺乏标识,表明变量没有指向任何对象。
全局属性undefined表示原始值undefinedundefined是自动分配给变量的原始值。 undefined意味着引用不存在。

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