DEV Community

Remembering that "functions are objects" can help in writing more concise code

Basti Ortiz on October 19, 2018

Introduction More often than not, we are obsessed with writing concise code. Who wouldn't, right? Concise code is short code that is eas...
Collapse
 
jburgy profile image
jburgy

You do have to be careful with things like

['0', '1', '2'].map(parseInt)
Collapse
 
somedood profile image
Basti Ortiz

Oh, wow. This is indeed weird. I didn't know this was an outlier.

Why does this happen? Are there any other outliers I should be aware of so I could update the article to mention them?

Collapse
 
ironydelerium profile image
ironydelerium

That one is a side effect of how the combination of Array.prototype.map and parseInt work - the former calls it's argument with (value, index, array) repeatedly, parseInt expects (value, base) where 2 <= base <= 36, or it returns NaN (ecma-262 1e, 15.1.2.2 "parseInt(string, radix)").

Most of the array iteration methods (forEach, map, every, some) pass 3 arguments; I believe reduce passes 4.

Thread Thread
 
somedood profile image
Basti Ortiz

Oh, I see now. There is a conflict between the two parameters (index and base). Since the code you mentioned returns [0, NaN, NaN], why does it return 0 in the "zeroth" element of the array? What even is a base 0 number to JavaScript?

As I experimented on passing in 0 as an argument for the base parameter of parseInt, I found that it works normally. Why would that work? Is it just all in the spec?

Thread Thread
 
robertcoopercode profile image
Robert Cooper

From MDN (radix being the same as base with the previously used verbage):

If radix is undefined or 0 (or absent), JavaScript assumes the following:

  • If the input string begins with "0", radix is eight (octal) or 10 (decimal). Exactly which radix is chosen is implementation-dependent. ECMAScript 5 specifies that 10 (decimal) is used, but not all browsers support this yet. For this reason always specify a radix when using parseInt.
Thread Thread
 
somedood profile image
Basti Ortiz

Thanks for looking into this! We appreciate your efforts. I'll go make a quick edit to the article now to raise this point.

Collapse
 
robertcoopercode profile image
Robert Cooper

Ah, thanks for this example! It was fun digging into this.

Collapse
 
ironydelerium profile image
ironydelerium • Edited

Except that it's not the same thing.

promise.then(value => console.log(value))
// 'this' in the execution of console.log is console
promise.then(console.log)
// 'this' is undefined
promise.then(console.log.bind(console))
// This one is roughly equivalent to the first

// Event listeners on DOM nodes bind 'this' to the element:
node.addEventListener('click', console.log)
// 'this' is 'node'.

Taking a more concise syntax without understanding it's implications is going to lead you to bugs in the long term.

Collapse
 
somedood profile image
Basti Ortiz

I didn't even think about the context of the execution when I wrote this article. That's my mistake on my part. I just wanted to show that one can generally use function definitions* as arguments in the hopes of shortening code just a bit more. Thanks for clarifying and pointing that out, though!

*By functions, I refer to short, simple, single-purpose functions that don't necessarily have significant side effects.

Collapse
 
robertcoopercode profile image
Robert Cooper
fetch('https://api.github.com/')
  .then(res => {
    return res.json();
  })
  .then(function(data) {
    console.log(data);
  })
  .catch(err => console.log(err));

^ I did not even know that this could be shortened the way you suggested. Thanks for explaining this idea of a stored function definition. I'm not quite sure I've got my head wrapper around the idea, but I believe to have a better understanding now.

Collapse
 
somedood profile image
Basti Ortiz

Thanks! However, as mentioned by jburgy, we do have to be aware of some weird outliers.

You do have to be careful with things like

['0', '1', '2'].map(parseInt)
Collapse
 
gypsydave5 profile image
David Wickes

This is great - but remember there are some gotchas when you start passing console.log in as the function argument. If the function you're passing to will take a variadic function (i.e a function that can take a different numbers of arguments), you may get unexpected results.

For instance

[1, 2, 3].forEach(console.log)

results in

1 0 [ 1, 2, 3 ]
2 1 [ 1, 2, 3 ]
3 2 [ 1, 2, 3 ]
Collapse
 
somedood profile image
Basti Ortiz

It really all comes down to being careful with parameters. As useful as this trick is, it can be dangerous if one has not read enough documentation. "With great power comes great responsibility" after all. Thanks for this! I appreciate all the quirks being discussed here in the comments section because even I wouldn't have thought of these quirks.

Collapse
 
johnkazer profile image
John Kazer

A useful article thanks but the smug tone is not necessary. "Of course, in a professional setting one would never do such a thing!" Didn't add to the utility or point of what you said, just irritated.

Collapse
 
somedood profile image
Basti Ortiz

Sorry for that. I didn't mean to sound boastful. For my improvement, how would I have rewritten it?

Collapse
 
johnkazer profile image
John Kazer

Don't forget that there are folk of different knowledge levels on dev.to. Maybe focus on the explanation with some descriptive 'colour' from your experience - I think most readers value new insight and want confidence in the person writing about it.

Thread Thread
 
somedood profile image
Basti Ortiz

Thank you for the advice! I will definitely be more sensitive with my words in my future posts.

Collapse
 
jhderojas_uva profile image
Jesus Hernandez

Great article. This is something I tell to my co-workers but they don't understand at all. They still think that a function is a function not that everything in JS is an object and you must use it as it is... an object.

Collapse
 
somedood profile image
Basti Ortiz • Edited

I struggled with the concept myself when I was a beginner in JavaScript. I couldn't understand why primitives and functions had properties and methods even though they weren't "objects" so to speak. I believe the confusion stems from the constant desire to mold JavaScript into another familiar language such as C++ or Java.

An example would be the implementation of ES6 Classes. There is no such thing as a class in JavaScript, yet it was added as syntactic sugar to accommodate those who came from other object-oriented languages. It also allowed for a straightforward interpretation of inheritance. JavaScript only emulates classical inheritance. Under the hood, it still uses prototypal inheritance.

This is true for functions. In object-oriented languages, a function/method exists as a member of a class. When the class is instantiated as an object, the function is merely a method of the instantiated object, and not a standalone object itself; unlike in JavaScript where a function is an "object". To truly master JavaScript, one must accept that JavaScript is not like the other languages. It is its own beast that needs to be tamed without any preconceived knowledge of other languages.

In conclusion, I think your co-workers are hindered by preconceived knowledge. They just have to treat JavaScript as it is, and not as how they want to mold it. But please do take my advice with a grain of salt. I am only with three years of experience in JavaScript myself. Surely there are others who are more qualified than I am to help you and your co-workers.

Collapse
 
squgeim profile image
Shreya Dahal

I think this is fine for little things, but often maintainability wins over conciseness. It is always easier to maintain explicit code.

Collapse
 
alainvanhout profile image
Alain Van Hout

More often than not, we are obsessed with writing concise code.

More often than not, ‘concise’ is just an alias for ‘dense’. And dense code is almost always unmaintainable code.