up
This commit is contained in:
parent
649ad4b05e
commit
acee6949c9
7 changed files with 35 additions and 35 deletions
|
@ -28,9 +28,9 @@ Different engines have different "codenames", for example:
|
||||||
- [Gecko](https://en.wikipedia.org/wiki/Gecko_(software)) -- in Firefox.
|
- [Gecko](https://en.wikipedia.org/wiki/Gecko_(software)) -- in Firefox.
|
||||||
- ...There are other codenames like "Trident", "Chakra" for different versions of IE, "ChakraCore" for Microsoft Edge, "Nitro" and "SquirrelFish" for Safari etc.
|
- ...There are other codenames like "Trident", "Chakra" for different versions of IE, "ChakraCore" for Microsoft Edge, "Nitro" and "SquirrelFish" for Safari etc.
|
||||||
|
|
||||||
These terms above are good to remember, because they are used in developer articles in the internet. We'll use them too. For instance, if "a feature X is supported by V8", then it probably works in Chrome and Opera.
|
The terms above are good to remember, because they are used in developer articles in the internet. We'll use them too. For instance, if "a feature X is supported by V8", then it probably works in Chrome and Opera.
|
||||||
|
|
||||||
```smart header="How the engines work?"
|
```smart header="How engines work?"
|
||||||
|
|
||||||
Engines are complicated. But the basics are easy.
|
Engines are complicated. But the basics are easy.
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ Engines are complicated. But the basics are easy.
|
||||||
2. The engine (embedded if it's a browser) reads the script ("parses") and converts ("compiles") it to the machine language.
|
2. The engine (embedded if it's a browser) reads the script ("parses") and converts ("compiles") it to the machine language.
|
||||||
3. And then it runs, pretty fast.
|
3. And then it runs, pretty fast.
|
||||||
|
|
||||||
The engine applies optimizations on every stage of the process. It even watches the script as it runs, analyzes the data which flows through it and applies optimizations to the machine-code basing on that knowledge.
|
The engine applies optimizations on every stage of the process. It even watches the script as it runs, analyzes the data which flows through it and applies optimizations to the machine-code basing on that knowledge. That's why the code runs fast.
|
||||||
```
|
```
|
||||||
|
|
||||||
## What can in-browser JavaScript do?
|
## What can in-browser JavaScript do?
|
||||||
|
@ -57,7 +57,7 @@ For instance, in-browser JavaScript is able to:
|
||||||
- Get and set cookies, ask questions to the visitor, show messages.
|
- Get and set cookies, ask questions to the visitor, show messages.
|
||||||
- Remember the data on the browser side ("local storage").
|
- Remember the data on the browser side ("local storage").
|
||||||
|
|
||||||
## What can in-browser JavaScript NOT do?
|
## What in-browser JavaScript can NOT do?
|
||||||
|
|
||||||
JavaScript abilities in the browser are limited for the sake of the user's safety. The aim is to prevent an evil webpage from accessing private information or harming the user's data.
|
JavaScript abilities in the browser are limited for the sake of the user's safety. The aim is to prevent an evil webpage from accessing private information or harming the user's data.
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ There are at least *three* great things about JavaScript:
|
||||||
|
|
||||||
Combined, these 3 things only exist in JavaScript and no other browser technology.
|
Combined, these 3 things only exist in JavaScript and no other browser technology.
|
||||||
|
|
||||||
That's what makes JavaScript unique. That's why it is the most widespread way of creating browser interfaces.
|
That's what makes JavaScript unique. That's why it's the most widespread tool to create browser interfaces.
|
||||||
|
|
||||||
While planning to learn a new technology, it's beneficial to check its perspectives. So let's move on to the modern trends that include new languages and browser abilities.
|
While planning to learn a new technology, it's beneficial to check its perspectives. So let's move on to the modern trends that include new languages and browser abilities.
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,6 @@ alert("some code");
|
||||||
Only comments may appear above `"use strict"`.
|
Only comments may appear above `"use strict"`.
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
```smart header="`use strict` for functions"
|
```smart header="`use strict` for functions"
|
||||||
We will learn functions (a way to group commands) soon.
|
We will learn functions (a way to group commands) soon.
|
||||||
|
|
||||||
|
@ -59,6 +58,7 @@ It is recommended to always start a script with `"use strict"`, for the followin
|
||||||
|
|
||||||
1. First, all modern browsers support it. Only outdated ones like Internet Explorer 9 and below do not.
|
1. First, all modern browsers support it. Only outdated ones like Internet Explorer 9 and below do not.
|
||||||
2. Second, the modern JavaScript actually forces us into the strict mode. There are several modern language features like "classes" and "modules" that enable strict mode automatically. So, it's hard to evade it.
|
2. Second, the modern JavaScript actually forces us into the strict mode. There are several modern language features like "classes" and "modules" that enable strict mode automatically. So, it's hard to evade it.
|
||||||
|
3. The last, but not the least: strict mode is the modern mode. Makes the language a little bit better in few aspects. We'll see that as we study more language features.
|
||||||
|
|
||||||
Here in the tutorial, all code (where not explicitly noted otherwise) works in `"use strict"`. We concentrate on modern JavaScript. But there will be notes about what happens without `"use strict"`, so that you can understand what's going on if you forget it or if you're working with an outdated script that doesn't have it.
|
Here in the tutorial, all code (where not explicitly noted otherwise) works in `"use strict"`. We concentrate on modern JavaScript. But there will be notes about what happens without `"use strict"`, so that you can understand what's going on if you forget it or if you're working with an outdated script that doesn't have it.
|
||||||
|
|
||||||
|
@ -67,4 +67,4 @@ Here in the tutorial, all code (where not explicitly noted otherwise) works in `
|
||||||
- The `"use strict"` directive switches the engine to the "modern" mode, changing the behavior of some built-in features.
|
- The `"use strict"` directive switches the engine to the "modern" mode, changing the behavior of some built-in features.
|
||||||
- Several modern features of the language enable `"use strict"` implicitly, so it's quite hard to evade it.
|
- Several modern features of the language enable `"use strict"` implicitly, so it's quite hard to evade it.
|
||||||
|
|
||||||
It's always recommended to start scripts with `"use strict"`. All examples in this book assume so, unless (very rarely) specified otherwise.
|
It's always recommended to start scripts with `"use strict"`. All examples in this tutorial assume so, unless (very rarely) specified otherwise.
|
||||||
|
|
|
@ -37,10 +37,10 @@ It is recommended to use figure brackets every time with `if`, even if there's o
|
||||||
|
|
||||||
The `if (…)` operator evaluates the expression in parentheses and converts it to the boolean type.
|
The `if (…)` operator evaluates the expression in parentheses and converts it to the boolean type.
|
||||||
|
|
||||||
Let's recall the conversion rules:
|
Let's recall the conversion rules from the chapter <info:type-conversions>:
|
||||||
|
|
||||||
- A number `0`, an empty string `""`, `null`, `undefined` and `NaN` are `false`,
|
- A number `0`, an empty string `""`, `null`, `undefined` and `NaN` become `false`. Because of that they are called "falsy" values.
|
||||||
- Other values -- `true`.
|
- Other values become `true`, so they are called "truthy".
|
||||||
|
|
||||||
So, the code under this condition would never execute:
|
So, the code under this condition would never execute:
|
||||||
|
|
||||||
|
|
|
@ -189,13 +189,11 @@ JavaScript engines apply many optimizations to make it run faster and not affect
|
||||||
|
|
||||||
Some of the optimizations:
|
Some of the optimizations:
|
||||||
|
|
||||||
- **Generational collection** -- objects are split into two sets: "new ones" and "old ones". Many objects appear, then do their job and die fast, so they can be cleaned up aggressively. Those that survive for long enough, become "old".
|
- **Generational collection** -- objects are split into two sets: "new ones" and "old ones". Many objects appear, do their job and die fast, they can be cleaned up aggressively. Those that survive for long enough, become "old" and are examined less often.
|
||||||
- **Incremental collection** -- if there are many objects, and we try to walk and mark the whole object set at once, it may take some time and introduce visible delays in the execution. So the engine tries to split the job into pieces. Then pieces are executed one at a time. That requires some extra bookkeeping between them to track changes.
|
- **Incremental collection** -- if there are many objects, and we try to walk and mark the whole object set at once, it may take some time and introduce visible delays in the execution. So the engine tries to split the garbage collection into pieces. Then the pieces are executed one by one, separately. That requires some extra bookkeeping between them to track changes, but we have many tiny delays instead of a big one.
|
||||||
- **Idle-time collection** -- the garbage collector tries to run only while the CPU is idle, to reduce the possible effect on the execution.
|
- **Idle-time collection** -- the garbage collector tries to run only while the CPU is idle, to reduce the possible effect on the execution.
|
||||||
|
|
||||||
There are other optimizations and flavours of garbage collection algorithms. As much as I'd like to describe them here, I have to hold off, because different engines implement different tweaks and techniques.
|
There are other optimizations and flavours of garbage collection algorithms. As much as I'd like to describe them here, I have to hold off, because different engines implement different tweaks and techniques. And -- what's even more important, things change as engines develop, so going deeper "in advance", without a real need is probably not worth that. Unless, of course, it is a matter of pure interest, then there will be some links for you below.
|
||||||
|
|
||||||
And -- what's even more important, things change as engines develop, so going really deep "in advance", without a real need is probably not worth that. Unless, of course, it is a matter of pure interest, then there will be some links for you below.
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
|
|
@ -159,14 +159,14 @@ alert( clone[id] ); // 123
|
||||||
There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`).
|
There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`).
|
||||||
|
|
||||||
````smart header="Property keys of other types are coerced to strings"
|
````smart header="Property keys of other types are coerced to strings"
|
||||||
We can only use strings or symbols as keys in objects. Other types are coerced to strings.
|
We can only use strings or symbols as keys in objects. Other types are converted to strings.
|
||||||
|
|
||||||
For instance:
|
For instance, a number `0` becomes a string `"0"` when used as a property key:
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
let obj = {
|
let obj = {
|
||||||
0: "test" // same as "0": "test"
|
0: "test" // same as "0": "test"
|
||||||
}
|
};
|
||||||
|
|
||||||
// both alerts access the same property (the number 0 is converted to string "0")
|
// both alerts access the same property (the number 0 is converted to string "0")
|
||||||
alert( obj["0"] ); // test
|
alert( obj["0"] ); // test
|
||||||
|
@ -176,11 +176,11 @@ alert( obj[0] ); // test (same property)
|
||||||
|
|
||||||
## Global symbols
|
## Global symbols
|
||||||
|
|
||||||
Normally, all symbols are different. But sometimes we want same-named symbols to be the same.
|
As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be same entities.
|
||||||
|
|
||||||
For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property.
|
For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property.
|
||||||
|
|
||||||
To achieve that, there exists a *global symbol registry*. We can create symbols in it and and access them later, and it guarantees that repeated accesses by the same name return exactly the same symbol.
|
To achieve that, there exists a *global symbol registry*. We can create symbols in it and access them later, and it guarantees that repeated accesses by the same name return exactly the same symbol.
|
||||||
|
|
||||||
In order to create or read a symbol in the registry, use `Symbol.for(name)`.
|
In order to create or read a symbol in the registry, use `Symbol.for(name)`.
|
||||||
|
|
||||||
|
@ -230,7 +230,9 @@ alert( Symbol.keyFor(Symbol.for("name")) ); // name, global symbol
|
||||||
alert( Symbol.keyFor(Symbol("name2")) ); // undefined, non-global symbol
|
alert( Symbol.keyFor(Symbol("name2")) ); // undefined, non-global symbol
|
||||||
```
|
```
|
||||||
|
|
||||||
For non-global symbols, the name is only used for debugging purposes.
|
So, for global symbols the name may be indeed helpful, as we can get a symbol by id.
|
||||||
|
|
||||||
|
And for non-global symbols the name is only used for debugging purposes, like printing out a symbol.
|
||||||
|
|
||||||
## System symbols
|
## System symbols
|
||||||
|
|
||||||
|
|
|
@ -108,11 +108,11 @@ Sometimes `event.stopPropagation()` creates hidden pitfalls that later may becom
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
1. We create a nested menu. Each submenu handles clicks on its elements and calls `stopPropagation` so that outer parts don't trigger.
|
1. We create a nested menu. Each submenu handles clicks on its elements and calls `stopPropagation` so that outer menu don't trigger.
|
||||||
2. Later we decide to catch clicks inside the whole window, to track users' behavior (where people click). Some counters do that. Usually a counter code does that by `document.addEventListener('click'…)`.
|
2. Later we decide to catch clicks on the whole window, to track users' behavior (where people click). Some analytic systems do that. Usually the code uses `document.addEventListener('click'…)` to catch all clicks.
|
||||||
3. Our counter won't work over the area where clicks are stopped by `stopPropagation`. We've got a "dead zone".
|
3. Our analytic won't work over the area where clicks are stopped by `stopPropagation`. We've got a "dead zone".
|
||||||
|
|
||||||
There's usually no real need to prevent the bubbling. One of them is to use custom events, we'll cover them later. Also we can write our data into the `event` object in one handler and read it in another one, so we can pass to handlers on parents information about the processing below.
|
There's usually no real need to prevent the bubbling. A task that seemingly requires that may be solved by other means. One of them is to use custom events, we'll cover them later. Also we can write our data into the `event` object in one handler and read it in another one, so we can pass to handlers on parents information about the processing below.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,14 +138,14 @@ Handlers added using `on<event>`-property or using HTML attributes or using `add
|
||||||
|
|
||||||
To catch an event on the capturing phase, we need to set the 3rd argument of `addEventListener` to `true`.
|
To catch an event on the capturing phase, we need to set the 3rd argument of `addEventListener` to `true`.
|
||||||
|
|
||||||
Actually, there are two possible values for that optional last argument:
|
There are two possible values for that optional last argument:
|
||||||
|
|
||||||
- If it's `false` (default), then the handler is set on the bubbling phase.
|
- If it's `false` (default), then the handler is set on the bubbling phase.
|
||||||
- If it's `true`, then the handler is set on the capturing phase.
|
- If it's `true`, then the handler is set on the capturing phase.
|
||||||
|
|
||||||
Note that while formally there are 3 phases, the 2nd phase ("target phase": the event reached the element) is not handled separately: handlers on both capturing and bubbling phases trigger at that phase.
|
Note that while formally there are 3 phases, the 2nd phase ("target phase": the event reached the element) is not handled separately: handlers on both capturing and bubbling phases trigger at that phase.
|
||||||
|
|
||||||
Handlers on the target element trigger last on the capturing state, and then trigger first on the bubbling stage.
|
If one puts a handler on the target element -- it triggers last on the capturing state, and first on the bubbling stage.
|
||||||
|
|
||||||
Let's see it in action:
|
Let's see it in action:
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,11 @@ And if we increase it in `setInterval`, by making 50 small changes per second, t
|
||||||
The pseudo-code can look like this:
|
The pseudo-code can look like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let fps = 50; // 50 frames per second
|
let delay = 1000 / 50; // in 1 second 50 frames
|
||||||
let timer = setInterval(function() {
|
let timer = setInterval(function() {
|
||||||
if (animation complete) clearInterval(timer);
|
if (animation complete) clearInterval(timer);
|
||||||
else increase style.left
|
else increase style.left
|
||||||
}, 1000 / fps)
|
}, delay)
|
||||||
```
|
```
|
||||||
|
|
||||||
More complete example of the animation:
|
More complete example of the animation:
|
||||||
|
@ -54,13 +54,13 @@ Click for the demo:
|
||||||
|
|
||||||
## requestAnimationFrame
|
## requestAnimationFrame
|
||||||
|
|
||||||
Let's imagine we have several simultaneous animations.
|
Let's imagine we have several animations running simultaneously.
|
||||||
|
|
||||||
If we run them separately, each one with its own `setInterval(..., 20)`, then the browser would have to repaint much more often than every `20ms`.
|
If we run them separately, each one with its own `setInterval(..., 20)`, then the browser would have to repaint much more often than every `20ms`.
|
||||||
|
|
||||||
Each `setInterval` triggers once per `20ms`, but they are independent, so we have several independent runs within `20ms`.
|
Each `setInterval` triggers once per `20ms`, but they are independent, so we have several independent runs within `20ms`.
|
||||||
|
|
||||||
These several independent actions should be grouped together, because it's easier for the browser to redraw things once per `20ms`.
|
These several independent redraws should be grouped together, to make it easier for the browser.
|
||||||
|
|
||||||
In other words, this:
|
In other words, this:
|
||||||
|
|
||||||
|
@ -80,11 +80,11 @@ setInterval(animate2, 20);
|
||||||
setInterval(animate3, 20);
|
setInterval(animate3, 20);
|
||||||
```
|
```
|
||||||
|
|
||||||
There's one more thing to keep in mind. Sometimes when CPU is overloaded or for other reasons it may be better to trigger redraws less often. Not 20, but maybe 200ms.
|
There's one more thing to keep in mind. Sometimes when CPU is overloaded, or there are other reasons to redraw less often. For instance, if the browser tab is hidden, then there's totally no point in drawing.
|
||||||
|
|
||||||
There's a standard [Animation timing](http://www.w3.org/TR/animation-timing/) that provides the function `requestAnimationFrame`.
|
There's a standard [Animation timing](http://www.w3.org/TR/animation-timing/) that provides the function `requestAnimationFrame`.
|
||||||
|
|
||||||
It addresses all those issues and even more.
|
It addresses all these issues and even more.
|
||||||
|
|
||||||
The syntax:
|
The syntax:
|
||||||
```js
|
```js
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue