true / false
| `1 / 0` |
| `string` | The string is read "as is", whitespaces from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. |
-**`ToBoolean`** -- Occurs in logical operations. Can be performed with `Boolean(value)`.
+**`To Boolean`** -- Occurs in logical operations. Can be performed with `Boolean(value)`.
Follows the rules:
diff --git a/1-js/02-first-steps/07-operators/article.md b/1-js/02-first-steps/07-operators/article.md
index b3fbfd9bb..a1373eade 100644
--- a/1-js/02-first-steps/07-operators/article.md
+++ b/1-js/02-first-steps/07-operators/article.md
@@ -26,7 +26,7 @@ Before we move on, let's grasp some common terminology.
alert( y - x ); // 2, binary minus subtracts values
```
- Formally, we're talking about two different operators here: the unary negation (single operand: reverses the sign) and the binary subtraction (two operands: subtracts).
+ Formally, in the examples above we have two different operators that share the same symbol: the negation operator, a unary operator that reverses the sign, and the subtraction operator, a binary operator that subtracts one number from another.
## String concatenation, binary +
@@ -93,9 +93,7 @@ alert( +"" ); // 0
It actually does the same thing as `Number(...)`, but is shorter.
-The need to convert strings to numbers arises very often. For example, if we are getting values from HTML form fields, they are usually strings.
-
-What if we want to sum them?
+The need to convert strings to numbers arises very often. For example, if we are getting values from HTML form fields, they are usually strings. What if we want to sum them?
The binary plus would add them as strings:
@@ -253,14 +251,14 @@ So, there are special operators for it:
```js run no-beautify
let counter = 2;
- counter++; // works the same as counter = counter + 1, but is shorter
+ counter++; // works the same as counter = counter + 1, but is shorter
alert( counter ); // 3
```
- **Decrement** `--` decreases a variable by 1:
```js run no-beautify
let counter = 2;
- counter--; // works the same as counter = counter - 1, but is shorter
+ counter--; // works the same as counter = counter - 1, but is shorter
alert( counter ); // 1
```
diff --git a/1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md b/1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md
index 5c8bd2bc4..6437b512e 100644
--- a/1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md
+++ b/1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md
@@ -3,11 +3,11 @@
```js no-beautify
5 > 4 → true
"apple" > "pineapple" → false
-"2" > "12" → true
-undefined == null → true
-undefined === null → false
+"2" > "12" → true
+undefined == null → true
+undefined === null → false
null == "\n0\n" → false
-null === +"\n0\n" → false
+null === +"\n0\n" → false
```
Some of the reasons:
@@ -17,5 +17,5 @@ Some of the reasons:
3. Again, dictionary comparison, first char of `"2"` is greater than the first char of `"1"`.
4. Values `null` and `undefined` equal each other only.
5. Strict equality is strict. Different types from both sides lead to false.
-6. See (4).
+6. Similar to `(4)`, `null` only equals `undefined`.
7. Strict equality of different types.
diff --git a/1-js/02-first-steps/08-comparison/article.md b/1-js/02-first-steps/08-comparison/article.md
index 8697076a4..d889b1328 100644
--- a/1-js/02-first-steps/08-comparison/article.md
+++ b/1-js/02-first-steps/08-comparison/article.md
@@ -74,7 +74,7 @@ alert( '2' > 1 ); // true, string '2' becomes a number 2
alert( '01' == 1 ); // true, string '01' becomes a number 1
```
-For boolean values, `true` becomes `1` and `false` becomes `0`.
+For boolean values, `true` becomes `1` and `false` becomes `0`.
For example:
@@ -138,11 +138,8 @@ The strict equality operator is a bit longer to write, but makes it obvious what
## Comparison with null and undefined
-Let's see more edge cases.
-
There's a non-intuitive behavior when `null` or `undefined` are compared to other values.
-
For a strict equality check `===`
: These values are different, because each of them is a different type.
diff --git a/1-js/02-first-steps/09-alert-prompt-confirm/article.md b/1-js/02-first-steps/09-alert-prompt-confirm/article.md
index c14e0c85a..8ba414e9c 100644
--- a/1-js/02-first-steps/09-alert-prompt-confirm/article.md
+++ b/1-js/02-first-steps/09-alert-prompt-confirm/article.md
@@ -30,7 +30,7 @@ The function `prompt` accepts two arguments:
result = prompt(title, [default]);
```
-It shows a modal window with a text message, an input field for the visitor, and the buttons OK/CANCEL.
+It shows a modal window with a text message, an input field for the visitor, and the buttons OK/Cancel.
`title`
: The text to show the visitor.
@@ -38,7 +38,7 @@ It shows a modal window with a text message, an input field for the visitor, and
`default`
: An optional second parameter, the initial value for the input field.
-The visitor may type something in the prompt input field and press OK. Or they can cancel the input by pressing CANCEL or hitting the `key:Esc` key.
+The visitor may type something in the prompt input field and press OK. Or they can cancel the input by pressing Cancel or hitting the `key:Esc` key.
The call to `prompt` returns the text from the input field or `null` if the input was canceled.
@@ -74,7 +74,7 @@ The syntax:
result = confirm(question);
```
-The function `confirm` shows a modal window with a `question` and two buttons: OK and CANCEL.
+The function `confirm` shows a modal window with a `question` and two buttons: OK and Cancel.
The result is `true` if OK is pressed and `false` otherwise.
@@ -94,10 +94,10 @@ We covered 3 browser-specific functions to interact with visitors:
: shows a message.
`prompt`
-: shows a message asking the user to input text. It returns the text or, if CANCEL or `key:Esc` is clicked, `null`.
+: shows a message asking the user to input text. It returns the text or, if Cancel button or `key:Esc` is clicked, `null`.
`confirm`
-: shows a message and waits for the user to press "OK" or "CANCEL". It returns `true` for OK and `false` for CANCEL/`key:Esc`.
+: shows a message and waits for 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 script execution and don't allow the visitor to interact with the rest of the page until the window has been dismissed.
diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.png b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.png
deleted file mode 100644
index 04fb1fb0b..000000000
Binary files a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.png and /dev/null differ
diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.svg b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.svg
new file mode 100644
index 000000000..ea4d122f6
--- /dev/null
+++ b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png
deleted file mode 100644
index 08226b790..000000000
Binary files a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png and /dev/null differ
diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/task.md b/1-js/02-first-steps/10-ifelse/2-check-standard/task.md
index 46fe05dc9..a4d943245 100644
--- a/1-js/02-first-steps/10-ifelse/2-check-standard/task.md
+++ b/1-js/02-first-steps/10-ifelse/2-check-standard/task.md
@@ -8,7 +8,6 @@ Using the `if..else` construct, write the code which asks: 'What is the "officia
If the visitor enters "ECMAScript", then output "Right!", otherwise -- output: "Didn't know? ECMAScript!"
-![](ifelse_task2.png)
+![](ifelse_task2.svg)
[demo src="ifelse_task2"]
-
diff --git a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md
index 638ce81f1..ff32354fa 100644
--- a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md
+++ b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md
@@ -1,6 +1,6 @@
```js
-result = (a + b < 4) ? 'Below' : 'Over';
+let result = (a + b < 4) ? 'Below' : 'Over';
```
diff --git a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md
index 684e239f2..6bdf8453e 100644
--- a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md
+++ b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md
@@ -4,13 +4,14 @@ importance: 5
# Rewrite 'if' into '?'
-Rewrite this `if` using the ternary operator `'?'`:
+Rewrite this `if` using the conditional operator `'?'`:
```js
+let result;
+
if (a + b < 4) {
result = 'Below';
} else {
result = 'Over';
}
```
-
diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md
index 49c1fc041..30287ccba 100644
--- a/1-js/02-first-steps/10-ifelse/article.md
+++ b/1-js/02-first-steps/10-ifelse/article.md
@@ -6,7 +6,7 @@ To do that, we can use the `if` statement and the conditional operator `?`, that
## The "if" statement
-The `if` statement evaluates a condition and, if the condition's result is `true`, executes a block of code.
+The `if(...)` statement evaluates a condition in parentheses and, if the result is `true`, executes a block of code.
For example:
@@ -216,7 +216,7 @@ Depending on the condition `company == 'Netscape'`, either the first or the seco
We don't assign a result to a variable here. Instead, we execute different code depending on the condition.
-**We don't recommend using the question mark operator in this way.**
+**It's not recommended to use the question mark operator in this way.**
The notation is shorter than the equivalent `if` statement, which appeals to some programmers. But it is less readable.
diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.png b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.png
deleted file mode 100644
index 32f0d4b94..000000000
Binary files a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.png and /dev/null differ
diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.svg b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.svg
new file mode 100644
index 000000000..010a53a4a
--- /dev/null
+++ b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task@2x.png b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task@2x.png
deleted file mode 100644
index c3867e62c..000000000
Binary files a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task@2x.png and /dev/null differ
diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md b/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md
index b535650ec..a30db7aae 100644
--- a/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md
@@ -10,7 +10,7 @@ if (userName == 'Admin') {
if (pass == 'TheMaster') {
alert( 'Welcome!' );
} else if (pass == '' || pass == null) {
- alert( 'Canceled.' );
+ alert( 'Canceled' );
} else {
alert( 'Wrong password' );
}
diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/task.md b/1-js/02-first-steps/11-logical-operators/9-check-login/task.md
index 780e674a9..290a52642 100644
--- a/1-js/02-first-steps/11-logical-operators/9-check-login/task.md
+++ b/1-js/02-first-steps/11-logical-operators/9-check-login/task.md
@@ -6,17 +6,17 @@ importance: 3
Write the code which asks for a login with `prompt`.
-If the visitor enters `"Admin"`, then `prompt` for a password, if the input is an empty line or `key:Esc` -- show "Canceled.", if it's another string -- then show "I don't know you".
+If the visitor enters `"Admin"`, then `prompt` for a password, if the input is an empty line or `key:Esc` -- show "Canceled", if it's another string -- then show "I don't know you".
The password is checked as follows:
- If it equals "TheMaster", then show "Welcome!",
- Another string -- show "Wrong password",
-- For an empty string or cancelled input, show "Canceled."
+- For an empty string or cancelled input, show "Canceled"
The schema:
-![](ifelse_task.png)
+![](ifelse_task.svg)
Please use nested `if` blocks. Mind the overall readability of the code.
diff --git a/1-js/02-first-steps/11-logical-operators/article.md b/1-js/02-first-steps/11-logical-operators/article.md
index 0773a10cb..25f8ff7f5 100644
--- a/1-js/02-first-steps/11-logical-operators/article.md
+++ b/1-js/02-first-steps/11-logical-operators/article.md
@@ -64,7 +64,7 @@ if (hour < 10 || hour > 18 || isWeekend) {
}
```
-## OR finds the first truthy value
+## OR "||" finds the first truthy value
The logic described above is somewhat classical. Now, let's bring in the "extra" features of JavaScript.
@@ -186,7 +186,7 @@ if (1 && 0) { // evaluated as true && false
```
-## AND finds the first falsy value
+## AND "&&" finds the first falsy value
Given multiple AND'ed values:
diff --git a/1-js/02-first-steps/12-while-for/article.md b/1-js/02-first-steps/12-while-for/article.md
index c809581f5..580ac3e14 100644
--- a/1-js/02-first-steps/12-while-for/article.md
+++ b/1-js/02-first-steps/12-while-for/article.md
@@ -17,7 +17,7 @@ while (condition) {
}
```
-While the `condition` is `true`, the `code` from the loop body is executed.
+While the `condition` is truthy, the `code` from the loop body is executed.
For instance, the loop below outputs `i` while `i < 3`:
@@ -84,7 +84,7 @@ This form of syntax should only be used when you want the body of the loop to ex
## The "for" loop
-The `for` loop is the most commonly used loop.
+The `for` loop is more complex, but it's also the most commonly used loop.
It looks like this:
@@ -108,11 +108,11 @@ Let's examine the `for` statement part-by-part:
|-------|----------|----------------------------------------------------------------------------|
| begin | `i = 0` | Executes once upon entering the loop. |
| condition | `i < 3`| Checked before every loop iteration. If false, the loop stops. |
-| step| `i++` | Executes after the body on each iteration but before the condition check. |
| body | `alert(i)`| Runs again and again while the condition is truthy. |
-
+| step| `i++` | Executes after the body on each iteration. |
The general loop algorithm works like this:
+
```
Run begin
→ (if condition → run body and run step)
@@ -121,6 +121,8 @@ Run begin
→ ...
```
+That is, `begin` executes once, and then it iterates: after each `condition` test, `body` and `step` are executed.
+
If you are new to loops, it could help to go back to the example and reproduce how it runs step-by-step on a piece of paper.
Here's exactly what happens in our case:
@@ -289,8 +291,7 @@ if (i > 5) {
(i > 5) ? alert(i) : *!*continue*/!*; // continue isn't allowed here
```
-...it stops working. Code like this will give a syntax error:
-
+...it stops working: there's a syntax error.
This is just another reason not to use the question mark operator `?` instead of `if`.
````
@@ -299,7 +300,7 @@ This is just another reason not to use the question mark operator `?` instead of
Sometimes we need to break out from multiple nested loops at once.
-For example, in the code below we loop over `i` and `j`, prompting for the coordinates `(i, j)` from `(0,0)` to `(3,3)`:
+For example, in the code below we loop over `i` and `j`, prompting for the coordinates `(i, j)` from `(0,0)` to `(2,2)`:
```js run no-beautify
for (let i = 0; i < 3; i++) {
@@ -308,8 +309,7 @@ for (let i = 0; i < 3; i++) {
let input = prompt(`Value at coords (${i},${j})`, '');
- // what if I want to exit from here to Done (below)?
-
+ // what if we want to exit from here to Done (below)?
}
}
@@ -358,12 +358,12 @@ for (let i = 0; i < 3; i++) { ... }
The `continue` directive can also be used with a label. In this case, code execution jumps to the next iteration of the labeled loop.
-````warn header="Labels are not a \"goto\""
+````warn header="Labels do not allow to \"jump\" anywhere"
Labels do not allow us to jump into an arbitrary place in the code.
For example, it is impossible to do this:
```js
-break label; // jumps to label? No.
+break label; // doesn't jumps to the label below
label: for (...)
```
diff --git a/1-js/02-first-steps/13-switch/article.md b/1-js/02-first-steps/13-switch/article.md
index 258f24068..dec40a537 100644
--- a/1-js/02-first-steps/13-switch/article.md
+++ b/1-js/02-first-steps/13-switch/article.md
@@ -125,7 +125,7 @@ switch (a) {
break;
*!*
- case 3: // (*) grouped two cases
+ case 3: // (*) grouped two cases
case 5:
alert('Wrong!');
alert("Why don't you take a math class?");
diff --git a/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md b/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md
index 523bb127a..46da079c0 100644
--- a/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md
+++ b/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md
@@ -13,7 +13,7 @@ function checkAge(age) {
if (age > 18) {
return true;
} else {
- return confirm('Do you have your parents permission to access this page?');
+ return confirm('Did parents allow you?');
}
}
```
diff --git a/1-js/02-first-steps/14-function-basics/4-pow/solution.md b/1-js/02-first-steps/14-function-basics/4-pow/solution.md
index 5ef20c386..19fe9011f 100644
--- a/1-js/02-first-steps/14-function-basics/4-pow/solution.md
+++ b/1-js/02-first-steps/14-function-basics/4-pow/solution.md
@@ -14,10 +14,8 @@ let x = prompt("x?", '');
let n = prompt("n?", '');
if (n < 1) {
- alert(`Power ${n} is not supported,
- use an integer greater than 0`);
+ alert(`Power ${n} is not supported, use a positive integer`);
} else {
alert( pow(x, n) );
}
```
-
diff --git a/1-js/02-first-steps/14-function-basics/article.md b/1-js/02-first-steps/14-function-basics/article.md
index ec34b744d..b1881e311 100644
--- a/1-js/02-first-steps/14-function-basics/article.md
+++ b/1-js/02-first-steps/14-function-basics/article.md
@@ -20,9 +20,13 @@ function showMessage() {
}
```
-The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (empty in the example above) and finally the code of the function, also named "the function body", between curly braces.
+The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above) and finally the code of the function, also named "the function body", between curly braces.
-![](function_basics.png)
+```js
+function name(parameters) {
+ ...body...
+}
+```
Our new function can be called by its name: `showMessage()`.
@@ -205,12 +209,11 @@ function showMessage(from, text = anotherFunction()) {
```
```smart header="Evaluation of default parameters"
+In JavaScript, a default parameter is evaluated every time the function is called without the respective parameter.
-In JavaScript, a default parameter is evaluated every time the function is called without the respective parameter. In the example above, `anotherFunction()` is called every time `showMessage()` is called without the `text` parameter. This is in contrast to some other languages like Python, where any default parameters are evaluated only once during the initial interpretation.
-
+In the example above, `anotherFunction()` is called every time `showMessage()` is called without the `text` parameter.
```
-
````smart header="Default parameters old-style"
Old editions of JavaScript did not support default parameters. So there are alternative ways to support them, that you can find mostly in the old scripts.
@@ -335,7 +338,19 @@ That doesn't work, because JavaScript assumes a semicolon after `return`. That'l
return*!*;*/!*
(some + long + expression + or + whatever * f(a) + f(b))
```
-So, it effectively becomes an empty return. We should put the value on the same line instead.
+
+So, it effectively becomes an empty return.
+
+If we want the returned expression to wrap across multiple lines, we should start it at the same line as `return`. Or at least put the opening parentheses there as follows:
+
+```js
+return (
+ some + long + expression
+ + or +
+ whatever * f(a) + f(b)
+ )
+```
+And it will work just as we expect it to.
````
## Naming a function [#function-naming]
diff --git a/1-js/02-first-steps/14-function-basics/function_basics.png b/1-js/02-first-steps/14-function-basics/function_basics.png
deleted file mode 100644
index f5e6f9418..000000000
Binary files a/1-js/02-first-steps/14-function-basics/function_basics.png and /dev/null differ
diff --git a/1-js/02-first-steps/14-function-basics/function_basics@2x.png b/1-js/02-first-steps/14-function-basics/function_basics@2x.png
deleted file mode 100644
index c31b2636a..000000000
Binary files a/1-js/02-first-steps/14-function-basics/function_basics@2x.png and /dev/null differ
diff --git a/1-js/02-first-steps/15-function-expressions-arrows/article.md b/1-js/02-first-steps/15-function-expressions-arrows/article.md
index 9b63907d5..d7f0f99ca 100644
--- a/1-js/02-first-steps/15-function-expressions-arrows/article.md
+++ b/1-js/02-first-steps/15-function-expressions-arrows/article.md
@@ -22,7 +22,6 @@ let sayHi = function() {
Here, the function is created and assigned to the variable explicitly, like any other value. No matter how the function is defined, it's just a value stored in the variable `sayHi`.
-
The meaning of these code samples is the same: "create a function and put it into the variable `sayHi`".
We can even print out that value using `alert`:
@@ -41,7 +40,7 @@ Please note that the last line does not run the function, because there are no p
In JavaScript, a function is a value, so we can deal with it as a value. The code above shows its string representation, which is the source code.
-It is a special value of course, in the sense that we can call it like `sayHi()`.
+Surely, a function is a special values, in the sense that we can call it like `sayHi()`.
But it's still a value. So we can work with it like with other kinds of values.
@@ -61,21 +60,21 @@ sayHi(); // Hello // this still works too (why wouldn't it)
Here's what happens above in detail:
1. The Function Declaration `(1)` creates the function and puts it into the variable named `sayHi`.
-2. Line `(2)` copies it into the variable `func`.
-
- Please note again: there are no parentheses after `sayHi`. If there were, then `func = sayHi()` would write *the result of the call* `sayHi()` into `func`, not *the function* `sayHi` itself.
+2. Line `(2)` copies it into the variable `func`. Please note again: there are no parentheses after `sayHi`. If there were, then `func = sayHi()` would write *the result of the call* `sayHi()` into `func`, not *the function* `sayHi` itself.
3. Now the function can be called as both `sayHi()` and `func()`.
Note that we could also have used a Function Expression to declare `sayHi`, in the first line:
```js
-let sayHi = function() { ... };
+let sayHi = function() {
+ alert( "Hello" );
+};
let func = sayHi;
// ...
```
-Everything would work the same. Even more obvious what's going on, right?
+Everything would work the same.
````smart header="Why is there a semicolon at the end?"
@@ -93,7 +92,7 @@ let sayHi = function() {
The answer is simple:
- There's no need for `;` at the end of code blocks and syntax structures that use them like `if { ... }`, `for { }`, `function f { }` etc.
-- A Function Expression is used inside the statement: `let sayHi = ...;`, as a value. It's not a code block. The semicolon `;` is recommended at the end of statements, no matter what is the value. So the semicolon here is not related to the Function Expression itself in any way, it just terminates the statement.
+- A Function Expression is used inside the statement: `let sayHi = ...;`, as a value. It's not a code block, but rather an assignment. The semicolon `;` is recommended at the end of statements, no matter what the value is. So the semicolon here is not related to the Function Expression itself, it just terminates the statement.
````
## Callback functions
@@ -133,11 +132,11 @@ function showCancel() {
ask("Do you agree?", showOk, showCancel);
```
-Before we explore how we can write it in a much shorter way, let's note that in the browser (and on the server-side in some cases) such functions are quite popular. The major difference between a real-life implementation and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such a function usually draws a nice-looking question window. But that's another story.
+In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such function usually draws a nice-looking question window. But that's another story.
-**The arguments of `ask` are called *callback functions* or just *callbacks*.**
+**The arguments `showOk` and `showCancel` of `ask` are called *callback functions* or just *callbacks*.**
-The idea is that we pass a function and expect it to be "called back" later if necessary. In our case, `showOk` becomes the callback for the "yes" answer, and `showCancel` for the "no" answer.
+The idea is that we pass a function and expect it to be "called back" later if necessary. In our case, `showOk` becomes the callback for "yes" answer, and `showCancel` for "no" answer.
We can use Function Expressions to write the same function much shorter:
@@ -156,12 +155,10 @@ ask(
*/!*
```
-
Here, functions are declared right inside the `ask(...)` call. They have no name, and so are called *anonymous*. Such functions are not accessible outside of `ask` (because they are not assigned to variables), but that's just what we want here.
Such code appears in our scripts very naturally, it's in the spirit of JavaScript.
-
```smart header="A function is a value representing an \"action\""
Regular values like strings or numbers represent the *data*.
@@ -196,19 +193,19 @@ First, the syntax: how to differentiate between them in the code.
The more subtle difference is *when* a function is created by the JavaScript engine.
-**A Function Expression is created when the execution reaches it and is usable from then on.**
+**A Function Expression is created when the execution reaches it and is usable only from that moment.**
Once the execution flow passes to the right side of the assignment `let sum = function…` -- here we go, the function is created and can be used (assigned, called, etc. ) from now on.
Function Declarations are different.
-**A Function Declaration is usable in the whole script (or a code block, if it's inside a block).**
+**A Function Declaration can be called earlier than it is defined.**
-In other words, when JavaScript *prepares* to run the script or a code block, it first looks for Function Declarations in it and creates the functions. We can think of it as an "initialization stage".
+For example, a global Function Declaration is visible in the whole script, no matter where it is.
-And after all of the Function Declarations are processed, the execution goes on.
+That's due to internal algorithms. When JavaScript prepares to run the script, it first looks for global Function Declarations in it and creates the functions. We can think of it as an "initialization stage".
-As a result, a function declared as a Function Declaration can be called earlier than it is defined.
+And after all Function Declarations are processed, the code is executed. So it has access to these functions.
For example, this works:
@@ -224,7 +221,7 @@ function sayHi(name) {
The Function Declaration `sayHi` is created when JavaScript is preparing to start the script and is visible everywhere in it.
-...If it was a Function Expression, then it wouldn't work:
+...If it were a Function Expression, then it wouldn't work:
```js run refresh untrusted
*!*
@@ -238,13 +235,13 @@ let sayHi = function(name) { // (*) no magic any more
Function Expressions are created when the execution reaches them. That would happen only in the line `(*)`. Too late.
-**When a Function Declaration is made within a code block, it is visible everywhere inside that block. But not outside of it.**
+Another special feature of Function Declarations is their block scope.
-Sometimes that's handy to declare a local function only needed in that block alone. But that feature may also cause problems.
+**In strict mode, when a Function Declaration is within a code block, it's visible everywhere inside that block. But not outside of it.**
For instance, let's imagine that we need to declare a function `welcome()` depending on the `age` variable that we get during runtime. And then we plan to use it some time later.
-The code below doesn't work:
+If we use Function Declaration, it won't work as intended:
```js run
let age = prompt("What is your age?", 18);
@@ -292,7 +289,7 @@ if (age < 18) {
} else {
- function welcome() { // for age = 16, this "welcome" is never created
+ function welcome() {
alert("Greetings!");
}
}
@@ -309,7 +306,7 @@ What can we do to make `welcome` visible outside of `if`?
The correct approach would be to use a Function Expression and assign `welcome` to the variable that is declared outside of `if` and has the proper visibility.
-Now it works as intended:
+This code works as intended:
```js run
let age = prompt("What is your age?", 18);
@@ -350,12 +347,12 @@ welcome(); // ok now
```
-```smart header="When should you choose Function Declaration versus Function Expression?"
-As a rule of thumb, when we need to declare a function, the first to consider is Function Declaration syntax, the one we used before. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
+```smart header="When to choose Function Declaration versus Function Expression?"
+As a rule of thumb, when we need to declare a function, the first to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
-It's also a little bit easier to look up `function f(…) {…}` in the code than `let f = function(…) {…}`. Function Declarations are more "eye-catching".
+That's also better for readability, as it's easier to look up `function f(…) {…}` in the code than `let f = function(…) {…}`. Function Declarations are more "eye-catching".
-...But if a Function Declaration does not suit us for some reason (we've seen an example above), then Function Expression should be used.
+...But if a Function Declaration does not suit us for some reason, or we need a conditional declaration (we've just seen an example), then Function Expression should be used.
```
@@ -396,7 +393,7 @@ alert( sum(1, 2) ); // 3
```
-If we have only one argument, then parentheses can be omitted, making that even shorter:
+If we have only one argument, then parentheses around parameters can be omitted, making that even shorter:
```js run
// same as
@@ -456,7 +453,7 @@ alert( sum(1, 2) ); // 3
```smart header="More to come"
Here we praised arrow functions for brevity. But that's not all! Arrow functions have other interesting features. We'll return to them later in the chapter func`string`
. The function `func` is called automatically, receives the string and embedded expressions and can process them. You can read more about it in the [docs](mdn:/JavaScript/Reference/Template_literals#Tagged_template_literals). This is called "tagged templates". This feature makes it easier to wrap strings into custom templating or other functionality, but it is rarely used.
-
## Special characters
-It is still possible to create multiline strings with single quotes by using a so-called "newline character", written as `\n`, which denotes a line break:
+It is still possible to create multiline strings with single and double quotes by using a so-called "newline character", written as `\n`, which denotes a line break:
```js run
let guestList = "Guests:\n * John\n * Pete\n * Mary";
@@ -60,39 +62,45 @@ let guestList = "Guests:\n * John\n * Pete\n * Mary";
alert(guestList); // a multiline list of guests
```
-For example, these two lines describe the same:
+For example, these two lines are equal, just written differently:
```js run
-alert( "Hello\nWorld" ); // two lines using a "newline symbol"
+let str1 = "Hello\nWorld"; // two lines using a "newline symbol"
// two lines using a normal newline and backticks
-alert( `Hello
-World` );
+let str2 = `Hello
+World`;
+
+alert(str1 == str2); // true
```
-There are other, less common "special" characters as well. Here's the list:
+There are other, less common "special" characters.
+
+Here's the full list:
| Character | Description |
|-----------|-------------|
-|`\b`|Backspace|
-|`\f`|Form feed|
|`\n`|New line|
-|`\r`|Carriage return|
+|`\r`|Carriage return: not used alone. Windows text files use a combination of two characters `\r\n` to represent a line break. |
+|`\'`, `\"`|Quotes|
+|`\\`|Backslash|
|`\t`|Tab|
-|`\uNNNN`|A unicode symbol with the hex code `NNNN`, for instance `\u00A9` -- is a unicode for the copyright symbol `©`. It must be exactly 4 hex digits. |
-|`\u{NNNNNNNN}`|Some rare characters are encoded with two unicode symbols, taking up to 4 bytes. This long unicode requires braces around it.|
+|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- kept for compatibility, not used nowadays. |
+|`\xXX`|Unicode character with the given hexadecimal unicode `XX`, e.g. `'\x7A'` is the same as `'z'`.|
+|`\uXXXX`|A unicode symbol with the hex code `XXXX` in UTF-16 encoding, for instance `\u00A9` -- is a unicode for the copyright symbol `©`. It must be exactly 4 hex digits. |
+|`\u{X…XXXXXX}` (1 to 6 hex characters)|A unicode symbol with the given UTF-32 encoding. Some rare characters are encoded with two unicode symbols, taking 4 bytes. This way we can insert long codes. |
Examples with unicode:
```js run
alert( "\u00A9" ); // ©
-alert( "\u{20331}" ); // 佫, a rare chinese hieroglyph (long unicode)
+alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long unicode)
alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long unicode)
```
All special characters start with a backslash character `\`. It is also called an "escape character".
-We would also use it if we want to insert a quote into the string.
+We might also use it if we wanted to insert a quote into the string.
For instance:
@@ -102,7 +110,7 @@ alert( 'I*!*\'*/!*m the Walrus!' ); // *!*I'm*/!* the Walrus!
As you can see, we have to prepend the inner quote by the backslash `\'`, because otherwise it would indicate the string end.
-Of course, that refers only to the quotes that are the same as the enclosing ones. So, as a more elegant solution, we could switch to double quotes or backticks instead:
+Of course, only to the quotes that are the same as the enclosing ones need to be escaped. So, as a more elegant solution, we could switch to double quotes or backticks instead:
```js run
alert( `I'm the Walrus!` ); // I'm the Walrus!
@@ -120,7 +128,6 @@ alert( `The backslash: \\` ); // The backslash: \
## String length
-
The `length` property has the string length:
```js run
@@ -189,7 +196,7 @@ For instance:
```js run
let str = 'Hi';
-str = 'h' + str[1]; // replace the string
+str = 'h' + str[1]; // replace the string
alert( str ); // hi
```
@@ -242,10 +249,8 @@ let str = 'Widget with id';
alert( str.indexOf('id', 2) ) // 12
```
-
If we're interested in all occurrences, we can run `indexOf` in a loop. Every new call is made with the position after the previous match:
-
```js run
let str = 'As sly as a fox, as strong as an ox';
@@ -305,10 +310,11 @@ if (str.indexOf("Widget") != -1) {
}
```
-````smart header="The bitwise NOT trick"
+#### The bitwise NOT trick
+
One of the old tricks used here is the [bitwise NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT) `~` operator. It converts the number to a 32-bit integer (removes the decimal part if exists) and then reverses all bits in its binary representation.
-For 32-bit integers the call `~n` means exactly the same as `-(n+1)` (due to IEEE-754 format).
+In practice, that means a simple thing: for 32-bit integers `~n` equals `-(n+1)`.
For instance:
@@ -321,9 +327,9 @@ alert( ~-1 ); // 0, the same as -(-1+1)
*/!*
```
-As we can see, `~n` is zero only if `n == -1`.
+As we can see, `~n` is zero only if `n == -1` (that's for any 32-bit signed integer `n`).
-So, the test `if ( ~str.indexOf("...") )` is truthy that the result of `indexOf` is not `-1`. In other words, when there is a match.
+So, the test `if ( ~str.indexOf("...") )` is truthy only if the result of `indexOf` is not `-1`. In other words, when there is a match.
People use it to shorten `indexOf` checks:
@@ -338,7 +344,10 @@ if (~str.indexOf("Widget")) {
It is usually not recommended to use language features in a non-obvious way, but this particular trick is widely used in old code, so we should understand it.
Just remember: `if (~str.indexOf(...))` reads as "if found".
-````
+
+To be precise though, as big numbers are truncated to 32 bits by `~` operator, there exist other numbers that give `0`, the smallest is `~4294967295=0`. That makes such check is correct only if a string is not that long.
+
+Right now we can see this trick only in the old code, as modern JavaScript provides `.includes` method (see below).
### includes, startsWith, endsWith
@@ -355,15 +364,15 @@ alert( "Hello".includes("Bye") ); // false
The optional second argument of `str.includes` is the position to start searching from:
```js run
-alert( "Midget".includes("id") ); // true
-alert( "Midget".includes("id", 3) ); // false, from position 3 there is no "id"
+alert( "Widget".includes("id") ); // true
+alert( "Widget".includes("id", 3) ); // false, from position 3 there is no "id"
```
The methods [str.startsWith](mdn:js/String/startsWith) and [str.endsWith](mdn:js/String/endsWith) do exactly what they say:
```js run
alert( "Widget".startsWith("Wid") ); // true, "Widget" starts with "Wid"
-alert( "Widget".endsWith("get") ); // true, "Widget" ends with "get"
+alert( "Widget".endsWith("get") ); // true, "Widget" ends with "get"
```
## Getting a substring
@@ -397,7 +406,6 @@ There are 3 methods in JavaScript to get a substring: `substring`, `substr` and
alert( str.slice(-4, -1) ); // gif
```
-
`str.substring(start [, end])`
: Returns the part of the string *between* `start` and `end`.
@@ -405,7 +413,6 @@ There are 3 methods in JavaScript to get a substring: `substring`, `substr` and
For instance:
-
```js run
let str = "st*!*ring*/!*ify";
@@ -421,7 +428,6 @@ There are 3 methods in JavaScript to get a substring: `substring`, `substr` and
Negative arguments are (unlike slice) not supported, they are treated as `0`.
-
`str.substr(start [, length])`
: Returns the part of the string from `start`, with the given `length`.
@@ -447,11 +453,10 @@ Let's recap these methods to avoid any confusion:
| `substring(start, end)` | between `start` and `end` | negative values mean `0` |
| `substr(start, length)` | from `start` get `length` characters | allows negative `start` |
-
```smart header="Which one to choose?"
All of them can do the job. Formally, `substr` has a minor drawback: it is described not in the core JavaScript specification, but in Annex B, which covers browser-only features that exist mainly for historical reasons. So, non-browser environments may fail to support it. But in practice it works everywhere.
-The author finds themself using `slice` almost all the time.
+Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write. So, it's enough to remember solely `slice` of these three methods.
```
## Comparing strings
@@ -514,7 +519,7 @@ alert( str );
// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
```
-See? Capital characters go first, then a few special ones, then lowercase characters.
+See? Capital characters go first, then a few special ones, then lowercase characters, and `Ö` near the end of the output.
Now it becomes obvious why `a > Z`.
@@ -523,10 +528,9 @@ The characters are compared by their numeric code. The greater code means that t
- All lowercase letters go after uppercase letters because their codes are greater.
- Some letters like `Ö` stand apart from the main alphabet. Here, it's code is greater than anything from `a` to `z`.
-
### Correct comparisons
-The "right" algorithm to do string comparisons is more complex than it may seem, because alphabets are different for different languages. The same-looking letter may be located differently in different alphabets.
+The "right" algorithm to do string comparisons is more complex than it may seem, because alphabets are different for different languages.
So, the browser needs to know the language to compare.
@@ -534,11 +538,11 @@ Luckily, all modern browsers (IE10- requires the additional library [Intl.JS](ht
It provides a special method to compare strings in different languages, following their rules.
-The call [str.localeCompare(str2)](mdn:js/String/localeCompare):
+The call [str.localeCompare(str2)](mdn:js/String/localeCompare) returns an integer indicating whether `str` is less, equal or greater than `str2` according to the language rules:
-- Returns `1` if `str` is greater than `str2` according to the language rules.
-- Returns `-1` if `str` is less than `str2`.
-- Returns `0` if they are equal.
+- Returns a negative number if `str` is less than `str2`.
+- Returns a positive number if `str` is greater than `str2`.
+- Returns `0` if they are equivalent.
For instance:
@@ -546,7 +550,7 @@ For instance:
alert( 'Österreich'.localeCompare('Zealand') ); // -1
```
-This method actually has two additional arguments specified in [the documentation](mdn:js/String/localeCompare), which allows it to specify the language (by default taken from the environment) and setup additional rules like case sensitivity or should `"a"` and `"á"` be treated as the same etc.
+This method actually has two additional arguments specified in [the documentation](mdn:js/String/localeCompare), which allows it to specify the language (by default taken from the environment, letter order depends on the language) and setup additional rules like case sensitivity or should `"a"` and `"á"` be treated as the same etc.
## Internals, Unicode
@@ -558,7 +562,7 @@ You can skip the section if you don't plan to support them.
### Surrogate pairs
-Most symbols have a 2-byte code. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation.
+All frequently used characters have 2-byte codes. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation.
But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol. So rare symbols are encoded with a pair of 2-byte characters called "a surrogate pair".
@@ -567,7 +571,7 @@ The length of such symbols is `2`:
```js run
alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X
alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY
-alert( '𩷶'.length ); // 2, a rare chinese hieroglyph
+alert( '𩷶'.length ); // 2, a rare Chinese hieroglyph
```
Note that surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language!
@@ -576,7 +580,7 @@ We actually have a single symbol in each of the strings above, but the `length`
`String.fromCodePoint` and `str.codePointAt` are few rare methods that deal with surrogate pairs right. They recently appeared in the language. Before them, there were only [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt). These methods are actually the same as `fromCodePoint/codePointAt`, but don't work with surrogate pairs.
-But, for instance, getting a symbol can be tricky, because surrogate pairs are treated as two characters:
+Getting a symbol can be tricky, because surrogate pairs are treated as two characters:
```js run
alert( '𝒳'[0] ); // strange symbols...
@@ -604,7 +608,7 @@ In many languages there are symbols that are composed of the base character with
For instance, the letter `a` can be the base character for: `àáâäãåā`. Most common "composite" character have their own code in the UTF-16 table. But not all of them, because there are too many possible combinations.
-To support arbitrary compositions, UTF-16 allows us to use several unicode characters. The base character and one or many "mark" characters that "decorate" it.
+To support arbitrary compositions, UTF-16 allows us to use several unicode characters: the base character followed by one or many "mark" characters that "decorate" it.
For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ.
@@ -627,10 +631,12 @@ This provides great flexibility, but also an interesting problem: two characters
For instance:
```js run
-alert( 'S\u0307\u0323' ); // Ṩ, S + dot above + dot below
-alert( 'S\u0323\u0307' ); // Ṩ, S + dot below + dot above
+let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below
+let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above
-alert( 'S\u0307\u0323' == 'S\u0323\u0307' ); // false
+alert( `s1: ${s1}, s2: ${s2}` );
+
+alert( s1 == s2 ); // false though the characters look identical (?!)
```
To solve this, there exists a "unicode normalization" algorithm that brings each string to the single "normal" form.
@@ -649,14 +655,13 @@ alert( "S\u0307\u0323".normalize().length ); // 1
alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
```
-In reality, this is not always the case. The reason being that the symbol `Ṩ` is "common enough", so UTF-16 creators included it in the main table and gave it the code.
+In reality, this is not always the case. The reason being that the symbol `Ṩ` is "common enough", so UTF-16 creators included it in the main table and gave it the code.
If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](http://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough.
-
## Summary
-- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions.
+- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`.
- Strings in JavaScript are encoded using UTF-16.
- We can use special characters like `\n` and insert letters by their unicode using `\u...`.
- To get a character, use: `[]`.
@@ -669,6 +674,6 @@ There are several other helpful methods in strings:
- `str.trim()` -- removes ("trims") spaces from the beginning and end of the string.
- `str.repeat(n)` -- repeats the string `n` times.
-- ...and more. See the [manual](mdn:js/String) for details.
+- ...and more to be found in the [manual](mdn:js/String).
-Strings also have methods for doing search/replace with regular expressions. But that topic deserves a separate chapter, so we'll return to that later.
+Strings also have methods for doing search/replace with regular expressions. But that's big topic, so it's explained in a separate tutorial section Hello @@ -148,7 +159,9 @@ You see? The `
` appeared out of nowhere. You should keep this in mind whi ## Other node types -Let's add more tags and a comment to the page: +There are some other node types besides elements and text nodes. + +For example, comments: ```html @@ -174,7 +187,7 @@ let node6 = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1, drawHtmlTree(node6, 'div.domtree', 690, 500); -Here we see a new tree node type -- *comment node*, labeled as `#comment`. +We can see here a new tree node type -- *comment node*, labeled as `#comment`, between two text nodes. We may think -- why is a comment added to the DOM? It doesn't affect the visual representation in any way. But there's a rule -- if something's in HTML, then it also must be in the DOM tree. @@ -195,8 +208,6 @@ There are [12 node types](https://dom.spec.whatwg.org/#node). In practice we usu To see the DOM structure in real-time, try [Live DOM Viewer](http://software.hixie.ch/utilities/js/live-dom-viewer/). Just type in the document, and it will show up DOM at an instant. -## In the browser inspector - Another way to explore the DOM is to use the browser developer tools. Actually, that's what we use when developing. To do so, open the web-page [elks.html](elks.html), turn on the browser developer tools and switch to the Elements tab. @@ -225,10 +236,12 @@ The best way to study them is to click around. Most values are editable in-place ## Interaction with console -As we explore the DOM, we also may want to apply JavaScript to it. Like: get a node and run some code to modify it, to see the result. Here are few tips to travel between the Elements tab and the console. +As we work the DOM, we also may want to apply JavaScript to it. Like: get a node and run some code to modify it, to see the result. Here are few tips to travel between the Elements tab and the console. -- Select the first `...
*/!* - div.outerHTML = 'A new element!
'; // (*) + div.outerHTML = 'A new element
'; // (*) *!* // Wow! The div is still the same! */!* - alert(div.outerHTML); //...
`. In the outer document we can see the new content instead of the `A new element
`. In the outer document we can see the new content instead of the `A new element
` was inserted instead. +- `div` still has the old value. The new HTML wasn't saved to any variable. -We can write to `outerHTML`, but should keep in mind that it doesn't change the element we're writing to. It creates the new content on its place instead. We can get a reference to new elements by querying DOM. +It's so easy to make an error here: modify `div.outerHTML` and then continue to work with `div` as if it had the new content in it. But it doesn't. Such thing is correct for `innerHTML`, but not for `outerHTML`. + +We can write to `elem.outerHTML`, but should keep in mind that it doesn't change the element we're writing to. It creates the new HTML on its place instead. We can get references to new elements by querying DOM. ## nodeValue/data: text node content The `innerHTML` property is only valid for element nodes. -Other node types have their counterpart: `nodeValue` and `data` properties. These two are almost the same for practical use, there are only minor specification differences. So we'll use `data`, because it's shorter. +Other node types, such as text nodes, have their counterpart: `nodeValue` and `data` properties. These two are almost the same for practical use, there are only minor specification differences. So we'll use `data`, because it's shorter. An example of reading the content of a text node and a comment: @@ -345,7 +349,9 @@ An example of reading the content of a text node and a comment: ``` -For text nodes we can imagine a reason to read or modify them, but why comments? Usually, they are not interesting at all, but sometimes developers embed information or template instructions into HTML in them, like this: +For text nodes we can imagine a reason to read or modify them, but why comments? + +Sometimes developers embed information or template instructions into HTML in them, like this: ```html @@ -353,7 +359,7 @@ For text nodes we can imagine a reason to read or modify them, but why comments? ``` -...Then JavaScript can read it and process embedded instructions. +...Then JavaScript can read it from `data` property and process embedded instructions. ## textContent: pure text @@ -436,7 +442,7 @@ Here's a blinking element: ## More properties -DOM elements also have additional properties, many of them provided by the class: +DOM elements also have additional properties, in particular those that depend on the class: - `value` -- the value for ``, `