You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: getting-started/ch2.md
+134-1
Original file line number
Diff line number
Diff line change
@@ -232,4 +232,137 @@ The `err` is a block-scoped variable that exists only inside the `catch` clause,
232
232
233
233
## Functions
234
234
235
-
TODO
235
+
The word "function" has a variety of meanings in programming. For example, in the world of Functional Programming, "function" has a precise mathematical definition and implies a strict set of rules to abide by.
236
+
237
+
In JS, we should consider "function" to take the broader meaning of "procedure": a collection of statements that can be invoked one or more times, may be provided some inputs, and may give back one or more outputs.
238
+
239
+
In the good ol' days of JS, there was just one way to define a function:
240
+
241
+
```js
242
+
functionawesomeFunction(coolThings) {
243
+
// ..
244
+
return amazingStuff;
245
+
}
246
+
```
247
+
248
+
This is called a function declaration because it appears as a statement by itself, not as an expression that's part of another statement. The association between the identifier `awesomeFunction` and the function value happens immediately during the compile phase of the code, before that code is executed.
249
+
250
+
By contrast, a function expression can be defined like this:
251
+
252
+
```js
253
+
// let awesomeFunction = ..
254
+
// const awesomeFunction = ..
255
+
varawesomeFunction=function(coolThings) {
256
+
// ..
257
+
return amazingStuff;
258
+
};
259
+
```
260
+
261
+
This function is an expression that is assigned to the variable `awesomeFunction`. Different from the function declaration form, a function expression is not associated with its identifier until that statement during runtime.
262
+
263
+
The function expression above is referred to as an *anonymous function expression*, since it has no name identifier between the `function` keyword and the `(..)` parameter list. This point confuses many JS developers because as of ES6, JS performs a "name inference" on an anonymous function:
264
+
265
+
```js
266
+
awesomeFunction.name;
267
+
// "awesomeFunction"
268
+
```
269
+
270
+
The `name` property of a function will reveal either its directly given name (in the case of a declaration) or its inferred name in the case of an anonymous function expression. That value is generally used by developer tools when inspecting a function value or when reporting an error stack trace.
271
+
272
+
So even an anonymous function expression *might* get a name. However, name inference only happens in limited cases such as when the function expression is assigned (with `=`). If you pass a function expression as an argument to a function call, for example, no name inference occurs, the `name` property will be an empty string, and the developer console will usually report "(anonymous function)".
273
+
274
+
Even if a name is inferred, **it's still an anonymous function.** Why? Because the inferred name is a metadata string value, not an available identifier to refer to the function. An anonymous function doesn't have an identifier to use to refer to itself from inside itself -- for recursion, event unbinding, etc.
275
+
276
+
Compare the anonymous function expression form to:
277
+
278
+
```js
279
+
// let awesomeFunction = ..
280
+
// const awesomeFunction = ..
281
+
varawesomeFunction=functionsomeName(coolThings) {
282
+
// ..
283
+
return amazingStuff;
284
+
};
285
+
286
+
awesomeFunction.name;
287
+
// "someName"
288
+
```
289
+
290
+
This function expression is a *named function expression*, since the identifier `someName` is directly associated with the function expression at compile time; the association with the identifier `awesomeFunction` still doesn't happen until runtime at the time of that statement. Those two identifiers don't have to match; sometimes it makes sense to have them be different, othertimes it's better to have them be the same.
291
+
292
+
Notice also that the explicit function name, the identifier `someName`, takes precedence when assignging a *name* for the `name` property.
293
+
294
+
Should function expressions be named or anonymous? Opinions vary widely on this. Most developers tend to be unconcerned with using anonymous functions. They're shorter, and unquestionably more common in the broad sphere of JS code out there.
295
+
296
+
| MY TAKE: |
297
+
| :--- |
298
+
| If a function exists in your program, it has a purpose; otherwise, take it out! If it has a purpose, it has a natural name that describes that purpose. If it has a name, you the code author should include that name in the code, so that the reader does not have to infer that name from reading and mentally executing that function's source code. Even a trivial function body like `x * 2` has to be read to infer a name like "double" or "multBy2"; that brief extra mental work is unnecessary when you could just take a second to name the function "double" or "multBy2" *once*, saving the reader that repeated mental work every time it's read in the future. |
299
+
300
+
There are, regretably in some respects, many other function definition forms in JS in 2019.
301
+
302
+
Here are some more declaration forms:
303
+
304
+
```js
305
+
// generator function declaration
306
+
function*two() { .. }
307
+
308
+
// async function declaration
309
+
asyncfunctionthree() { .. }
310
+
311
+
// async generator function declaration
312
+
asyncfunction*four() { .. }
313
+
314
+
// named function export declaration (ES6 modules)
315
+
exportfunctionfive() { .. }
316
+
```
317
+
318
+
And here are some more of the (many!) function expression forms:
319
+
320
+
```js
321
+
// IIFE
322
+
(function(){ .. })();
323
+
(functionnamedIIFE(){ .. })();
324
+
325
+
// asynchronous IIFE
326
+
(asyncfunction(){ .. })();
327
+
(asyncfunctionnamedAIIFE(){ .. })();
328
+
329
+
// arrow function expressions
330
+
var f;
331
+
f= () =>42;
332
+
f=x=> x *2;
333
+
f= (x) => x *2;
334
+
f= (x,y) => x * y;
335
+
f=x=> ({ x: x *2 });
336
+
f=x=> { return x *2; };
337
+
f =asyncx=> {
338
+
var y =awaitdoSomethingAsync(x);
339
+
return y *2;
340
+
};
341
+
someOperation( x=> x *2 );
342
+
// ..
343
+
```
344
+
345
+
Keep in mind that arrow function expressions are **syntactically anonymous**, meaning the syntax doesn't provide a way to provide a direct name identifier for the function. The function expression may get an inferred name, but only if it's one of the assignment forms, not in the (more common!) form of being passed as a function call argument (as in the last line of the snippet).
346
+
347
+
Functions can also be specified in class definitions and object literal definitions. They're typically referred to as "methods" when in these forms, though in JS this term doesn't have much observable difference over "function".
348
+
349
+
```js
350
+
classSomethingKindaGreat {
351
+
coolMethod() { .. } // look, no commas!
352
+
boringMethod() { .. }
353
+
}
354
+
355
+
var EntirelyDifferent = {
356
+
coolMethod() { .. }, // don't forget the comma!
357
+
boringMethod() { .. },
358
+
359
+
// old-school (anonymous) function expression
360
+
oldSchool:function() { .. }
361
+
};
362
+
```
363
+
364
+
Phew! That's a lot of different ways to define functions.
365
+
366
+
There's no simple shortcut path here, you just have to get really used to all the function forms so you can recognize them in existing code and use them appropriately in the code you write. Study them closely and practice!
0 commit comments