js
@maxavNested scope
JavaScript distinguishes not just global and local bindings. Blocks and functions can be created inside other blocks and functions, producing multiple degrees of locality.
For example, this function—which outputs the ingredients needed to make a batch of hummus—has another function inside it:
const hummus = function(factor) { const ingredient = function(amount, unit, name) { let ingredientAmount = amount * factor; if (ingredientAmount > 1) { unit += "s"; } console.log(`${ingredientAmount} ${unit} ${name}`); }; ingredient(1, "can", "chickpeas"); ingredient(0.25, "cup", "tahini"); ingredient(0.25, "cup", "lemon juice"); ingredient(1, "clove", "garlic"); ingredient(2, "tablespoon", "olive oil"); ingredient(0.5, "teaspoon", "cumin"); };
The code inside the ingredient
function can see the factor
binding from the outer function. But its local bindings, such as unit
or ingredientAmount
, are not visible in the outer function.
The set of bindings visible inside a block is determined by the place of that block in the program text. Each local scope can also see all the local scopes that contain it, and all scopes can see the global scope. This approach to binding visibility is called lexical scoping.
Arrow functions
There’s a third notation for functions, which looks very different from the others. Instead of the function
keyword, it uses an arrow (=>
) made up of an equal sign and a greater-than character (not to be confused with the greater-than-or-equal operator, which is written >=
).
const power = (base, exponent) => { let result = 1; for (let count = 0; count < exponent; count++) { result *= base; } return result; };
The arrow comes after the list of parameters and is followed by the function’s body. It expresses something like “this input (the parameters) produces this result (the body)”.
When there is only one parameter name, you can omit the parentheses around the parameter list. If the body is a single expression, rather than a block in braces, that expression will be returned from the function. So, these two definitions of square
do the same thing:
const square1 = (x) => { return x * x; }; const square2 = x => x * x;
When an arrow function has no parameters at all, its parameter list is just an empty set of parentheses.
const horn = () => { console.log("Toot"); };
There’s no deep reason to have both arrow functions and function
expressions in the language. Apart from a minor detail, which we’ll discuss in Chapter 6, they do the same thing. Arrow functions were added in 2015, mostly to make it possible to write small function expressions in a less verbose way. We’ll be using them a lot in Chapter 5.