• Understanding JavaScript’s ‘undefined’
  • By Angus Croll
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: yanyixin
  • Proofreader: Noahziheng, Moonliujk

The concept of undefined in JavaScript is somewhat confusing compared to other languages. In particular, trying to understand referenceErrors (” x is not defined “) and how to write elegant code against them can be frustrating.

This article is my attempt to clarify the matter. If you’re not familiar with the difference between variables and attributes in JavaScript (including internal variableObjects), you might want to read my last article.

What is undefined?

In JavaScript, there is Undefined (type), Undefined (value), and Undefined (variable).

Undefined (type) is a JavaScript built-in type.

Undefined (value) is the only value of undefined. Any attribute that is not assigned is assumed to be undefined (ECMA 4.3.9 and 4.3.10). Functions without a return statement, or functions with an empty return, will return undefined. The value of an undefined parameter in a function is also considered undefined.

var a;
typeof a; //"undefined"
 
window.b;
typeof window.b; //"undefined"
 
var c = (function() () {}); typeof c; //"undefined"
 
var d = (function(e) {return e})();
typeof d; //"undefined"
Copy the code

Undefined is a global property with an initial value of undefined. Because it is a global property, we can also access it as a variable. For consistency, I’ll call it a variable throughout this article.

typeof undefined; //"undefined"
 
var f = 2;
f = undefined; //re-assigning to undefined (variable)
typeof f; //"undefined"
Copy the code

Starting with ECMA 3, it can be reassigned:

undefined = "washing machine"; // Assign a string to undefined (variable) typeof undefined //"string"
 
f = undefined;
typeof f; //"string"
f; //"washing machine"
Copy the code

Needless to say, reassigning a value to undefined is bad practice. In fact, ECMA 5 doesn’t allow this (although, in current browsers, only Safari does).

And then null?

Yes, this is generally well understood, but it is important to reiterate that undefined is different from null, which means that the original value of the value is intentionally missing. The only similarity between undefined and null is that they are both false.

So, what is a ReferenceError?

ReferenceError indicates that an invalid reference value was detected. (ECMA 5 15.11.6.3)

In real life projects, this means that ReferenceError is thrown when JavaScript tries to get a reference that cannot be parsed. (There are other cases where referenceErrors are thrown, especially when running in ECMA 5 strict mode. Check out the reading list at the end of this article if you’re interested.)

Notice how the syntax of the messages from different browsers varies, and as we’ll see, none of this information is particularly illuminating:

alert(foo)
//FF/Chrome: foo is not defined
//IE: foo is undefined
//Safari: can't find variable foo
Copy the code

Still not sure about the “unresolvable reference”?

In ECMA terminology, a reference consists of a base value and a reference name (ECMA 5 8.7 – AGAIN, I’m ignoring the strict pattern. Also note that the terminology for ECMA 3 is slightly different, but the actual meaning is the same).

If the reference is an attribute, then the base value and reference name are flanking the. (or the first parenthesis or whatever) :

window.foo; //base value = window, reference name = foo;
a.b; //base value = a, reference name = b;
myObj['create']; // base value = myObj, reference name = 'create';
//Safari, Chrome, IE8+ only
Object.defineProperty(window,"foo", {value: "hello"}); //base value = window, reference name = foo;
Copy the code

For variable references, the base value is the VariableObject of the current execution context. The VariableObject of the global context is the global object itself (the window in the browser). Each function context has an abstract variable object called ActivationObject.

var foo; //base value = window, reference name = foo
function a() {
    var b; base value = <code>ActivationObject</code>, reference name = b
}
Copy the code

If the base value is undefined, the reference is considered unresolvable.

Therefore, if the value of the variable before. Is undefined, the attribute reference is not resolvable. The following example would have thrown a ReferenceError, but it doesn’t, because TypeError is thrown first. This is because the attribute’s base value is influenced by CheckObjectCoercible (ECMA 5 9.10 to 11.2.1), which throws TypeError when it attempts to convert Undefined to Object. (Thanks kangax for pre-posting on Twitter)

var foo; foo.bar; //TypeError (base value, foo is undefined) bar.baz; //ReferenceError (bar cannot be parsed) undefined. Foo; //TypeError (base value is undefined)Copy the code

Variable references are always resolved because the var keyword ensures that VariableObject is always assigned to the base value.

By definition, references that are neither attributes nor variables are not resolvable and raise a ReferenceError:

foo; //ReferenceError
Copy the code

We don’t see an explicit base value in the JavaScript above, so we look for VariableObject to reference the property named foo. Make sure foo has no base value, and then raise ReferenceError.

butfooIsn’t it an undeclared variable?

Technically not. Although we sometimes find “undeclared variable” to be a useful term for error diagnosis, in reality, a variable is not a variable until it is declared.

What about implicit global variables?

Indeed, identifiers that have never been declared by the var keyword will be created as global variables — but only if they are assigned.

function a() { alert(foo); / / ReferenceError bar = [1, 2, 3]. // Foo is global} a(); bar; //"1, 2, 3"
Copy the code

Of course, it’s annoying. It would be better if JavaScript always threw ReferenceErrors whenever it encountered a reference that could not be resolved (which is actually what it does in ECMA strict mode).

When do YOU need to code for ReferenceError?

If your code is good enough, you rarely need to do this. As we have seen in typical usage, there is only one way to get a non-resolvable reference: use syntactically correct references that are neither attributes nor variables. In most cases, make sure you remember the var keyword to avoid this. Runtime exceptions occur only when references to variables that only exist in some browsers or third-party code.

A good example is Console. In the Webkit browser, Console is built in, and the properties of Console are always available. However, Console in Firefox relies on installing and opening Firebug (or other add-ons). Internet Explorer 7 does not have a console. Internet Explorer 8 has a console, but the console attribute exists only when the IE development tool is started. Obviously Opera has console, but I’ve never used it.

The conclusion is that the following code snippet is likely to raise a ReferenceError when run in a browser:

console.log(new Date());
Copy the code

How do I code variables that may not exist?

One way to check for an unresolvable reference without raising a ReferenceError is to use the Typeof keyword.

if(typeof console ! ="undefined") {
    console.log(new Date());
}
Copy the code

However, this always seemed tedious to me, not to mention suspicious (it’s not that the reference name is undefined, but that the base value is undefined). But anyway, I prefer to keep typeof for type checking.

Fortunately, there is another way: we already know that if the base value of undefined is defined, it will not raise a ReferenceError — and since console is a global object, we can do this:

window.console && console.log(new Date());
Copy the code

In fact, you only need to check whether variables exist in the global context (there are other execution contexts in the function, and you can control which variables exist in your own function). So, in theory, you should be able to avoid using Typeof to check for references.

Where can I read more?

Mozilla Developer Center: undefined

Angus Croll: Variables and properties in JavaScript

Juriy Zaytsev (” Kangax “) : Understand Delete

Dmitry A. Soshnikov: EcMA-262-3 Details: Chapter 2 Variable objects

Ecma-262 Fifth edition standard documentation

Undefined: 4.3.9, 4.3.10, 8.1

Reference Error: 8.7.1, 8.7.2, 10.2.1, 10.2.1.1.4, 10.2.1.2.4, and 11.13.1.

ECMAScript’s strict schema Annex C

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.