Merge branch 'master' into patch-2
This commit is contained in:
commit
1394eae4c2
17 changed files with 89 additions and 76 deletions
|
@ -1,6 +1,6 @@
|
|||
# Operators
|
||||
|
||||
Many operators are known to us from school. It is an addition `+`, a multiplication `*`, a substraction `-` and so on.
|
||||
Many operators are known to us from school. It is an addition `+`, a multiplication `*`, a subtraction `-` and so on.
|
||||
|
||||
In this chapter we concentrate on aspects that are not covered by the school arithmetic.
|
||||
|
||||
|
@ -11,7 +11,7 @@ In this chapter we concentrate on aspects that are not covered by the school ari
|
|||
Before we move on, let's grasp the common terminology.
|
||||
|
||||
- *An operand* -- is what operators are applied to. For instance in multiplication `5 * 2` there are two operands: the left operand is `5`, and the right operand is `2`. Sometimes people say "arguments" instead of "operands".
|
||||
- An operator is *unary* if it has a single operand. For example, the unary minus `"-"` reverses the sign of the number:
|
||||
- An operator is *unary* if it has a single operand. For example, the unary negation `"-"` reverses the sign of the number:
|
||||
|
||||
```js run
|
||||
let x = 1;
|
||||
|
@ -19,16 +19,16 @@ Before we move on, let's grasp the common terminology.
|
|||
*!*
|
||||
x = -x;
|
||||
*/!*
|
||||
alert( x ); // -1, unary minus was applied
|
||||
alert( x ); // -1, unary negation was applied
|
||||
```
|
||||
- An operator is *binary* if it has two operands. The same minus exists in the binary form as well:
|
||||
|
||||
```js run no-beautify
|
||||
let x = 1, y = 3;
|
||||
alert( y - x ); // 2, binary minus substracts values
|
||||
alert( y - x ); // 2, binary minus subtracts values
|
||||
```
|
||||
|
||||
Formally, we're talking about the two different operators here: the unary minus (single operand, reverses the sign) and the binary minus (two operands, substracts).
|
||||
Formally, we're talking about the two different operators here: the unary negation (single operand, reverses the sign) and the binary subtraction (two operands, subtracts).
|
||||
|
||||
## Strings concatenation, binary +
|
||||
|
||||
|
@ -135,11 +135,11 @@ An extract from the [precedence table](https://developer.mozilla.org/en/JavaScri
|
|||
| Precedence | Name | Sign |
|
||||
|------------|------|------|
|
||||
| ... | ... | ... |
|
||||
| 15 | unary plus | `+` |
|
||||
| 15 | unary minus | `-` |
|
||||
| 16 | unary plus | `+` |
|
||||
| 16 | unary negation | `-` |
|
||||
| 14 | multiplication | `*` |
|
||||
| 14 | division | `/` |
|
||||
| 13 | addition (binary) | `+` |
|
||||
| 13 | addition | `+` |
|
||||
| 13 | subtraction | `-` |
|
||||
| ... | ... | ... |
|
||||
| 3 | assignment | `=` |
|
||||
|
@ -194,7 +194,7 @@ alert( a ); // 3
|
|||
alert( c ); // 0
|
||||
```
|
||||
|
||||
In the example above, the result of `(a = b + 1)` is the value which is assigned to `a` (that is `3`). It is then used to substract from `3`.
|
||||
In the example above, the result of `(a = b + 1)` is the value which is assigned to `a` (that is `3`). It is then used to subtract from `3`.
|
||||
|
||||
Funny code, isn't it? We should understand how it works, because sometimes we can see it in 3rd-party libraries, but shouldn't write anything like that ourselves. Such tricks definitely don't make the code clearer and readable.
|
||||
````
|
||||
|
|
|
@ -136,7 +136,7 @@ alert( 0 === false ); // false, because the types are different
|
|||
|
||||
There also exists a "strict non-equality" operator `!==`, as an analogy for `!=`.
|
||||
|
||||
The string equality check operator is a bit longer to write, but makes it obvious what's going on and leaves less space for errors.
|
||||
The strict equality check operator is a bit longer to write, but makes it obvious what's going on and leaves less space for errors.
|
||||
|
||||
## Comparison with null and undefined
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ For example:
|
|||
alert("Hello");
|
||||
```
|
||||
|
||||
The mini-window with the message is called a *modal window*. The word "modal" means that the visitor can't interact with the rest of the page, press other buttons etc, until they deal with the window. In this case -- until they press "OK".
|
||||
The mini-window with the message is called a *modal window*. The word "modal" means that the visitor can't interact with the rest of the page, press other buttons etc, until they have dealt with the window. In this case -- until they press "OK".
|
||||
|
||||
## prompt
|
||||
|
||||
|
@ -101,7 +101,7 @@ We covered 3 browser-specific functions to interact with the visitor:
|
|||
`confirm`
|
||||
: shows a message and waits the user to press "OK" or "CANCEL". It returns `true` for OK and `false` for CANCEL/`key:Esc`.
|
||||
|
||||
All these methods are modal: they pause the script execution and don't let the visitor to interact with the rest of the page until he dismisses them.
|
||||
All these methods are modal: they pause the script execution and don't allow the visitor to interact with the rest of the page until the message has been dismissed.
|
||||
|
||||
There are two limitations shared by all the methods above:
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ if (age > 18) {
|
|||
alert(accessAllowed);
|
||||
```
|
||||
|
||||
The so-called "ternary" or "question mark" operator allows to do that shorter and simpler.
|
||||
The so-called "ternary" or "question mark" operator lets us do that shorter and simpler.
|
||||
|
||||
The operator is represented by a question mark `"?"`. The formal term "ternary" means that the operator has 3 operands. It is actually the one and only operator in JavaScript which has that many.
|
||||
|
||||
|
@ -143,7 +143,7 @@ For example:
|
|||
let accessAllowed = (age > 18) ? true : false;
|
||||
```
|
||||
|
||||
Technically, we can omit parentheses around `age > 14`. The question mark operator has a low precedence. It executes after the comparison `>`, so that'll do the same:
|
||||
Technically, we can omit parentheses around `age > 18`. The question mark operator has a low precedence. It executes after the comparison `>`, so that'll do the same:
|
||||
|
||||
```js
|
||||
// the comparison operator "age > 18" executes first anyway
|
||||
|
|
|
@ -16,7 +16,7 @@ The "OR" operator is represented with two vertical line symbols:
|
|||
result = a || b;
|
||||
```
|
||||
|
||||
In classical programming, logical OR is meant to manipulate boolean values. If any of it's arguments is `true`, then it returns `true`, otherwise -- returns `false`.
|
||||
In classical programming, logical OR is meant to manipulate boolean values only. If any of its arguments are `true`, then it returns `true`, otherwise it returns `false`.
|
||||
|
||||
In JavaScript the operator is a little bit more tricky and powerful. But first let's see what happens with boolean values.
|
||||
|
||||
|
@ -62,7 +62,7 @@ let hour = 12;
|
|||
let isWeekend = true;
|
||||
|
||||
if (hour < 10 || hour > 18 || isWeekend) {
|
||||
alert( 'The office is closed.' ); // it is weekend
|
||||
alert( 'The office is closed.' ); // it is the weekend
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -78,13 +78,13 @@ Given multiple OR'ed values:
|
|||
result = value1 || value2 || value3;
|
||||
```
|
||||
|
||||
The OR `"||"` operator is doing the following:
|
||||
The OR `"||"` operator does the following:
|
||||
|
||||
- Evalutes operands from left to right.
|
||||
- For each value -- converts it to boolean. If it's true then stops and returns that value.
|
||||
- If operands finished, returns the last value.
|
||||
- Evalute operands from left to right.
|
||||
- For each operand, convert it to boolean. If the result is `true`, then stop and return that the original value of that operand.
|
||||
- If all other operands have been assessed (i.e. all were `falsy`), return the last operand.
|
||||
|
||||
A value is returned in it's original form, without the conversion.
|
||||
A value is returned in its original form, without the conversion.
|
||||
|
||||
In other words, a chain of OR `"||"` returns the first truthy value or the last one if no such value found.
|
||||
|
||||
|
@ -159,7 +159,7 @@ The AND operator is represented with two ampersands `&&`:
|
|||
result = a && b;
|
||||
```
|
||||
|
||||
In classical programming AND returns `true` if both operands are truthy and `false` -- otherwise:
|
||||
In classical programming AND returns `true` if both operands are truthy and `false` otherwise:
|
||||
|
||||
```js run
|
||||
alert( true && true ); // true
|
||||
|
@ -196,13 +196,13 @@ Given multiple AND'ed values:
|
|||
result = value1 && value2 && value3;
|
||||
```
|
||||
|
||||
The AND `"&&"` operator is doing the following:
|
||||
The AND `"&&"` operator does the following:
|
||||
|
||||
- Evalutes operands from left to right.
|
||||
- For each value converts it to a boolean. If the result is `false`, stops and returns the original value.
|
||||
- If values finished (all are truthy), returns the last one.
|
||||
- Evalute operands from left to right.
|
||||
- For each operand, convert it to a boolean. If the result is `false`, stop and return the original value of that operand.
|
||||
- If all other operands have been assessed (i.e. all were truthy), return the last operand.
|
||||
|
||||
In other words, AND returns the first falsy value or the last value if none found.
|
||||
In other words, AND returns the first falsy value or the last value if none were found.
|
||||
|
||||
The rules above are similar to OR. The difference is that AND returns the first *falsy* value while OR returns the first *truthy* one.
|
||||
|
||||
|
@ -210,12 +210,12 @@ Examples:
|
|||
|
||||
```js run
|
||||
// if the first operand is truthy,
|
||||
// AND returns the second one:
|
||||
// AND returns the second operand:
|
||||
alert( 1 && 0 ); // 0
|
||||
alert( 1 && 5 ); // 5
|
||||
|
||||
// if the first operand is falsy,
|
||||
// AND returns it, and the second one is ignored
|
||||
// AND returns it. The second operand is ignored
|
||||
alert( null && 5 ); // null
|
||||
alert( 0 && "no matter what" ); // 0
|
||||
```
|
||||
|
@ -266,7 +266,7 @@ if (x > 0) {
|
|||
|
||||
The variant with `&&` appears to be shorter. But `if` is more obvious and tends to be a little bit more readable.
|
||||
|
||||
So it is recommended to use every construct for it's purpose. Use `if` if we want if. And use `&&` if we want AND.
|
||||
So it is recommended to use every construct for its purpose. Use `if` if we want if. And use `&&` if we want AND.
|
||||
|
||||
## ! (NOT)
|
||||
|
||||
|
@ -297,9 +297,9 @@ alert( !!"non-empty string" ); // true
|
|||
alert( !!null ); // false
|
||||
```
|
||||
|
||||
That is: the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again, at the end we have a plain value-to-boolean conversion.
|
||||
That is, the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again. At the end we have a plain value-to-boolean conversion.
|
||||
|
||||
There's a little more verbose to do the same -- a built-in `Boolean` function:
|
||||
There's a little more verbose way to do the same thing -- a built-in `Boolean` function:
|
||||
|
||||
```js run
|
||||
alert( Boolean("non-empty string") ); // true
|
||||
|
|
|
@ -4,7 +4,7 @@ importance: 5
|
|||
|
||||
# Replace "for" with "while"
|
||||
|
||||
Rewrite the code changing the `for` loop to `while` without altering it's behavior (the output should stay same).
|
||||
Rewrite the code changing the `for` loop to `while` without altering its behavior (the output should stay same).
|
||||
|
||||
```js run
|
||||
for (let i = 0; i < 3; i++) {
|
||||
|
|
|
@ -142,7 +142,7 @@ if (i < 3) { alert(i); i++ }
|
|||
```
|
||||
|
||||
````smart header="Inline variable declaration"
|
||||
Here the "counter" variable `i` is declared right in the loop. That's called an "inline" variable declaration. Such variable is visible only inside the loop.
|
||||
Here the "counter" variable `i` is declared right in the loop. That's called an "inline" variable declaration. Such variables are visible only inside the loop.
|
||||
|
||||
```js run
|
||||
for (*!*let*/!* i = 0; i < 3; i++) {
|
||||
|
@ -202,7 +202,7 @@ for (;;) {
|
|||
}
|
||||
```
|
||||
|
||||
Please note that the two `for` semicolons `;` must present, otherwise it would be a syntax error.
|
||||
Please note that the two `for` semicolons `;` must be present, otherwise it would be a syntax error.
|
||||
|
||||
## Breaking the loop
|
||||
|
||||
|
@ -210,7 +210,7 @@ Normally the loop exits when the condition becomes falsy.
|
|||
|
||||
But we can force the exit at any moment. There's a special `break` directive for that.
|
||||
|
||||
For example, this code below asks user for numbers and breaks if no number entered:
|
||||
For example, the loop below asks the user for a series of numbers, but "breaks" when no number is entered:
|
||||
|
||||
```js
|
||||
let sum = 0;
|
||||
|
@ -353,7 +353,7 @@ In the code above `break outer` looks upwards for the label named `outer` and br
|
|||
|
||||
So the control goes straight from `(*)` to `alert('Done!')`.
|
||||
|
||||
We can also move a label into the separate string:
|
||||
We can also move the label onto a separate line:
|
||||
|
||||
```js no-beautify
|
||||
outer:
|
||||
|
|
|
@ -46,7 +46,17 @@ Nothing is "carved in stone" here. Everything is optional and can be changed: th
|
|||
|
||||
In most JavaScript projects figure brackets are written on the same line, not on the new line. A so-called "egyptian" style. There's also a space before an opening bracket.
|
||||
|
||||
An edge case is a single-line `if/for`. Should we use brackets at all? If yes, then where?
|
||||
Like this:
|
||||
|
||||
```js
|
||||
if (condition) {
|
||||
// do this
|
||||
// ...and that
|
||||
// ...and that
|
||||
}
|
||||
```
|
||||
|
||||
A single-line construct is an important edge case. Should we use brackets at all? If yes, then where?
|
||||
|
||||
Here are the annotated variants, so you can judge about their readability on your own:
|
||||
|
||||
|
@ -82,9 +92,9 @@ There are two types of indents:
|
|||
|
||||
- **A horizontal indent: 2(4) spaces.**
|
||||
|
||||
A horizantal identation is made using either 2 or 4 spaces or the "Tab" symbol. Which one to choose is a kind of an old holy war. Spaces are more common nowadays.
|
||||
A horizantal identation is made using either 2 or 4 spaces or the "Tab" symbol. Which one to choose is an old holy war. Spaces are more common nowadays.
|
||||
|
||||
One of advantages of spaces over tabs is that they allow more flexible configurations of indents than the "Tab" symbol.
|
||||
One of advantages of spaces over tabs is that spaces allow more flexible configurations of indents than the "Tab" symbol.
|
||||
|
||||
For instance, we can align the arguments with the opening bracket, like this:
|
||||
|
||||
|
@ -99,7 +109,7 @@ There are two types of indents:
|
|||
}
|
||||
```
|
||||
|
||||
- **A vertical indent: empty lines for splitting the code in logical blocks.**
|
||||
- **A vertical indent: empty lines for splitting code into logical blocks.**
|
||||
|
||||
Even a single function can often be divided in logical blocks. In the example below, the initialization of variables, the main loop and returning the result are split vertically:
|
||||
|
||||
|
@ -121,9 +131,9 @@ There are two types of indents:
|
|||
|
||||
A semicolon should be present after each statement. Even if it could be possibly be skipped.
|
||||
|
||||
There are languages where a semicolon is truly optional. It's rarely used there.
|
||||
There are languages where a semicolon is truly optional. It's rarely used there. But in JavaScript there are few cases when a line break is sometimes not interpreted as a semicolon. That leaves a place for programming errors.
|
||||
|
||||
But in JavaScript there are few cases when a line break is sometimes not interpreted as a semicolon. That leaves a place for programming errors, so semicolons should be at place.
|
||||
As you become more mature as a programmer, you may choose a no-semicolon style, like [StandardJS](https://standardjs.com/), but that's only when you know JavaScript well and understand possible pitfalls.
|
||||
|
||||
### Nesting levels
|
||||
|
||||
|
@ -240,7 +250,7 @@ If you are writing several "helper" functions and the code to use them, then the
|
|||
...
|
||||
}
|
||||
```
|
||||
3. Mixed, a function is described where it's first used.
|
||||
3. Mixed: a function is described where it's first used.
|
||||
|
||||
Most of time, the second variant is preferred.
|
||||
|
||||
|
@ -259,6 +269,7 @@ For instance:
|
|||
- [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml)
|
||||
- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)
|
||||
- [Idiomatic.JS](https://github.com/rwaldron/idiomatic.js)
|
||||
- [StandardJS](https://standardjs.com/)
|
||||
- (there are more)
|
||||
|
||||
If you're a novice developer, then you could start with the cheatsheet above in the chapter, and later browse the style guides to pick up the common principles and maybe choose one.
|
||||
|
@ -267,7 +278,7 @@ If you're a novice developer, then you could start with the cheatsheet above in
|
|||
|
||||
There are tools that can check the code style automatically. They are called "linters".
|
||||
|
||||
The great thing about them is that style-checking also finds some bugs, like a typo in variable name or a function.
|
||||
The great thing about them is that style-checking also finds some bugs, like a typo in a variable or function name.
|
||||
|
||||
So it's recommended to install one, even if you don't want to stick to a "code style". They help to find typos -- and that's already good enough.
|
||||
|
||||
|
@ -314,7 +325,7 @@ Using a linter has the great side-effect. Linters catch typos. For instance, whe
|
|||
|
||||
For that reason even if you're not concerned about styles, using a linter is highly recommended.
|
||||
|
||||
Also certain IDEs support built-in linting, but not so tunable as ESLint.
|
||||
Also certain IDEs support built-in linting, that also may be good, but not so tunable as ESLint.
|
||||
|
||||
## Summary
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
Arrays by themselves are iterable. But not only arrays. Strings are iterable too, and many other built-in objects as well.
|
||||
|
||||
Iterables are widely used by the core JavaScript, as we'll see many operators and built-in methods rely on them.
|
||||
Iterables are widely used by the core JavaScript. As we'll see many built-in operators and methods rely on them.
|
||||
|
||||
[cut]
|
||||
|
||||
|
@ -23,13 +23,13 @@ let range = {
|
|||
to: 5
|
||||
};
|
||||
|
||||
// We want for..of to work:
|
||||
// We want the for..of to work:
|
||||
// for(let num of range) ... num=1,2,3,4,5
|
||||
```
|
||||
|
||||
To make the `range` iterable (and thus let `for..of` work) we need to add a method to the object named `Symbol.iterator` (a special built-in symbol just for that).
|
||||
|
||||
- When `for..of` starts, it calls that method (or errors if none found).
|
||||
- When `for..of` starts, it calls that method (or errors if not found).
|
||||
- The method must return an *iterator* -- an object with the method `next`.
|
||||
- When `for..of` wants the next value, it calls `next()` on that object.
|
||||
- The result of `next()` must have the form `{done: Boolean, value: any}`, where `done=true` means that the iteration is finished, otherwise `value` must be the new value.
|
||||
|
@ -47,13 +47,13 @@ range[Symbol.iterator] = function() {
|
|||
|
||||
// 2. ...it returns the iterator:
|
||||
return {
|
||||
current: this.from, // start at "range.from",
|
||||
last: this.to, // end at "range.to"
|
||||
current: this.from,
|
||||
last: this.to,
|
||||
|
||||
// 3. next() is called on each iteration by for..of
|
||||
// 3. next() is called on each iteration by the for..of loop
|
||||
next() {
|
||||
// 4. it should return the value as an object {done:.., value :...}
|
||||
if (this.current <= this.last) {
|
||||
// 4. it should return the value as an object {done:.., value :...}
|
||||
return { done: false, value: this.current++ };
|
||||
} else {
|
||||
return { done: true };
|
||||
|
@ -62,6 +62,7 @@ range[Symbol.iterator] = function() {
|
|||
};
|
||||
};
|
||||
|
||||
// now it works!
|
||||
for (let num of range) {
|
||||
alert(num); // 1, then 2, 3, 4, 5
|
||||
}
|
||||
|
@ -72,9 +73,9 @@ There is an important separation of concerns in this code:
|
|||
- The `range` itself does not have the `next()` method.
|
||||
- Instead, another object, a so-called "iterator" is created by the call to `range[Symbol.iterator]()`, and it handles the iteration.
|
||||
|
||||
So, the iterator is separate from the object.
|
||||
So, the iterator object is separate from the object it iterates over.
|
||||
|
||||
Technically, we may merge them and use `range` itself as the iterator, to make the code simpler.
|
||||
Technically, we may merge them and use `range` itself as the iterator to make the code simpler.
|
||||
|
||||
Like this:
|
||||
|
||||
|
@ -102,7 +103,7 @@ for (let num of range) {
|
|||
}
|
||||
```
|
||||
|
||||
Now `range[Symbol.iterator]()` returns the `range` object itself, and it has the necessary `next()` method. Sometimes that's fine too. The downside is that now it's impossible to have two `for..of` loops running over the object simultaneously: they'll share the iteration state, because there's only one iterator -- the object itself.
|
||||
Now `range[Symbol.iterator]()` returns the `range` object itself: it has the necessary `next()` method and remembers the current iteration progress in `this.current`. Sometimes that's fine too. The downside is that now it's impossible to have two `for..of` loops running over the object simultaneously: they'll share the iteration state, because there's only one iterator -- the object itself.
|
||||
|
||||
```smart header="Infinite iterators"
|
||||
Infinite iterators are also doable. For instance, the `range` becomes infinite for `range.to = Infinity`. Or we can make an iterable object that generates an infinite sequence of pseudorandom numbers. Also can be useful.
|
||||
|
@ -138,9 +139,9 @@ for(let char of str) {
|
|||
|
||||
Normally, internals of iterables are hidden from the external code. There's a `for..of` loop, that works, that's all it needs to know.
|
||||
|
||||
But to understand things a little bit more deeper let's see how to create an iterator explicitly. We'll do that the same way as `for..of`, but with direct calls.
|
||||
But to understand things a little bit more deeper let's see how to create an iterator explicitly.
|
||||
|
||||
For instance, this code gets a string iterator and calls it "manually":
|
||||
We'll iterate over a string the same way as `for..of`, but with direct calls. This code gets a string iterator and calls it "manually":
|
||||
|
||||
```js run
|
||||
let str = "Hello";
|
||||
|
@ -157,18 +158,18 @@ while(true) {
|
|||
}
|
||||
```
|
||||
|
||||
That is rarely needed, but gives us more control than `for..of`. For instance, we can split the iteration process: iterate a bit, then stop, do something else, and then resume later.
|
||||
That is rarely needed, but gives us more control over the process than `for..of`. For instance, we can split the iteration process: iterate a bit, then stop, do something else, and then resume later.
|
||||
|
||||
## Iterables and array-likes [#array-like]
|
||||
|
||||
There are two official terms that look similar, but are very different. Please be careful to avoid the confusion.
|
||||
There are two official terms that look similar, but are very different. Please make sure you understand them well to avoid the confusion.
|
||||
|
||||
- *Iterables* are objects that implement the `Symbol.iterator` method, as described above.
|
||||
- *Array-likes* are objects that have indexes and `length`, so they look like arrays.
|
||||
|
||||
Naturally, they can combine. For instance, strings are both iterable and array-like.
|
||||
Naturally, these properties can combine. For instance, strings are both iterable (`for..of` works on them) and array-like (they have numeric indexes and `length`).
|
||||
|
||||
But an iterable may be not array-like and vice versa.
|
||||
But an iterable may be not array-like. And vice versa an array-like may be not iterable.
|
||||
|
||||
For example, the `range` in the example above is iterable, but not array-like, because it does not have indexed properties and `length`.
|
||||
|
||||
|
@ -236,7 +237,7 @@ let arr = Array.from(range, num => num * num);
|
|||
alert(arr); // 1,4,9,16,25
|
||||
```
|
||||
|
||||
We can also use `Array.from` to turn a string into an array of characters:
|
||||
Here we use `Array.from` to turn a string into an array of characters:
|
||||
|
||||
```js run
|
||||
let str = '𝒳😂';
|
||||
|
|
|
@ -53,7 +53,7 @@ Unwanted elements of the array can also be thrown away via an extra comma:
|
|||
let [, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
|
||||
*/!*
|
||||
|
||||
alert( title ); // Imperator
|
||||
alert( title ); // Consul
|
||||
```
|
||||
|
||||
In the code above, the first and second elements of the array are skipped, the third one is assigned to `title`, and the rest is also skipped.
|
||||
|
|
|
@ -334,9 +334,9 @@ Here's what's going on in the `makeCounter` example step-by-step, follow it to m
|
|||
|
||||
3. During the execution of `makeCounter()`, a tiny nested function is created.
|
||||
|
||||
It doesn't matter whether the function is created using Function Declaration or Function Expression. All functions get the `[[Environment]]` property that references the Lexical Environment where they were made.
|
||||
It doesn't matter whether the function is created using Function Declaration or Function Expression. All functions get the `[[Environment]]` property that references the Lexical Environment where they were made. So that new tiny nested function gets it as well.
|
||||
|
||||
For our new nested function that is the current Lexical Environment of `makeCounter()`:
|
||||
For our new nested function the value of `[[Environment]]` is the current Lexical Environment of `makeCounter()` (where it was born):
|
||||
|
||||

|
||||
|
||||
|
|
|
@ -319,7 +319,7 @@ class Article {
|
|||
|
||||
let article = Article.createTodays();
|
||||
|
||||
alert( articles.title ); // Todays digest
|
||||
alert( article.title ); // Todays digest
|
||||
```
|
||||
|
||||
Now every time we need to create a todays digest, we can call `Article.createTodays()`. Once again, that's not a method of an article, but a method of the whole class.
|
||||
|
|
|
@ -102,8 +102,8 @@ table.onclick = function(event) {
|
|||
Explanations:
|
||||
1. The method `elem.closest(selector)` returns the nearest ancestor that matches the selector. In our case we look for `<td>` on the way up from the source element.
|
||||
2. If `event.target` is not inside any `<td>`, then the call returns `null`, and we don't have to do anything.
|
||||
3. In case of nested tables, `event.target` may be a `<td>` outside of the current table. So we check if that's actually *our* `<td>`.
|
||||
4. And, if it is so, highlight it.
|
||||
3. In case of nested tables, `event.target` may be a `<td>` lying outside of the current table. So we check if that's actually *our table's* `<td>`.
|
||||
4. And, if it's so, then highlight it.
|
||||
|
||||
## Delegation example: actions in markup
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@
|
|||
|
||||
This text is always visible.
|
||||
|
||||
But if the page is shown inside a document from another domain, the div over it prevents any actions.
|
||||
But if the page was open inside a document from another domain, the div over it would prevent any actions.
|
||||
|
||||
<button onclick="alert(1)">Click doesn't work in that case</button>
|
||||
<button onclick="alert(1)">Click wouldn't work in that case</button>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -97,7 +97,7 @@ In other words, all special characters are allowed except where they mean someth
|
|||
|
||||
A dot `"."` inside square brackets means just a dot. The pattern `pattern:[.,]` would look for one of characters: either a dot or a comma.
|
||||
|
||||
In the example below the regexp `pattern:[-().^+]` looks for one of the characters `-().^`:
|
||||
In the example below the regexp `pattern:[-().^+]` looks for one of the characters `-().^+`:
|
||||
|
||||
```js run
|
||||
// No need to escape
|
||||
|
|
|
@ -29,7 +29,8 @@ The call initiates the script loading, then the execution continues. While the s
|
|||
|
||||
```js
|
||||
loadScript('/my/script.js');
|
||||
// the code below doesn't wait for the script loading to finish
|
||||
// the code below loadScript doesn't wait for the script loading to finish
|
||||
// ...
|
||||
```
|
||||
|
||||
Now let's say we want to use the new script when it loads. It probably declares new functions, so we'd like to run them.
|
||||
|
@ -44,7 +45,7 @@ newFunction(); // no such function!
|
|||
*/!*
|
||||
```
|
||||
|
||||
Naturally, the browser probably didn't have time to load the script. As of now, `loadScript` function doesn't provide a way to track the load completion. The script loads and eventually runs, that's all. But we'd like to know when happens, to use new functions and variables from that script.
|
||||
Naturally, the browser probably didn't have time to load the script. So the immediate call to the new function fails. As of now, `loadScript` function doesn't provide a way to track the load completion. The script loads and eventually runs, that's all. But we'd like to know when happens, to use new functions and variables from that script.
|
||||
|
||||
Let's add a `callback` function as a second argument to `loadScript` that should execute when the script loads:
|
||||
|
||||
|
@ -150,7 +151,7 @@ function loadScript(src, callback) {
|
|||
|
||||
*!*
|
||||
script.onload = () => callback(null, script);
|
||||
script.onerror = () => callback(new Error(`Script load error ` + src));
|
||||
script.onerror = () => callback(new Error(`Script load error for ${src}`));
|
||||
*/!*
|
||||
|
||||
document.head.append(script);
|
||||
|
|
|
@ -96,7 +96,7 @@ let promise = new Promise(function(resolve, reject) {
|
|||
|
||||
The idea is that a job done by the executor may have only one result or an error. In programming, there exist other data structures that allow many "flowing" results, for instance streams and queues. They have their own advantages and disadvantages versus promises. They are not supported by JavaScript core and lack certain language features that promises provide, we don't cover them here to concentrate on promises.
|
||||
|
||||
Also we if we call `resolve/reject` with more then one argument -- only the first argument is used, the next ones are ignored.
|
||||
Also if we call `resolve/reject` with more then one argument -- only the first argument is used, the next ones are ignored.
|
||||
````
|
||||
|
||||
```smart header="Reject with `Error` objects"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue