• The Dark Side of Javascript: A Look at 3 Features You Never Want to Use
  • By Fernando Doglio
  • Translation from: The Gold Project
  • This article is permalink: github.com/xitu/gold-m…
  • Translator: Z Zhaojin
  • Proofreader: CarlosChen and Finalwhy

Describe three features of JavaScript that you should not use

JavaScript has been around for quite some time (about 26 years), and the language has come a long way in that time.

Much of this evolution has been purposeful, especially in the latest iteration, where the developer community has managed to influence some of the changes to make JavaScript a very flexible and easy to use language.

Over the years, however, it’s fair to say that there are still remnants of outdated features that haven’t been taken away, but don’t really serve any purpose (or, more accurately, are inefficient in their original purpose).

Here are three JavaScript features that you should avoid using, even if they are still available at runtime.

Void operator

You may have seen the existence of the void operator at some point. In the past, whenever you clicked on a link that would trigger a JavaScript function, you would add href=” JavaScript :void(0)” to ensure that the default behavior (i.e. page jump) would not trigger.

But what exactly does that mean?

The void operator is a way to generate undefined values in JavaScript. Yes, it can take any expression, and it returns undefined every time.

I know what you’re thinking: Why not just use the existing undefined keyword? Well, as you can see, before ECMAScript 5, undefined was not a constant value. Yeah, you can define undefined, if you think about it, isn’t that what we used to want to do?

Of course, it didn’t make sense to do so, which is why it was eventually redefined as a constant value that cannot be changed. However, since you could change it earlier, void will allow you to access undefined even if the constant no longer works.

In fact, a good way to avoid any problems with third-party libraries is to redefine constants that belong only to your namespace by creating your own IIFEs, where one of the arguments is indeed undefined, like this:

(function (window.undefined) {
  // You can use undefined as expected}) (window.void(0))
Copy the code

Of course, the void operator still has its use today, but it’s not necessary. For example, in JavaScript today, the best use case is to help avoid the unexpected return of a one-line arrow function.

As you probably know, a one-line arrow function returns the result of that line, even if you don’t explicitly use a return statement.

const double = x= > x * 2; // Return the result of X multiplied by 2

const callAfunction = () = > myFunction(); // Return the result returned by myFunction, even if I don't want to
Copy the code

Both of these functions return something. Obviously, for a double function, you want it to return one value, but the other one might not, and you might just want it to call another function (i.e., myFunction()), but you’re not interested in the resulting value. So here’s what you can do:

const callAfunction = () = > void myFunction(); // Return the result returned by myFunction, even if I don't want to
Copy the code

This immediately overrides the return value and ensures that your call only returns undefined.

To me, this behavior provides a minimal benefit, making void useless in JavaScript in this day and age.

I suggest you avoid using it and leave it in a disused state.

With statement

This is one of the constructs that comes with JavaScript, but you’ve probably never heard of it because it’s not really popularized. In fact, even the official MDN documentation discourges you from using it because it can lead to very confusing code.

The with statement allows the scope chain of a given statement to be extended. In other words, it allows you to inject an expression into the scope of a given statement, ideally simplifying the statement.

Here’s an example, so you can see what I’m talking about:

function greet(user) {
  
  with(user) {
    console.log(`Hello there ${name}, how are you and your ${kids.length}kids today? `)
  }
}

greet({
  name: "Fernando".kids: ["Brian"."Andrew"]})Copy the code

Note the magic of the with statement in the greet function. This is a basic example that shows the happy path of an expression. But let’s look at another situation where things get a little more complicated:

function greet(user, message) {
  with(user) {
    console.log(`Hey ${name}, here is a message for you: ${message}`)}}// happy path
greet({
  name: "Fernando"
}, "You got 2 emails")

// kinda sad path
greet({
  name: "Fernando".message: "Unrelated message"
}, "you got email")
Copy the code

What do you think the output of this execution will be?

Hey Fernando, here is a message for you: You got 2 emails
Hey Fernando, here is a message for you: Unrelated message
Copy the code

By adding a property of the same name to the object passed in, you inadvertently override the second argument to the function. I would add that this is completely normal, as one would never expect both to be in the same scope level. However, thanks to with, we have mixed the two scopes together, but the results are not ideal.

This is all to say to avoid using with. While it may seem like a good way to save code, your code can quickly become so complex that it becomes mentally taxing for someone else (or you two weeks later) to understand your code.

Labels tag

If you learned programming early enough (as I did), you’ve experienced the hatred of go-to statements in other languages such as C. That’s too bad, it was a feature that made sense in its day, but eventually became so outdated and bad with newer solutions to the same problem that it became an anti-pattern.

So JavaScript has to implement it.

A go-to statement is a way for you to put a tag anywhere in your code and then jump there from somewhere else. You can jump into the middle of a function, or into an IF statement, and it’s like a magic entry point to anywhere in your code. I’m sure you can see that this could be a problem, it’s too powerful, it’s too flexible, and we’re certainly going to miss the opportunity to use it.

However, JavaScript implements a similar, but not identical, structure: the labels tag.

In JavaScript, a tag statement is a tag that you put before a statement, and then you can break or continue. Note that there is no more go-to, which is a good advantage.

You could write:

label1: {
  console.log(1)
  let condition = true
  if(condition) {
  	break label1
  }
  console.log(2)}console.log("end")
Copy the code

The output will be:

1
end
Copy the code

Of course, this example looks very much like an if.. The else statement. And you could argue that it doesn’t look so bad. However, you break the normal flow of code and skip statements. If that’s what you want, then use if.. Else is going to be much less of a mental burden.

The problems with labels become more apparent when we include their interactions with loops and continue statements.

let i, j;

loop1:
for(i = 0; i < 10; i++) {
  loop2:
  for(j = 0; j < 10; j++) {

    if(j == 3 && i == 2) {
      continue loop2;
    }
    console.log({i, j})
    if(j % 2= =0) {
      continueloop1; }}}Copy the code

Can you run the above code in your head and tell me the exact output? It’s not impossible, but it will take time. The script above will print:

{ i: 0, j: 0 }
{ i: 1, j: 0 }
{ i: 2, j: 0 }
{ i: 3, j: 0 }
{ i: 4, j: 0 }
{ i: 5, j: 0 }
{ i: 6, j: 0 }
{ i: 7, j: 0 }
{ i: 8, j: 0 }
{ i: 9, j: 0 }
Copy the code

Essentially, the second if evaluates to true at 0, so the continue statement affects the outer loop, causing it to move to the next index value, which in turn resets the inner loop, causing it to go back to 0, and the same thing keeps happening, 10 times. The first if, if you want to know, is never evaluated to true, because j never reaches anything other than 0.

Labels can be tricky little things, even if you can use them correctly and they make a lot of sense from an interpreter’s point of view, but you should be writing code for humans, not machines. Someone else will read it (even you in three weeks’ time), and the moment they see the label, they’ll hate you forever. Sure, they’ll spend more time understanding the basic flow of your code, but that’s a secondary issue right now.

This paper summarizes

Don’t get me wrong, I love JavaScript, and I’ve been interacting with it in different ways since I started web development 18 years ago. I’ve seen this language evolve, and like a good bottle of wine, it gets better with time. However, it would be false for me to say that there are not some dark corners of the language that I dislike. And these three functions just show that.

The good news is that in my years of experience, I have yet to see either with or Label implemented and deployed into production. That’s not to say there aren’t cases like this, it’s just that I’ve never seen one, which makes me think there aren’t many code reviews that would allow them to pass.

Have you seen these features used in modern JavaScript?

If you find any errors in the translation or other areas that need improvement, you are welcome to revise and PR the translation in the Gold Translation program, and you can also get corresponding bonus points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


Diggings translation project is a community for translating quality Internet technical articles from diggings English sharing articles. The content covers the fields of Android, iOS, front end, back end, blockchain, products, design, artificial intelligence and so on. For more high-quality translations, please keep paying attention to The Translation Project, official weibo and zhihu column.