Any point or "feature" I mention here has made this list (or rather, got the Golden Raspberry Award) because of either of these things:
The last point might boil the blood of a lot of people, but I have seen some features of JavaScript being used incorrectly; to an extent that sometimes I think using ES5 would've fine here.
constReason: False Impression
Many new programmers, when starting with ES6 or above, think of const as being immutable. It might be true for base types (boolean, string, and the likes) but it's not so true for objects (objects AND arrays).
For example, let's say I have this piece of code:
const testValue1 = 'Hello, Hashnode!';
// Will not execute. Thank God.
testValue1 = 'I love Java!';
Perfect! It's doing what it's supposed to. However, let's look at ECMAScript 2019 Specification. In particular:
let and const are actually built for lexical environment scoping (unlike var where the scope leaked).
They links are actually from the 2019 spec. Let's look at the 2015 spec where they were introduced so § 13.2.14] which says: If IsConstantDeclaration of d is true, then
Let status be env.CreateImmutableBinding(dn, true).
Else,
Let status be env.CreateMutableBinding(dn, false).
Alright. We are getting somewhere. Let's dig in deeper: an excerpt from CreateImmutableBinding.
Create an immutable binding in envRec for N and record that it is uninitialized. If S is true record that the newly created binding is a strict binding.
Aahhhh! So it means that the variable reference is immutable and not the derivative thereof.
As we saw in the spec (13.2.14, ECMAScript 262), only reassigning references isn't allowed; that is to say you can't point it another value. However, whatever value you have can be mutated as long as it doesn't change the lexical environment.
Reason: readability
Almost everyone who has used styles-components knows what this is:
const Button = styled.a`
display: inline-block;
`
It's a styled button! But for new readers, this is just probably a syntax error? Where is the parenthesis since styled.a is supposed to be a function? What is this?
These are tagged templates. You seem, when ES5 introduced templates, they also thought of introducing a function which works on them in case someone wanted to do some customized interpolation. I have used this as a part of a project I worked on where we created a contenteditable wrapper around Draft.js and used a pluggable approach to the exporters, and the core logic of the adapters relied on tagged templates.
For those of you who don't know what these are, let's take a quick example:
const wrapInHead = ( str, ...vars ) => {
// str is an array which contains strings split by where there was an interpolation.
// and vars is the respective variables which were to be filled.
let finalString = '';
for ( let i in str ) {
// we use short circuiting since the last value is str will always be "" and if the parts are greater than
// the value, it'll just give a blank.
finalString += str[ i ] + ( vars[ i ] || '' );
}
return finalString;
};
Very cool!
But think about it. Do we seriously need it? I mean, yeah, it is certainly good and useful but if you're a new dev, will you immediately know what it is? And most of the good JS courses don't touch on this either.
Because of this reason, I really don't like tagged template literals. They are good, but only when the entire team know what they are or if you are working on something personal.
A big bummer for new devs! And really confusing too.
() => {}Reason: gives a false impression/improper usage
This is a big one!
With the introduction of arrow functions, our code bases became a lot cleaner!
function testFunction( testVar, function( cbVal ) {
const args = Array.from( arguments );
// Do something...
} );
With arrow functions, these became:
const testFunction = ( testVar, cbVal => {
const args = Array.from( arguments );
// Do something!
} );
After this modification, we broke an entire build. Why? Because people thought () => {} is the same a function name() {}.
NO. It is NOT. We hear the term lexical scoping a lot. What that means is that the scope of the current function or block is based on its parents or ancestors (sometimes). However, arrow functions do not have their own this or arguments. And because of this, they use whatever the callee provides. Many, including me, thought that it was the same and we messed up.
function testFunction( test ) {
console.log( arguments.caller );
}
const newFunction = () => {
testFunction( 'Hello World' );
};
This should print newFunction() right? Because that's the one calling testFunction()? Right? NO! Arrow functions are treated as anonymous functions and hence, they don't have a function signature in call stack. (Try that code in the dev tools console.)
And this also makes them really bad for any code which has logging since the function signature will never resolve in the logs.
argumentsReason: JUST BECAUSE/readability/improper usage
The arguments special variable contains the list of arguments passed to a specific function. This is especially useful when you don't know the number of arguments you'll receive; here, you use arguments which behaves like an array.
What do you mean: behaves?
Right. When you execute this:
console.log( Object.prototype.toString.call( arguments ) );
You get [object Arguments]. It is so special that it has a separate type. Wow.
But then you can access the values like arguments[ 0 ], etc. And you can call const args = Array.from( arguments );
Weird. This object also have some (now deprecated) properties:
Note: this is not a ES6 feature as such but it is something which wasn't patched in JavaScript.
I know that these "features" are used very extensively, even by me, but I am sure TC39 could've done a better naming jobs. But well, programmers are bad at naming things anyway! xD
This list isn't exclusively ES6. I have tried to include some weird parts of ES5 and 4 as well.