diff --git a/1-js/99-js-misc/02-eval/1-eval-calculator/task.md b/1-js/99-js-misc/02-eval/1-eval-calculator/task.md index 3ebf7272..ece43ec9 100644 --- a/1-js/99-js-misc/02-eval/1-eval-calculator/task.md +++ b/1-js/99-js-misc/02-eval/1-eval-calculator/task.md @@ -6,6 +6,6 @@ importance: 4 Create a calculator that prompts for an arithmetic expression and returns its result. -There's no need to check the expression for correctness in this task. +There's no need to check the expression for correctness in this task. Just evaluate and return the result. [demo] diff --git a/1-js/99-js-misc/02-eval/article.md b/1-js/99-js-misc/02-eval/article.md index 1f3b487a..73e8424d 100644 --- a/1-js/99-js-misc/02-eval/article.md +++ b/1-js/99-js-misc/02-eval/article.md @@ -1,6 +1,6 @@ # Eval: run a code string -The built-in `eval` function allows to execute a string of `code`.; +The built-in `eval` function allows to execute a string of code. The syntax is: @@ -15,7 +15,9 @@ let code = 'alert("Hello")'; eval(code); // Hello ``` -A call to `eval` returns the result of the last statement. +A string of code may be long, contain line breaks, function declarations, variables and so on. + +The result of `eval` is the result of the last statement. For example: ```js run @@ -23,7 +25,12 @@ let value = eval('1+1'); alert(value); // 2 ``` -The code is executed in the current lexical environment, so it can see outer variables: +```js run +let value = eval('let i = 0; ++i'); +alert(value); // 1 +``` + +The eval'ed code is executed in the current lexical environment, so it can see outer variables: ```js run no-beautify let a = 1; @@ -68,13 +75,13 @@ The reason is simple: long, long time ago JavaScript was a much weaker language, Right now, there's almost no reason to use `eval`. If someone is using it, there's a good chance they can replace it with a modern language construct or a [JavaScript Module](info:modules). -Still, if you're sure you need to dynamically `eval` a string of code, please note that its ability to access outer variables has side-effects. +Please note that its ability to access outer variables has side-effects. -Code minifiers (tools used before JS gets to production, to compress it) replace local variables with shorter ones for brewity. That's usually safe, but not if `eval` is used, as it may reference them. So minifiers don't replace all local variables that might be visible from `eval`. That negatively affects code compression ratio. +Code minifiers (tools used before JS gets to production, to compress it) replace local variables with shorter ones for optimization. That's usually safe, but not if `eval` is used, as it may reference them. So minifiers don't replace all local variables that might be visible from `eval`. That negatively affects code compression ratio. Using outer local variables inside `eval` is a bad programming practice, as it makes maintaining the code more difficult. -There are two ways how to evade any eval-related problems. +There are two ways how to be totally safe from such problems. **If eval'ed code doesn't use outer variables, please call `eval` as `window.eval(...)`:** @@ -88,7 +95,7 @@ let x = 1; } ``` -**If your code needs local variables, execute it with `new Function` and pass them as arguments:** +**If eval'ed code needs local variables, change `eval` to `new Function` and pass them as arguments:** ```js run let f = new Function('a', 'alert(a)'); diff --git a/2-ui/2-events/05-dispatch-events/article.md b/2-ui/2-events/05-dispatch-events/article.md index ce046b73..a272db30 100644 --- a/2-ui/2-events/05-dispatch-events/article.md +++ b/2-ui/2-events/05-dispatch-events/article.md @@ -2,9 +2,9 @@ We can not only assign handlers, but also generate events from JavaScript. -Custom events can be used to create "graphical components". For instance, a root element of the menu may trigger events telling what happens with the menu: `open` (menu open), `select` (an item is selected) and so on. +Custom events can be used to create "graphical components". For instance, a root element of our own JS-based menu may trigger events telling what happens with the menu: `open` (menu open), `select` (an item is selected) and so on. Another code may listen to the events and observe what's happening with the menu. -Also we can generate built-in events like `click`, `mousedown` etc, that may be good for testing. +We can generate not only completely new events, that we invent for our own purposes, but also built-in ones, such as `click`, `mousedown` etc. That may be helpful for automated testing. ## Event constructor @@ -27,9 +27,9 @@ Arguments: ## dispatchEvent -After an event object is created, we should "run" it on an element using the call `elem.dispatchEvent(event)`. +After an event object is created, we should "run" it on an element using the call `elem.dispatchEvent(event)`. -Then handlers react on it as if it were a regular built-in event. If the event was created with the `bubbles` flag, then it bubbles. +Then handlers react on it as if it were a regular browser event. If the event was created with the `bubbles` flag, then it bubbles. In the example below the `click` event is initiated in JavaScript. The handler works same way as if the button was clicked: @@ -129,11 +129,11 @@ alert(event.clientX); // undefined, the unknown property is ignored! Technically, we can work around that by assigning directly `event.clientX=100` after creation. So that's a matter of convenience and following the rules. Browser-generated events always have the right type. -The full list of properties for different UI events is in the specification, for instance [MouseEvent](https://www.w3.org/TR/uievents/#mouseevent). +The full list of properties for different UI events is in the specification, for instance, [MouseEvent](https://www.w3.org/TR/uievents/#mouseevent). ## Custom events -For our own, custom events like `"hello"` we should use `new CustomEvent`. Technically [CustomEvent](https://dom.spec.whatwg.org/#customevent) is the same as `Event`, with one exception. +For our own, completely new events types like `"hello"` we should use `new CustomEvent`. Technically [CustomEvent](https://dom.spec.whatwg.org/#customevent) is the same as `Event`, with one exception. In the second argument (object) we can add an additional property `detail` for any custom information that we want to pass with the event. @@ -158,23 +158,25 @@ For instance: The `detail` property can have any data. Technically we could live without, because we can assign any properties into a regular `new Event` object after its creation. But `CustomEvent` provides the special `detail` field for it to evade conflicts with other event properties. -The event class tells something about "what kind of event" it is, and if the event is custom, then we should use `CustomEvent` just to be clear about what it is. +Besides, the event class describes "what kind of event" it is, and if the event is custom, then we should use `CustomEvent` just to be clear about what it is. ## event.preventDefault() -We can call `event.preventDefault()` on a script-generated event if `cancelable:true` flag is specified. +Many browser events have a "default action", such as nagivating to a link, starting a selection, and so on. -Of course, for custom events, with names unknown for the browser, there are no "default browser actions". But our code may plan its own actions after `dispatchEvent`. +For new, custom events, there are definitely no default browser actions, but a code that dispatches such event may have its own plans what to do after triggering the event. -The call of `event.preventDefault()` is a way for the handler to send a signal that those actions should be canceled. +By calling `event.preventDefault()`, an event handler may send a signal that those actions should be canceled. -In that case the call to `elem.dispatchEvent(event)` returns `false`. And the event-generating code knows that the processing shouldn't continue. +In that case the call to `elem.dispatchEvent(event)` returns `false`. And the code that dispatched it knows that it shouldn't continue. -For instance, in the example below there's a `hide()` function. It generates the `"hide"` event on the element `#rabbit`, notifying all interested parties that the rabbit is going to hide. +Let's see a practical example - a hiding rabbit (could be a closing menu or something else). -A handler set by `rabbit.addEventListener('hide',...)` will learn about that and, if it wants, can prevent that action by calling `event.preventDefault()`. Then the rabbit won't hide: +Below you can see a `#rabbit` and `hide()` function that dispatches `"hide"` event on it, to let all interested parties know that the rabbit is going to hide. -```html run refresh +Any handler can listen to that event with `rabbit.addEventListener('hide',...)` and, if needed, cancel the action using `event.preventDefault()`. Then the rabbit won't disappear: + +```html run refresh autorun
|\ /| \|_|/ @@ -182,6 +184,7 @@ A handler set by `rabbit.addEventListener('hide',...)` will learn about that and =\_Y_/= {>o<}+ ``` +Обратите внимание: событие должно иметь флаг `cancelable: true`, иначе вызов `event.preventDefault()` будет проигнорирован. ## Events-in-events are synchronous @@ -219,11 +219,10 @@ Then the control jumps to the nested event handler, and after it goes back. For instance, here the nested `menu-open` event is processed synchronously, during the `onclick`: -```html run +```html run autorun ``` -Please note that the nested event `menu-open` bubbles up and is handled on the `document`. The propagation of the nested event is fully finished before the processing gets back to the outer code (`onclick`). +The output order is: 1 -> nested -> 2. + +Please note that the nested event `menu-open` fully bubbles up and is handled on the `document`. The propagation and handling of the nested event must be fully finished before the processing gets back to the outer code (`onclick`). That's not only about `dispatchEvent`, there are other cases. JavaScript in an event handler can call methods that lead to other events -- they are too processed synchronously. -If we don't like it, we can either put the `dispatchEvent` (or other event-triggering call) at the end of `onclick` or wrap it in zero-delay `setTimeout`: +If we don't like it, we can either put the `dispatchEvent` (or other event-triggering call) at the end of `onclick` or, maybe better, wrap it in zero-delay `setTimeout`: ```html run