diff --git a/1-js/06-advanced-functions/06-function-object/article.md b/1-js/06-advanced-functions/06-function-object/article.md index fb9a5798..f6234a6d 100644 --- a/1-js/06-advanced-functions/06-function-object/article.md +++ b/1-js/06-advanced-functions/06-function-object/article.md @@ -3,18 +3,18 @@ As we already know, functions in JavaScript are values. -Every value in JavaScript has the type. What type of value is a function? +Every value in JavaScript has a type. What type is a function? -In JavaScript, a function is an object. +In JavaScript, functions are objects. A good way to imagine functions is as callable "action objects". We can not only call them, but also treat them as objects: add/remove properties, pass by reference etc. ## The "name" property -Function objects contain few sometimes-useable properties. +Function objects contain a few useable properties. -For instance, a function name is accessible as the "name" property: +For instance, a function's name is accessible as the "name" property: ```js run function sayHi() { @@ -24,7 +24,7 @@ function sayHi() { alert(sayHi.name); // sayHi ``` -What's more funny, the name-assigning logic is smart. It also sticks the right name to function that are used in assignments: +What's more funny, the name-assigning logic is smart. It also assigns the correct name to functions that are used in assignments: ```js run let sayHi = function() { @@ -34,7 +34,7 @@ let sayHi = function() { alert(sayHi.name); // sayHi (works!) ``` -Also works if the assignment is done via a default value: +It also works if the assignment is done via a default value: ```js run function f(sayHi = function() {}) { @@ -65,9 +65,7 @@ alert(user.sayHi.name); // sayHi alert(user.sayBye.name); // sayBye ``` -There's no magic though. There are cases when there's no way to figure out the right name. - -Then it's empty, like here: +There's no magic though. There are cases when there's no way to figure out the right name. In that case, the name property empty, like here: ```js // function created inside array @@ -77,7 +75,7 @@ alert( arr[0].name ); // // the engine has no way to set up the right name, so there is none ``` -In practice, most functions do have a name. +In practice, however, most functions do have a name. ## The "length" property @@ -97,14 +95,14 @@ Here we can see that rest parameters are not counted. The `length` property is sometimes used for introspection in functions that operate on other functions. -For instance, in the code below `ask` function accepts a `question` to ask and an arbitrary number of `handler` functions to call. +For instance, in the code below the `ask` function accepts a `question` to ask and an arbitrary number of `handler` functions to call. -When a user answers, it calls the handlers. We can pass two kinds of handlers: +Once a user provides their answer, the function calls the handlers. We can pass two kinds of handlers: -- A zero-argument function, then it is only called for a positive answer. -- A function with arguments, then it is called in any case and gets the answer. +- A zero-argument function, which is only called when the user gives a positive answer. +- A function with arguments, which is called in either case and returns an answer. -The idea is that we have a simple no-arguments handler syntax for positive cases (most frequent variant), but allow to provide universal handlers as well. +The idea is that we have a simple, no-arguments handler syntax for positive cases (most frequent variant), but are able to provide universal handlers as well. To call `handlers` the right way, we examine the `length` property: @@ -158,7 +156,7 @@ A property assigned to a function like `sayHi.counter = 0` does *not* define a l We can treat a function as an object, store properties in it, but that has no effect on its execution. Variables never use function properties and vice versa. These are just parallel words. ``` -Function properties can replace the closure sometimes. For instance, we can rewrite the counter example from the chapter to use a function property: +Function properties can replace closures sometimes. For instance, we can rewrite the counter function example from the chapter to use a function property: ```js run function makeCounter() { @@ -181,9 +179,9 @@ alert( counter() ); // 1 The `count` is now stored in the function directly, not in its outer Lexical Environment. -Is it worse or better than using the closure? +Is it better or worse than using a closure? -The main difference is that if the value of `count` lives in an outer variable, then an external code is unable to access it. Only nested functions may modify it. And if it's bound to function, then such thing is possible: +The main difference is that if the value of `count` lives in an outer variable, then external code is unable to access it. Only nested functions may modify it. And if it's bound to a function, then such a thing is possible: ```js run function makeCounter() { @@ -205,11 +203,11 @@ alert( counter() ); // 10 */!* ``` -So it depends on our aims which variant to choose. +So the choice of implementation depends on our aims. ## Named Function Expression -Named Function Expression or, shortly, NFE, is a term for Function Expressions that have a name. +Named Function Expression, or NFE, is a term for Function Expressions that have a name. For instance, let's take an ordinary Function Expression: @@ -219,7 +217,7 @@ let sayHi = function(who) { }; ``` -...And add a name to it: +And add a name to it: ```js let sayHi = function *!*func*/!*(who) { @@ -227,7 +225,7 @@ let sayHi = function *!*func*/!*(who) { }; ``` -Did we do anything sane here? What's the role of that additional `"func"` name? +Did we achieve anything here? What's the purpose of that additional `"func"` name? First let's note, that we still have a Function Expression. Adding the name `"func"` after `function` did not make it a Function Declaration, because it is still created as a part of an assignment expression. @@ -245,10 +243,10 @@ sayHi("John"); // Hello, John There are two special things about the name `func`: -1. It allows to reference the function from inside itself. +1. It allows the function to reference itself internally. 2. It is not visible outside of the function. -For instance, the function `sayHi` below re-calls itself with `"Guest"` if no `who` is provided: +For instance, the function `sayHi` below calls itself again with `"Guest"` if no `who` is provided: ```js run let sayHi = function *!*func*/!*(who) { @@ -305,9 +303,9 @@ welcome(); // Error, the nested sayHi call doesn't work any more! That happens because the function takes `sayHi` from its outer lexical environment. There's no local `sayHi`, so the outer variable is used. And at the moment of the call that outer `sayHi` is `null`. -The optional name which we can put into the Function Expression is exactly meant to solve this kind of problems. +The optional name which we can put into the Function Expression is meant to solve exactly these kinds of problems. -Let's use it to fix the code: +Let's use it to fix our code: ```js run let sayHi = function *!*func*/!*(who) { @@ -326,9 +324,9 @@ sayHi = null; welcome(); // Hello, Guest (nested call works) ``` -Now it works, because the name `"func"` is function-local. It is not taken from outside (and not visible there). The specification guarantees that it always references the current function. +Now it works, because the name `"func"` is function-local. It is not taken from outside (and not visible there). The specification guarantees that it will always reference the current function. -The outer code still has it's variable `sayHi` or `welcome` later. And `func` is an "internal function name", how it calls itself privately. +The outer code still has it's variable `sayHi` or `welcome`. And `func` is an "internal function name", how the function can call itself internally. ```smart header="There's no such thing for Function Declaration" The "internal name" feature described here is only available for Function Expressions, not to Function Declarations. For Function Declarations, there's just no syntax possibility to add a one more "internal" name. @@ -345,10 +343,10 @@ Here we covered their properties: - `name` -- the function name. Exists not only when given in the function definition, but also for assignments and object properties. - `length` -- the number of arguments in the function definition. Rest parameters are not counted. -If the function is declared as a Function Expression (not in the main code flow), and it carries the name, then it is called Named Function Expression. The name can be used inside to reference itself, for recursive calls or such. +If the function is declared as a Function Expression (not in the main code flow), and it carries the name, then it is called a Named Function Expression. The name can be used inside to reference itself, for recursive calls or such. -Also, functions may carry additional properties. Many well-known JavaScript libraries make a great use of this feature. +Also, functions may carry additional properties. Many well-known JavaScript libraries make great use of this feature. -They create a "main" function and attach many other "helper" functions to it. For instance, the [jquery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`. And then adds `_.clone`, `_.keyBy` and other properties to (see the [docs](https://lodash.com/docs) when you want learn more about them). Actually, they do it to less pollute the global space, so that a single library gives only one global variable. That lowers the chance of possible naming conflicts. +They create a "main" function and attach many other "helper" functions to it. For instance, the [jquery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`. And then adds `_.clone`, `_.keyBy` and other properties to (see the [docs](https://lodash.com/docs) when you want learn more about them). Actually, they do it to lessen their pollution of the global space, so that a single library gives only one global variable. That reduces the possibility of naming conflicts. So, a function can do a useful job by itself and also carry a bunch of other functionality in properties.