2
$\begingroup$

I'm teaching a a high-school classes on front-end JavaSript development. What is overwhelming in specifically JavaScript is the large number of seemingly disparate ways of doing the same thing. Like functions. I've identified three ways of declaring functions:

  1. Classic: function <name> ( <param> ) { <body }
  2. (fat) Arrow: const <name> = ( <param-list> ) => { <body }
  3. Class member: class <class-name> { <name> ( <param-list> ) { <body> }

As I tend to use and push the module and encapsulation traits in JavaScript I also want to go with the latter but omitting the keyword function makes it less transferable to learn other languages. Number 2. has it benefits (immutable and used for anonymous or lambda) and pitfalls (no hoisting) and 1. has the clear advantage of looking more like other imperative and oop languages and makes it clear that it is a function by saying so.

What should I be starting with?

$\endgroup$

1 Answer 1

3
$\begingroup$

The differences you mention are pretty negligible, so whichever style students want to use should be fine. It's unfortunate that there are multiple styles, but it's normal for mainstream languages, and most of the critical differences (mostly binding this) won't matter to students at first.


Here are responses to your specific concerns:

hoisting

I don't think hoisting (or lack thereof) is a big issue. Generally speaking, it's sensible to expect things to be defined before they're used, so if anything, this is a point in favor of const over function. Hoisting is only a pitfall if you're used to it, and then it's not there all of a sudden.

If students are arriving with some exposure to an OO language like Java or C#, they may be used to "hoisting", but functions are always methods in classes and order doesn't matter. That's its own thing and the behavior is no different in JS classes.

omitting the keyword function makes it less transferable to teaching learning other languages

Actually, most languages don't use the word function in their definitions of functions: Java, C#, C++ and C are a stylistic family that use something like int foo() {} to declare a function. Ruby and Python use def (as in Def Jam). Perl uses sub. Rust uses fn, Kotlin uses fun and Swift and Go use func, close but not quite. Bash has an optional function keyword (but it's optional, and Bash!). Only R, Lua and PHP come to mind as explicitly using function. PHP's arrow equivalent uses fn because it's really annoying to write function in every array_map call, like JS.

[function] has the clear advantage of looking more like other imperative and oop languages

I'll grant that the lack of => and required braces makes a function definition feel less "functional" and closer to imperative Java/C++/C#-family languages. JS isn't special in having anonymous/lambda/arrow-style functions, only somewhat special in that they're typically used for top-level assignments.

As I tend to use the module and encapsulation traits in JavaScript...

Using modules to group functions doesn't imply classes, necessarily. By the time classes are introduced to students (usually too early in most curricula, in my opinion, given that I don't use them all that often in day to day JS coding--closures and modules without classes are usually plenty of encapsulation), students will be able to navigate the unfortunate fact that the syntax differs between standalone functions and class methods.

Actually, object literals are probably the worst offender here, since:

const o = {
  foo() {},
  bar: () => {},
  baz: function () {},
}

The top style is preferred, but the choice mainly boils down to how you want to bind this, which is generally out of scope for most first semester students.

[fat arrow] is immutable

I think you mean "reassignable", since you can technically add properties and mutate the arrow function, even if const. const saves a rare function redefinition name clash, but that's about it--not enough to force a decision either way. Also, if students don't use const, it's reassignable as well as mutable.

[fat arrow] is used for anonymous or lambda

Yeah, this is common, although function can be used for any anonymous or "lambda" (not actually a thing in JS; I'd avoid the term) cases. They'll definitely be seeing ["a", "b", "c"].forEach(e => console.log(e)) rather than ["a", "b", "c"].forEach(function (e) {console.log(e);}) before long, which is why you can't get away with ignoring arrow syntax, even if it's not actually necessary.

I'd be remiss to mention one significant pitfall with arrow functions, which is the implicit return value. Students will probably be bitten by mistakes like [1, 2, 3].map(e => { e * e }) and [1, 2, 3].map(e => return e * e) at some point and wonder why they're getting weird results and syntax errors. You can cover these cases when the time is right, and start out with always using braces and return.

Ditto for arrow argument parentheses--I'm used to omitting them on single-argument parameters, but for beginners it's probably better to always use them (although, yet again, they'll inevitably encounter them in the wild).

On a similar topic, should students use the var keyword since it's closer to "variable" than let or const, which probably make little sense initially? I'd suggest not, since var is worse in every regard than let and const. As with the function versus arrow debate, I'll mention that var exists in case they see it in the wild, but tell students to avoid using it in their own programs unless they're trying to write code that'll run in old IE versions without transpilation.


If you've read through this post and you're still on the fence, then I'd recommend using arrow functions and const for everything. It's common to see these days, will unavoidably be seen in callbacks, and has more predictable this behavior. You'll still need to mention that students may encounter the function version from time to time, and that it's occasionally used to allow special this binding in callbacks. You can skip the second half of that explanation if they're not to objects and this yet.

On the other hand, if you feel function is clearer for beginners, that's an acceptable position. Go for it. But as above, you'll still have to introduce arrow functions more or less as soon as you get to callbacks. A rule like "use function for all standalone function definitions and use arrow functions for all callbacks" is a sensible approach to take, although I'd leave the decision ultimately up to students and wouldn't deduct points (I'd issue a warning for mixing styles arbitrarily).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.