Leaving null, Meeting undefined
2021. 10. 5.

Recently, during a code review, a discussion arose about the use of undefined
. Personally, for a very long time, I had quite clearly distinguished between null
and undefined
and used them according to their respective purposes, so I hadn't really thought about looking into this further. Ironically, the issue that sparked the discussion turned out to be a misunderstanding about something else and was easily resolved. However, while searching related topics, I encountered something unexpected: the argument that we should avoid using null
and stick solely to undefined
. This was even stated in the TypeScript coding conventions: "Use undefined, do not use null." I think I saw this before but just brushed it off, as my preconceived notions were too strong.
Luckily, the new book by Douglas Crockford that I happened to be reading also touched upon this topic, allowing me to ponder it a bit more. However, the book only covered it lightly, which was a bit disappointing.
It seems that even things that seem obvious and unchanging can see their paradigms shift over time. Nothing stays the same.
Consequently, I'm considering not using null
directly in the codebase for future projects and relying solely on undefined
. Especially in toy projects, I plan to avoid null
for the time being, until I arrive at my own conclusion based on experience.
Fixed Ideas
There are a few characteristics that come to mind when thinking about undefined
.
- Accessing a non-existent property on an object yields
undefined
. - A variable not initialized with a value holds
undefined
. undefined
represents a value that does not yet exist (has not been initialized).- Therefore, assigning
undefined
directly creates a contradiction. It means assigning a value representing a "not yet existing" state; the moment you assign it, the value exists, yet its value (undefined
) signifies non-existence. - Some older browsers didn't treat
undefined
as a keyword, allowing it to be used like a variable, potentially resulting in it not being the pureundefined
value.
There are more, but I've listed the features relevant to distinguishing between undefined
and null
.
My fixed ideas might have formed from what I've seen and felt throughout my career in this field. I took it for granted that undefined
, being a sort of pre-definition state, meant it was natural to use null
, which carries the clear meaning of an "empty value". I don't even know why I started thinking this way. I can't remember where I read about it, or even if I ever saw a precise definition like this. Anyway, it was firmly fixed in my mind.
undefined
means a value not yet initialized, non-existent.null
means an empty value, but it exists (like an empty string).
I found an image online that properly explains my understanding.
Truthfully, while I used null
distinctively, it wasn't without drawbacks. Sometimes, because I used null
, I had to check for both undefined
and null
. null
having a typeof
of object
can also lead to mistakes. While null
is shorter to type than undefined
, avoiding the default undefined
value meant the code sometimes became longer.
let value;
// vs
let value = null;
Still, I never considered using undefined
instead of null
, because I thought they had different purposes. In other words, I never thought about not using null
in my code, because it had its purpose.
JavaScript Has Two?
Most programming languages have a value or type to represent absence. Usually, there's just one. Languages like Java, C, C++, C# use null
. (C also uses \0
, but it essentially means the same as null
.) Lisp, Objective-C, Swift use nil
. There are many other languages, but I've only considered those I know a little about. Yes, anyway, they all have one.
There are cases like Rust, which doesn't have null. Haskell doesn't either. It seems languages applying functional programming principles tend to avoid null. Given the nature of functional languages, avoiding null makes sense. Emphasizing immutability, they wouldn't want to use values that could potentially change later. It's either something exists or it doesn't. (Though I don't know much about functional programming...)
Languages that utilize absence mostly use a single value and don't distinguish between null
and undefined
. I hadn't really recognized this fact until now. "Ah, JavaScript has two?" I never thought of that as a problem. Having more than one value representing a negative state, bundled together as Truthy and Falsy values through implicit type coercion, offered both convenience and ambiguity simultaneously. It was a double-edged sword that put pressure on you to use it "well" or face the consequences. Perhaps I'm overthinking the cause.
Reasons to Use Only undefined
So why should we only use undefined
? Is null
better than undefined
? The argument for using only undefined
is essentially an argument for choosing one over the other. Thus, the question becomes which one is better to use.
null
is used intentionally by the developer. In contrast, undefined
is used by the JavaScript engine.
let something;
When declaring a variable like this without an initial value, undefined
is assigned to the something
variable. This happens even if the developer doesn't explicitly assign it. Rather than saying the value was implicitly assigned in the code, it's more accurate to describe it as the result of the JavaScript engine's internal process: before executing this code, a new execution context's activation object (AO) is created, variables within the function are collected, and they hold the undefined
value until explicitly assigned a value in the code. Even if the code declares and initializes the variable simultaneously, the process involves the variable first holding undefined
before its value is changed. Anyway, undefined
is invariably used initially.
The engine uses undefined
, not null
. At least in this process, there's no way to make the engine use null
instead of undefined
. undefined
is the default and irreplaceable value. Similarly, when a function doesn't explicitly return a value, it returns undefined
.
Here lies the first reason:
"The engine uses
undefined
, notnull
."
If a developer intentionally uses null
, situations requiring checks for falsy
values necessitate explicitly checking for both undefined
and null
. For example, for a number
variable, one might need to check for the number 0
, null
, and undefined
.
Second reason:
"Using
null
adds anotherfalsy
value."
And finally, there's the third reason, a well-known one:
"Using the
typeof
keyword identifies the type ofnull
asobject
."
This is a clear bug in JavaScript, not intended by the specification. Despite being a bug, it cannot be changed because it has been used as if it were standard for so long that altering it would significantly impact existing code. Thus, it's reluctantly left as is. To fix this issue, we might need another type-checking keyword alongside typeof
. In other words, it's unlikely to be resolved.
If you use null
to represent the absence of an object
in a variable meant to hold an object
, you need to be extra careful when using typeof
for type checks. It's quite ironic that the code intended for extra caution (typeof
checks) requires even more caution and attention when used. This problem doesn't exist if null
is not used.
Problems When Using Only undefined
The first problem relates to undefined
itself. Despite being a keyword, undefined
was not always treated as such and could be used as an identifier.
function doSomething1(undefined) {
console.log(undefined + 1);
}
function doSomething2() {
var undefined = 0;
console.log(undefined + 1);
}
Modern browsers have resolved this issue, preventing assignment to undefined
. However, if you need to support older browsers, there's still potential for problems. Even developers unaware of this issue are unlikely to introduce such nonsensical code into the codebase thanks to static analysis tools like ESLint, but there's no way to prevent malicious manipulation from external sources at runtime.
The second problem is that the DOM API uses null
. It's less of a problem and more of a "Huh? We came this far arguing the engine uses undefined
, but the DOM API uses null
?" situation. Of course, the engine and the DOM API are separate entities, but the question "Why?" does arise. APIs like querySelector
or getElementById
, which search for elements in the DOM, return null
when the target is not found.
The third problem is that JSON doesn't support undefined
. Generally, null
is used in JSON to represent optional values that are absent. undefined
is not a valid value according to the JSON specification. One might think, "Why fuss over JSON?" but it's used in our code anyway. We've come this far trying to eliminate the nagging ambiguity; there shouldn't be exceptions considered from the start.
Using Only undefined
There were three potential problems with using only undefined
:
- The purity of
undefined
. - The DOM API's use of
null
. null
in JSON.
Let's consider alternatives for each problem.
Purity of undefined
As mentioned earlier, this issue tends to disappear over time. In modern browsers, undefined
is purely guaranteed to be undefined
. Even I, having developed since the early IE6 days, haven't experienced problems caused by the value of undefined
being changed. Malicious intent could cause issues, but it was always just a possibility.
The most ideal solution is to raise the browser support baseline to eliminate this problem. It's a bit tricky to specify the exact browser range, but mostに対応 versions before ES6 support were likely patched. What's certain is that browsers supporting ES6 don't have this issue. Nevertheless, if restricting browser support isn't an option or if you want to be extra cautious, create and use a pure undefined
value.
const undef = (() => {})();
Leveraging the side effect that a function returns undefined
when it returns nothing, we can create a pure undefined
value. There's no purer undefined
than this :)
DOM API's null
Usage
This part is a bit annoying. At this point, frustration arises, questioning why these APIs had to use null
. For instance, the relatively recent WeakRef
's deref()
method, which checks if the referenced object exists, returns undefined
when the object doesn't exist. It doesn't use null
. So why did the DOM APIs insist on using it? Complaining won't change anything. Anyway, they use null
. One might wish things had changed, at least with the querySelector
API, but then again, that would create its own kind of terrible inconsistency.
So, we inevitably have to perform the task of converting null
to undefined
each time.
const element = document.querySelector('#something') || undefined;
This isn't much of an alternative, but nowadays, using frameworks like React or Vue is commonplace, reducing the need for direct DOM API access. It might only be slightly bothersome at the library or general module level.
null
in JSON
Typically, APIs are designed to use null
to represent the absence of optional data. While the JSON spec dictates this, it's often better not to send the value at all if it's missing. It is literally "absent". Instead of explicitly using a property with a key and null
to represent an absent value, omitting the property entirely has more advantages. This is a clear benefit; at the very least, it reduces the payload size.
const badJsonPayload = {
name: 'shiren',
ownedHouse: null // Represents absence with null
}
const goodJsonPayload = {
name: 'shiren' // Property is simply omitted
}
And anyway, I don't actually own a house. ㅜㅜ
Conclusion
While learning new technologies is important, it seems equally important to strive for deeper and richer thinking by accepting different opinions on things considered established and looking at them from new perspectives. Achieving such flexibility is truly difficult. Towards the end of Douglas Crockford's new book, there's a line: "Science advances one funeral at a time." It means that because people's ability to accept and adopt new paradigms lags behind the speed at which these paradigms emerge and change, progress often requires a generational shift—people passing away. Personally, this was the most impactful(?) part of the book for me. Accumulating unchanging, fixed ideas is probably how one becomes resistant to change (a kkondae). It seems the only unchanging thing in this field is the fact that nothing is unchanging.
with kakaopay
Recommend Post
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.