DEV Community

Cover image for JavaScript WTF: Six of the Language’s Gravest Design Flaws
Sam Winter
Sam Winter

Posted on • Originally published at thecarrots.io

JavaScript WTF: Six of the Language’s Gravest Design Flaws

Some of us have a perhaps misguided affection for JavaScript; others loathe the idiosyncrasies of a language created in ten days. Either way we're stuck with the parlance of web browsers, the idiom whose very name its creator called a "marketing scam." JavaScript makes us yell. It makes us laugh. Above all, it makes us cry a barbaric NaN over the mechanical keyboards of the world.

==

In the beginning was 1, and 1 was with true, and 1 == true.

Equality lies at the heart of logic, mathematics, and democratic society. JavaScript's equality operator (==) breaks the equivalence relation of mathematics in that it performs type coercion when evaluating equality. Yes, 1 is equal to 1 in JavaScript, but it's also equal to true and "1".

0 == 0; // => true
0 == 1; // => false
0 == "0"; // => true
0 == false; // => true
Enter fullscreen mode Exit fullscreen mode

To rectify this original sin of unequal equality, JavaScript also offers the strict equality operator ===, which considers both type and value. Even the strict equality operator isn't without its quirks (or faults): NaN === NaN // => false. In JavaScript some equality operators are more equal than others.

this

A junior developer said, What is this?, pointing to his monitor with wide eyes; How could I answer the junior developer? … I do not know what it is anymore than he.

The JavaScript keyword this is much like English homograph "set." Its meanings are manifold and depend on context. There are as many ways to bind the value of this as there are days in the American programmer's work week, as much as we might wish there were fewer:

  1. within a method, this is the calling object;
  2. within a constructor, this is the newly created object;
  3. in the global scope, this refers to the global object (or is undefined in strict mode);
  4. in event handlers, this is the currentTarget of the event;
  5. within a function bound with the call, apply, or bind methods of Function.prototype, this refers to the first argument of the binding method.

For a language that draws an unusually nuanced distinction between types of nothingness in null and undefined, the ambiguity of this is a curious choice. The global this in particular is utterly useless at best and often hazardous, hence its removal in strict mode.

hasOwnProperty

The runtime opened the object at once, while S. and JavaScript watched. It was stuffed with properties, and when it was opened two large prototypes fell out, tied up as you might tie up bundles of firewood. The runtime flinched in alarm. "Try higher up, higher up," said JavaScript, directing operations from above. The runtime, gathering up the properties in memory, obediently cleared everything out of the object to get to the properties up the chain. The runtime's memory was already half full of properties. "Oh, there’s been a lot of definition done," said JavaScript, nodding, "and this is only a small part of it. I keep the larger part of what I have here up the chain."

JavaScript is the only popular programming language using prototypal inheritance, often contrasted with classical or class-based inheritance. While prototypal inheritance isn't as classy as its counterpart, it's a more powerful paradigm. One can easily build classical inheritance from prototypal, and prototypal inheritance is more naturally suited to composition over inheritance.

Unfortunately, the for in loop unexpectedly traverses an object's entire prototype chain, not only the object itself. If one were to iterate over the properties of a Goomba, the minutiae of the Nintendo Corporation would follow (provided these minute Nintendoan properties weren't defined with Object.defineProperty, added in ES5). To iterate through a Goomba and a Goomba alone, one need check if goomba.hasOwnProperty(property):

for (const property in goomba) {
  if (goomba.hasOwnProperty(property)) {
    console.log(property);
  }
}
Enter fullscreen mode Exit fullscreen mode

hasOwnProperty isn't an original sin like == or a source of bewilderment like this. It's a guardrail to unintuitive and usually unwanted behavior.

typeof

There is no variable one can declare that is not filled with angst and ambivalence, that is not, in one of those values, the mighty typeof an object.

The operator typeof is the most worthless feature in all of JavaScript. With the precision of a software developer returning from a long vacation and trying to determine where she left off, typeof's return values are often misleading and uninformative:

typeof {}; // => object
typeof null; // => object
typeof []; // => object
typeof /abc/; // => object
typeof Math; // => object
typeof new String("abc"); // => object
typeof new Date(); // => object
typeof new Boolean(false); // => object
typeof new Number(1); // => object
typeof new Function(); // => function ;)
Enter fullscreen mode Exit fullscreen mode

The highest purpose of typeof is to check whether a variable is undefined, e.g., typeof actuallyNotAnObject === "undefined". To reference the variable otherwise would result in a ReferenceError.

eval

Then, with inviolate curve, forsake our eyes

As apparitional as sails that cross

Some string of text to be evaled away;

- Till with untrusted code ourselves betray ...

The eval function is JavaScript's four-letter word. It executes any string of code passed to it with the privileges of the caller. When a malicious party has influenced that string, eval poses a tremendous security risk. It's not even performant given that it has to invoke the JavaScript interpreter—particularly expensive when interfacing with machine code as in variable lookup.

JavaScript developers may not realize that they're using eval "under the hood" when they pass a string of code as an event-listener callback or as an argument to setTimeout or setInterval. Barring build tools and the onanism of metaprogrammers, code ought to be written as code, not strings.

;

The Semicolon has not left me and I don't believe it will leave me so soon; but I no longer have to bear it, it is no longer an illness or a passing fit: it is I.

Like a well-intentioned simpleton under cover of night, the JavaScript parser covertly inserts semicolons when it encounters syntactic errors due to missing semicolons, often inadvertently changing the code's behavior. (The official rules of automatic semicolon insertion read like GPT-3's attempt at computer-scientific legalese.)

The parser papers over what ought to be errors rather than constraining syntax by design. This degree of freedom causes the semicolon-forgetful JavaScript developer's code to break in surprising ways. The developer only discovers this sort of nerdwar-precipitating bug at runtime, if at all:

clearMenus()
!isActive && $parent.toggleClass("open")
Enter fullscreen mode Exit fullscreen mode

Semicolons are tedious; they lack understated beauty; yet with parser so devious, semicolons are one's duty.

About Us

At Carrots we're building a hiring platform specifically for software engineers. You can connect your GitHub, Stack Overflow, and more to show off so much more than your resume. Our algorithm shows where you rank among world-class talent and surfaces your profile to top companies.

Top comments (0)