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

2 2

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. :)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more