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