DEV Community

Discussion on: Why do we write JavaScript like this?

Collapse
 
tiagojpdias profile image
Tiago Dias

I don't want to sound bitter but...

I don't get the idea of writing convoluted examples to force your point of view...

How is this hard to read?

const isPalindrome = (actualString) => {
  const reversedString = [...actualString].reverse().join('');

  return actualString === reversedString;
}
Enter fullscreen mode Exit fullscreen mode

And why would you rather write code like this?

function isPalindrome(s) {

  for (var i = 0; i < s.length / 2; ++i) {

    if (s[i] != s[s.length - 1 - i]) {

      return false;
    }
  }

  return true;
}
Enter fullscreen mode Exit fullscreen mode

Single character variables? s.length -1 -i ? Creating if statements to return true/false ?

How s this more readable to you?

Collapse
 
anders profile image
Anders

This is exactly the discussion I want us to have =)

as for the particular example you highlight (and I do take your point about "s", although "i" as a common name for an iterator.. well, its quite common)

In my view what you can see there is code that more explicitly mirror the actual functions "action", specifically it explicitly does what you'd do to see if a string is a palindrome or not, ie, you check the "mirror" character to equal the current character.

Using an if statement for an early out I feel also is quite handy, as soon as its apparent that its not a palindrome, we return, without having to process the entire string in those cases.

Collapse
 
functional_js profile image
Functional Javascript

Choosing implementation variants is straightforward if you adhere to a predefined criteria set.

I write about how to evaluate implementations on criteria here:
TLDR: Choose the fastest implementation considering equal robustness.
dev.to/functional_js/squeezing-out...

In this case, the loop is many magnitudes faster. Use the loop.

//a.
const isPalindrome_loop = str => {
  const s = str.toLowerCase();
  for (let i = 0; i < s.length / 2; ++i) {
    if (s[i] !== s[s.length - 1 - i]) {
      return false;
    }
  }
  return true;
};

//b.
const isPalindrome_spread = str => {
  const s = str.toLowerCase();
  return [...s].reverse().join("") === s;
};

//@tests
const palid = "A man, a plan, a canal: Panama—!@#$#@%$$%^&&^*()=-_+,.<>/?";

//a.
timeInLoop("isPalindrome_loop", 1e6, () => isPalindrome_loop(palid));
// isPalindrome_loop: 1e+6: 162.986ms

//b.
timeInLoop("isPalindrome_spread", 1e6, () => isPalindrome_spread(palid));
//isPalindrome_spread: 1e+6: 5.494s
Thread Thread
 
anders profile image
Anders

Very clear comparison of the actual performance of the two.

I do wonder though why declaring the actual functions as "function Name(arg) { ..." has fallen somewhat out of favor, it just seems such a more natural way to do it given how the English language works.

Then again in most other languages you'd typically see:
returnType FunctionName(args) {
or something similar to that

Thread Thread
 
functional_js profile image
Functional Javascript

That's a good question, here's my answer to it:

I don't understand why people still use the "function" keyword, unless you are accessing the "this" keyword, which should be never, except for legacy JavaScript.

Plus I would pick one consistent strategy and go with it, instead of intermingle, "sometimes arrow and sometimes function".

I also don't use single quotes. Everything double quotes.
Then there's none of this, "sometimes this, sometimes that" sprinkled all over the place.

I'm a minimalist, and only use a subset of the language.
Here is a list of what I don't use in JavaScript:
dev.to/functional_js/what-subset-o...

Thread Thread
 
anders profile image
Anders

Thanks for that response.

I agree, consistency is key. Which is why on my projects there are always a set of coding guidelines that are enforced in terms of naming, spacing, comments, all that.

I do use the "this" keyword relatively frequently however myself, specifically from within member functions of an object, to access member data or other member functions.

Thread Thread
 
functional_js profile image
Functional Javascript

That's because of your Object-oriented approach to programming.

I use a functional approach, so everything in that list I linked to in my last post are unnecessary.

Without those constructs, there is almost nothing left but funcs themselves, specifically, arrow funcs.

Collapse
 
brandinchiu profile image
Brandin Chiu

In this particular case, the if is redundant, as the condition for your if is the same as your return content.

You could simply return everything between the brackets of your if instead of explicitly returning true.

The above is important because the way you've written actually makes your application harder to read because it increases what's called "Cyclomatic Complexity" by introducing a fork in your execution path.

Other than that, "the syntantic sugar" of Javascript (arrow functions and the like) are not something I like either. What you're seeing is the proloferarion of the "Code Golf" fallacy. While a fun thought experiment, it is often a measurably worse way to write software thay needs to be maintained by other people.

Thread Thread
 
anders profile image
Anders

I'm not entirely sure I follow, how would that look?

I do agree in principle though re: complexity. I could have spent some more time on my counter examples for sure.

Thread Thread
 
brandinchiu profile image
Brandin Chiu • Edited

Oh woops!

I've misinterpreted what this is doing; I thought I saw an else statement in your if.

That's definitely my bad -- ignore my comments about Cyclomatic Complexity. They don't apply here.

Thread Thread
 
anders profile image
Anders

Roger that, I thought you had some extra magic in store there and got way intrigued : )

Collapse
 
cwraytech profile image
Christopher Wray

That was my thought too. The second is much less readable.(: