How's tricks? I welcome you to the marvelous world of JavaScript quizzes on Twitter! This very article is part of a series where we deep dive and demystify them. This week is a tough one, so this article is a little longer than usual. So let's jump right into the in-depth exploration of constructors in JavaScript!
Snippet of the Week
This week's snippet is from Oliver Jumpertz:
const c = 'constructor';
c[c][c]('console.log("wth?")')();
This time we have a complex one. However, as confusing as it might seem, it also makes a hell of a lot of fun to destruct.
We start by creating a string. The value of it is pretty essential here, for it's the name of the property we access in the second line two times iteratively. We are accessing the constructor
property of the string. Then we (again) access the property constructor
of the resulting value.
The resulting function gets called with an argument representing a call of a function, console.log("WTH?")
, itself. The return value of that call gets executed (()
) anonymously right after.
So far, so confusing. But worry not, we clear things up right away.
The Output
The output here is probably something the least can guess on the fly. Presumably, the context of the riddle gave it away a bit, tho. It is a log to the console reading "wth?" Well, indeed: what the heck?!
The Analysis
Let us move through this step by step. First, we get the more accessible things out of the way: accessing object properties by the given string value constructor
twice. Splitting this fraction up in an additional snippet helps to understand what's going on:
const stringObject = new String('test');
stringObject.test = { test: 'foobar'};
// Three times the same call:
console.log(stringObject[stringObject][stringObject]); // foobar
console.log(stringObject['test']['test']); // foobar
console.log(stringObject.test.test); // foobar
It shows how we can access specific object properties by a string, even if they are part of the string object reference itself. For our Twitter quiz meaning, we are accessing the constructor
property of the string. Then yet again, the property constructor
of the resulting value.
Now comes the crucial part of understanding all of this — the property constructor. What does it hold? Why is it there? Well, it stores the function used to construct the object. Let me explain this concept by another snippet (I'm sorry):
function FooBar() {
}
const fooBarInstance = new FooBar();
console.log(fooBarInstance.constructor); // function FooBar()
const stringInstance = 'foobar'; // OR new String('foobar')
console.log(stringInstance.constructor); // function String()
Here we define a custom function used to construct an instance. This instance then holds a property constructor
with the value of the specified function. That's simply what JavaScript automatically does on instantiation.
Further, you can see how this concept works with strings. You use syntactical sugar to avoid writing new String('')
, but the paradigm is the same: a function "String" exists. It accepts an argument, and when called to create an instance, the resulting object has a property constructor
holding the used function. And that's the key-secret here.
Coming back to the original snippet, we create a string and access its property constructor. By now, we know that this property holds the function String
. So what happens if we access the constructor property of a function object? Well, yet again, it holds a function. This time the one used to construct, well, functions themselves. Which is indeed function Function()
.
Let's examine this by another snippet:
function foo() {}
console.log(foo.constructor); // function Function()
const bar = new Function('console.log("something")');
bar(); // something
console.log(bar.constructor); // function Function()
const stringInstance = 'foobar'; // OR new String('foobar')
console.log(stringInstance.constructor); // function String()
console.log(stringInstance.constructor.constructor); // function Function()
Mention how a function declaration is just syntactical sugar around new Function()
. So, if the constructor property of a String object is a function, the constructor property of this function is the function used to construct functions, thus the function Function()
. 🤯😂
Now that we have learned this, the rest is pretty straightforward. After accessing the constructor property the second time, we have a function constructing functions. So whatever we pass in as a string gets returned as a function instance. In our case, console.log("wth?")
. Since we do not store this return-value, we call it anonymously immediately right after via ()
. And that's how after all of this, console.log("wth?")
gets executed and, well, logs the string wth?
to the console.
Let's wrap it up in one last snippet:
const c = 'constructor';
const stringConstructorFunction = c[c];
console.log(stringConstructorFunction[c]); // function Function()
// As simple as:
Function('console.log("wth?")')(); // wth?
// Or in a more common syntax:
(() => console.log('wth?'))(); // wth?
Snippet Summary
- Trickery: the constructor property
- Key Learning: how constructor functions work in JS
- Further Reading:
Top comments (0)