JavaScript has many quirks and difficult-to-understand behaviors. There are hilarious talks such as WTFJS and WAT that make fun of JavaScript for its strangeness.
Since I work on refactorings, I have to consider many weird and sometimes funny sides of JavaScript. I will share some of the surprising behaviors that I encounter, so if you see them (which you hopefully never will), it might hint at what's going on.
This blog post explores an innocent-looking statement:
// ... some code
helloWorld;
You might intuitively think that nothing should happen here - the statement seems to do nothing because there is no obvious function call here.
However, it can do anything, for example, print "Hello World!" to the console.
// ... some code
helloWorld; // prints "Hello World!"
How can this even be possible?
It turns out that global variables (in this case, helloWorld
) are properties of the global object. And properties in JavaScript do not have to be simple values. They can be implemented using getters and setters, which can execute code. Since the global object inherits from Object.prototype
in modern JavaScript engines, adding properties to Object.prototype
creates properties on the global object.
Here, helloWorld
is defined as such a getter:
Object.defineProperty(Object.prototype, 'helloWorld', {
get() { console.log("Hello World!"); },
});
helloWorld; // prints "Hello World!"
Thankfully this can only happen with global variables, and not with parameters or local variables.
Object.defineProperty(Object.prototype, 'helloWorld', {
get() { console.log("Hello World!"); },
});
const a = helloWorld; // getter is evaluated, prints "Hello World!"
a; // does nothing
I learned about this strange behavior in a blog post about the globalThis
polyfill. In the polyfill, a global property getter is used to access the global this
object in different environments such as browsers, web workers, frames, Node.js, and ES modules. Have a look if you want to know more!