DEV Community

Cover image for Things I wish I knew about… JavaScript functions
Paul Walker
Paul Walker

Posted on • Originally published at solarwinter.net on

Things I wish I knew about… JavaScript functions

Especially coming from a C/Python/Elixir background, there were some things about JavaScript functions that I really didn’t get to start with. I thought I’d write them down in the hope they’ll help someone else on their journey.

I should note this is probably part one - there’s bound to be more things I learn about JavaScript functions as I keep using the language.

When one is async, all are async

I didn’t really understand how JavaScript does async when I started using it, so I spent quite some time trying to work out how a function could get a result from an asynchronous call and return it without the function caller having to be async itself.

If you’re aiming for the same thing, I’ll save you the bother - you can’t do it. I initially had high hopes for something like the construction below.

async function iAmAsync(num) {
  return num * 2;
}

function iUseThen(num) {
  return iAmAsync(num).then(res => res + 1);
}

console.log("iUseThen(3) =>", iUseThen(3));

Enter fullscreen mode Exit fullscreen mode

What I didn’t realise was that iAmAsync(3).then(...) will implicitly return a Promise, meaning the whole of iUseThen will return a Promise.

iUseThen(3) => Promise { <pending> }

Enter fullscreen mode Exit fullscreen mode

One approach I did find for using async functions in short scripts is to declare an anonymous async function and immediately invoke it:

(async function() {
    const result = await somethingNetwork();
    console.log("Result", result);
}) ()

Enter fullscreen mode Exit fullscreen mode

What’s the difference between function and =>?

In JavaScript, => is called a ‘fat arrow’. Fat arrows are a shorthand way to create functions (with some restrictions as below):

function anonymous(name) {
  console.log("Hello", name);
}

Enter fullscreen mode Exit fullscreen mode

you can use:

name => console.log("Hello", name);

Enter fullscreen mode Exit fullscreen mode

Apart from anything it saves coming up with lots of different names for anonymous functions.

Limitations of =>

As handy as this is, there are some limitations of the fat arrow form.

No this

A function defined with => doesn’t have a this to reference. A (somewhat contrived) example - this works:

withFunction = {
  answer: 42,
  ask: function () {
    console.log("The answer is:", this.answer);
  }
};
withFunction.ask();

Enter fullscreen mode Exit fullscreen mode

Producing:

The answer is: 42

Enter fullscreen mode Exit fullscreen mode

This one doesn’t:

withArrow = {
  answer: 42,
  ask: () => {
    console.log("The answer is:", this.answer)
  }
}
withArrow.ask();


The answer is: undefined

Enter fullscreen mode Exit fullscreen mode

A more real-world example of this can be seen with Vuex - if you’re defining a mutation or an action and you use a fat arrow function, it probably won’t work as you expect.

As an implication of this — because there’s no this, you can’t use super either.

Can’t be used as constructors.

If you’re defining a class, you must use the full function foo(bar) {} form.

Can’t use yield

I have to admit this hasn’t been a problem for me, I haven’t yet had a cause to use generators.

When to use (foo) => and when to use foo =>?

The foo => ... form accepts one and only one parameter, and even then only if it’s a simple form.

If you need to indicate no parameters, bracket are required.

() => console.log("I'm not listening to you");

Enter fullscreen mode Exit fullscreen mode

If you need to pass two, (foo, bar) => ... then it needs brackets. So this is fine:

foo => console.log("I'm a valid construction");

Enter fullscreen mode Exit fullscreen mode

And this:

(foo, bar) => console.log("You gave me", foo, "and", bar);

Enter fullscreen mode Exit fullscreen mode

But this is not:

foo, bar => console.log("While I won't run!");

Enter fullscreen mode Exit fullscreen mode

Important note

If you need to do anything at all with that single parameter, you need brackets. For example - need to add a TypeScript type? Brackets. Need to destructure? Brackets. Want to supply a default parameter? Brackets. And so on.

What this boils down to - just because you can_do something, doesn’t mean you _should. For reference, see Kyle Simpson’s wonderful flowchart.

Things I wish I knew about… JavaScript functions
Brackets flowchart

When to use foo => {bar; return baz} and when foo => bar?

If the function body is a single statement, you can omit the braces. Otherwise, the braces are required.

One statement:

foo => foo + 1

Enter fullscreen mode Exit fullscreen mode

More than one statement:

foo => {
    console.log("You gave me", foo);
    return foo + 1;
}

Enter fullscreen mode Exit fullscreen mode

Closures

Kind of a hybrid - part data, part function. I’ve come across closures before, but JavaScript makes them easier to use than the other languages I’ve spent much time with.

A closure is essentially a function together with the environment present when it was created.

function makeClosure(outerArgument) {
  // Return a function which adds 'outerArgument' to
  // whatever argument it's given.
  return function(innerArgument) {
    return outerArgument + innerArgument;
  }
}

addOne = makeClosure(1)
console.log("Created addOne", addOne);
console.log("Two plus one is", addOne(2));

Enter fullscreen mode Exit fullscreen mode

Which outputs:

$ node closure.js
Created addOne [Function (anonymous)]
Two plus one is 3

Enter fullscreen mode Exit fullscreen mode

Note that the function returned is anonymous, simply because we didn’t name It in makeClosure. It’s quite possible to name it, though I haven’t found it to serve much purpose (so far).

That’s a trivia example of a closure - for a more useful one see my other blog post on using Axios.

Conclusion

I hope that’s been a useful introduction for someone — wish I’d known these when I started with JavaScript!

Top comments (2)

Collapse
 
moopet profile image
Ben Sinclair

Apart from anything it saves coming up with lots of different names for anonymous functions

Hang on a second. Anonymous functions don't have names, that's why they're called "anonymous"!

Collapse
 
arafel profile image
Paul Walker

Good point, well made. :)

I think I was having a brain hiccup at the time, for some reason I was thinking functions declared with function have to be named - but of course they don't. Thanks for chipping in. :)