fixes
This commit is contained in:
parent
c9401b3104
commit
0fcf9f84fa
58 changed files with 673 additions and 643 deletions
|
@ -15,14 +15,14 @@ We can have as many statements in the code as we want. Another statement can be
|
|||
For example, here we split the message into two:
|
||||
|
||||
```js run no-beautify
|
||||
alert( 'Hello' ); alert( 'World' );
|
||||
alert('Hello'); alert('World');
|
||||
```
|
||||
|
||||
Usually each statement is written on a separate line -- thus the code becomes more readable:
|
||||
|
||||
```js run no-beautify
|
||||
alert( 'Hello' );
|
||||
alert( 'World' );
|
||||
alert('Hello');
|
||||
alert('World');
|
||||
```
|
||||
|
||||
## Semicolons [#semicolon]
|
||||
|
@ -32,8 +32,8 @@ A semicolon may be omitted in most cases when a line break exists.
|
|||
This would also work:
|
||||
|
||||
```js run no-beautify
|
||||
alert( 'Hello' )
|
||||
alert( 'World' )
|
||||
alert('Hello')
|
||||
alert('World')
|
||||
```
|
||||
|
||||
Here JavaScript interprets the line break as an "implicit" semicolon. That's also called an [automatic semicolon insertion](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion).
|
||||
|
@ -61,23 +61,21 @@ If you're curious to see a concrete example of such an error, check this code ou
|
|||
[1, 2].forEach(alert)
|
||||
```
|
||||
|
||||
It shows `1` then `2`.
|
||||
|
||||
No need to think about the meaning of the brackets `[]` and `forEach` yet. We'll study them, for now -- it does not matter. Let's just remember the result.
|
||||
No need to think about the meaning of the brackets `[]` and `forEach` yet. We'll study them later, for now -- it does not matter. Let's just remember the result: it shows `1`, then `2`.
|
||||
|
||||
Now let's add an `alert` before the code. And *not* finish it with a semicolon:
|
||||
|
||||
```js run no-beautify
|
||||
alert( "There will be an error" )
|
||||
alert("There will be an error")
|
||||
|
||||
[1, 2].forEach(alert)
|
||||
[1, 2].forEach(alert)
|
||||
```
|
||||
|
||||
Now if we run it, only the first `alert` is shown, and then an error.
|
||||
Now if we run it, only the first `alert` is shown, and then we have an error!
|
||||
|
||||
But everything is fine again if we add a semicolon after `alert`:
|
||||
```js run
|
||||
alert( "All fine now" );
|
||||
alert("All fine now");
|
||||
|
||||
[1, 2].forEach(alert)
|
||||
```
|
||||
|
@ -85,12 +83,12 @@ alert( "All fine now" );
|
|||
Now we have the "All fine now" message and then `1` and `2`.
|
||||
|
||||
|
||||
The error in the no-semicolon variant occurs because automatic semicolon insertion rules are complex, and in particular, JavaScript does not imply a semicolon before square brackets `[...]`.
|
||||
The error in the no-semicolon variant occurs because JavaScript does not imply a semicolon before square brackets `[...]`.
|
||||
|
||||
And, because the semicolon is not auto-inserted, the code in the first example is treated as a single statement, like this:
|
||||
So, because the semicolon is not auto-inserted, the code in the first example is treated as a single statement, that's how the engine sees it:
|
||||
|
||||
```js run no-beautify
|
||||
alert( "There will be an error" )[1, 2].forEach(alert)
|
||||
alert("There will be an error")[1, 2].forEach(alert)
|
||||
```
|
||||
|
||||
But it should be two separate statements, not a single one. Such a merging in this case is just wrong, hence the error. There are other situations when such thing happens.
|
||||
|
@ -111,9 +109,9 @@ The rest of the line is a comment. It may occupy a full line of its own or follo
|
|||
Like here:
|
||||
```js run
|
||||
// This comment occupies a line of its own
|
||||
alert( 'Hello' );
|
||||
alert('Hello');
|
||||
|
||||
alert( 'World' ); // This comment follows the statement
|
||||
alert('World'); // This comment follows the statement
|
||||
```
|
||||
|
||||
**Multiline comments start with a slash and a star <code>"/*"</code> and end with a star and a slash <code>"*/"</code>.**
|
||||
|
@ -124,8 +122,8 @@ Like this:
|
|||
/* An example with two messages.
|
||||
This is a multiline comment.
|
||||
*/
|
||||
alert( 'Hello' );
|
||||
alert( 'World' );
|
||||
alert('Hello');
|
||||
alert('World');
|
||||
```
|
||||
|
||||
The content of comments is ignored, so if we put a code inside <code>/* ... */</code> it won't execute.
|
||||
|
@ -134,9 +132,9 @@ Sometimes it comes handy to temporarily disable a part of the code:
|
|||
|
||||
```js run
|
||||
/* Commenting out the code
|
||||
alert( 'Hello' );
|
||||
alert('Hello');
|
||||
*/
|
||||
alert( 'World' );
|
||||
alert('World');
|
||||
```
|
||||
|
||||
```smart header="Use hotkeys!"
|
||||
|
|
|
@ -4,9 +4,8 @@ For a long time JavaScript was evolving without compatibility issues. New featur
|
|||
|
||||
That had the benefit of never breaking the existing code. But the back side is that any mistake or an imprefect decision made by JavaScript creators got stuck in the language forever.
|
||||
|
||||
It had been so before ECMAScript 5 (ES5) appeared which added new features to the language and modified some of the existing ones.
|
||||
It had been so before 2009 when ECMAScript 5 (ES5) appeared. It added new features to the language and modified some of the existing ones. To keep the old code working, most modifications are off by default. One needs to enable them explicitly with a special directive `"use strict"`.
|
||||
|
||||
To keep the old code working, most modifications are off by default. One needs to enable them explicitly with a special directive `"use strict"`.
|
||||
|
||||
[cut]
|
||||
|
||||
|
@ -61,7 +60,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.
|
||||
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.
|
||||
|
||||
Here in the tutorial all code (except where said otherwise) works in `"use strict"`. but we'll still note the subtle differences of what happens if you forget it or if the visitor has an outdated browser. So you will also be able to write a code that also works for old IE if you'd like that.
|
||||
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.
|
||||
|
||||
## Summary
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ Second, the name of the current visitor:
|
|||
let currentUserName = "John";
|
||||
```
|
||||
|
||||
Again, we could shorten that to `userName` if we know beyound the reasonable doubt that the user is current.
|
||||
Again, we could shorten that to `userName` if we know for sure that the user is current.
|
||||
|
||||
Modern editors and autocomplete make long variable names easy to write. Don't save on them. Say, a name with 3 words in it is fine.
|
||||
Modern editors and autocomplete make long variable names easy to write. Don't save on them. A name with 3 words in it is fine.
|
||||
|
||||
And if your editor does not have proper autocompletion, get [a new one](/editor).
|
||||
And if your editor does not have proper autocompletion, get [a new one](/editors).
|
||||
|
|
|
@ -4,5 +4,5 @@ importance: 3
|
|||
|
||||
# Giving the right name
|
||||
|
||||
1. Create the variable to store the name of our planet. Assign the value `"Earth"` to it. What should be its name?
|
||||
2. Create the variable to store the name of the current visitor. What about its name?
|
||||
1. Create the variable with the name of our planet. How would you name such a variable?
|
||||
2. Create the variable to store the name of the current visitor. How would you name that variable?
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# Variables
|
||||
|
||||
Most of the time, a script needs to work with the information.
|
||||
|
||||
If it's an online-shop -- that's going to be the goods and a shopping cart. If it's a chat -- users, messages and so on.
|
||||
Most of the time, a script needs to work with information. If it's an online-shop -- that's going to be the goods and a shopping cart. If it's a chat -- users, messages and so on.
|
||||
|
||||
Variables are used to store the information.
|
||||
|
||||
|
@ -10,17 +8,17 @@ Variables are used to store the information.
|
|||
|
||||
## A variable
|
||||
|
||||
A [variable]("https://en.wikipedia.org/wiki/Variable_(computer_science)") is a "named storage" for the information. We can use variables to store goodies, visitors and other data.
|
||||
A [variable](https://en.wikipedia.org/wiki/Variable_(computer_science)) is a "named storage" for data. We can use variables to store goodies, visitors and other data.
|
||||
|
||||
To create a variable in JavaScript, we need to use the `let` keyword.
|
||||
|
||||
The statement below creates (in other words: *declares* or *defines*) the variable with the name "message":
|
||||
The statement below creates (in other words: *declares* or *defines*) a variable with the name "message":
|
||||
|
||||
```js
|
||||
let message;
|
||||
```
|
||||
|
||||
Now we can put some data into it:
|
||||
Now we can put some data into it by using the assignment operator `=`:
|
||||
|
||||
```js
|
||||
let message;
|
||||
|
@ -37,7 +35,7 @@ let message;
|
|||
message = 'Hello!';
|
||||
|
||||
*!*
|
||||
alert( message ); // shows the variable content
|
||||
alert(message); // shows the variable content
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -92,12 +90,12 @@ In older scripts you may also find another keyword: `var` instead of `let`:
|
|||
|
||||
The `var` keyword is *almost* the same as `let`. It also declares a variable, but in a slightly different, "old-school" fashion.
|
||||
|
||||
There are subtle differences between `let` and `var`, but they do not matter for us yet. We'll cover them in detail later.
|
||||
There are subtle differences between `let` and `var`, but they do not matter for us yet. We'll cover them in detail later, in the chapter <info:var>.
|
||||
````
|
||||
|
||||
## A real-life analogy
|
||||
|
||||
We can easily grasp the concept of a "variable" if we imagine it as a "box" for the data, with the unique-named sticker on it.
|
||||
We can easily grasp the concept of a "variable" if we imagine it as a "box" for data, with a unique-named sticker on it.
|
||||
|
||||
For instance, the variable `message` can be imagined as a box labelled `"message"` with the value `"Hello!"` in it:
|
||||
|
||||
|
@ -114,14 +112,14 @@ message = 'Hello!';
|
|||
|
||||
message = 'World!'; // value changed
|
||||
|
||||
alert( message );
|
||||
alert(message);
|
||||
```
|
||||
|
||||
When the value is changed, the old data is removed from the variable:
|
||||
|
||||

|
||||
|
||||
We can also declare two variables and copy the data from one into the other.
|
||||
We can also declare two variables and copy data from one into the other.
|
||||
|
||||
```js run
|
||||
let hello = 'Hello world!';
|
||||
|
@ -133,22 +131,22 @@ let message;
|
|||
message = hello;
|
||||
*/!*
|
||||
|
||||
// now two variables have the same data
|
||||
alert( hello ); // Hello world!
|
||||
alert( message ); // Hello world!
|
||||
// now two variables hold the same data
|
||||
alert(hello); // Hello world!
|
||||
alert(message); // Hello world!
|
||||
```
|
||||
|
||||
```smart header="Functional languages"
|
||||
It may be interesting to know that there also exist [functional](http://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) programming languages that forbid to change a variable value. For example, [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/).
|
||||
It may be interesting to know that there also exist [functional](https://en.wikipedia.org/wiki/Functional_programming) programming languages that forbid changing a variable value. For example, [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/).
|
||||
|
||||
In such languages, once the value is assined "into the box" -- it's there forever. If we need to store something else -- the language forces to create a new box (declare a new variable), we can't reuse the old one.
|
||||
In such languages, once the value is stored "in the box" -- it's there forever. If we need to store something else -- the language forces to create a new box (declare a new variable), we can't reuse the old one.
|
||||
|
||||
Though it may seem a little bit odd at the first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation infers certain benefits. Studying of such a language (even if you're not planning to use it soon) is recommended to broaden one's mind.
|
||||
Though it may seem a little bit odd at the first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation infers certain benefits. Studying of such a language (even if not planning to use it soon) is recommended to broaden the mind.
|
||||
```
|
||||
|
||||
## Variable naming [#variable-naming]
|
||||
|
||||
There are two limitations for the variable name in JavaScript:
|
||||
There are two limitations for a variable name in JavaScript:
|
||||
|
||||
1. The name must contain only letters, digits, symbols `$` and `_`.
|
||||
2. The first character must not be a digit.
|
||||
|
@ -168,9 +166,9 @@ These names are valid:
|
|||
|
||||
```js run untrusted
|
||||
let $ = 1; // declared a variable with the name "$"
|
||||
let _ = 2; // and now the variable with the name "_"
|
||||
let _ = 2; // and now a variable with the name "_"
|
||||
|
||||
alert( $ + _ ); // 3
|
||||
alert($ + _); // 3
|
||||
```
|
||||
|
||||
Examples of incorrect variable names:
|
||||
|
@ -211,15 +209,17 @@ let return = 5; // also can't name it "return", error!
|
|||
|
||||
````warn header="An assignment without `use strict`"
|
||||
|
||||
Normally, we need to define a variable before using it. But in the old times, it was technically possible to create a variable by a mere assignment of the value. This still works now in if we don't put `use strict`, the behavior is kept for compatibility with old scripts.
|
||||
Normally, we need to define a variable before using it. But in the old times, it was technically possible to create a variable by a mere assignment of the value, without `let`. This still works now in if we don't put `use strict`, the behavior is kept for compatibility with old scripts.
|
||||
|
||||
```js run no-strict
|
||||
// note: no "use strict" in this example
|
||||
|
||||
num = 5; // the variable "num" is created if didn't exist
|
||||
|
||||
alert(num); // 5
|
||||
```
|
||||
|
||||
That's a bad practice of course, it gives an error in the strict mode:
|
||||
That's a bad practice, it gives an error in the strict mode:
|
||||
|
||||
```js run untrusted
|
||||
"use strict";
|
||||
|
@ -233,7 +233,7 @@ num = 5; // error: num is not defined
|
|||
|
||||
## Constants
|
||||
|
||||
To declare a constant (unchanging) variable, one can use `const`:
|
||||
To declare a constant (unchanging) variable, one can use `const` instead of `let`:
|
||||
|
||||
```js
|
||||
const myBirthday = '18.04.1982';
|
||||
|
@ -266,36 +266,41 @@ const COLOR_ORANGE = "#FF7F00";
|
|||
|
||||
// ...when we need to pick a color
|
||||
let color = COLOR_ORANGE;
|
||||
alert( color ); // #FF7F00
|
||||
alert(color); // #FF7F00
|
||||
```
|
||||
|
||||
`COLOR_ORANGE` is much easier to remember than `"#FF7F00"`. Also it is much easier to mistype in `"#FF7F00"` than in `COLOR_ORANGE`. And when reading the code -- `COLOR_ORANGE` is much more meaningful.
|
||||
Benefits:
|
||||
|
||||
- `COLOR_ORANGE` is much easier to remember than `"#FF7F00"`.
|
||||
- It is much easier to mistype in `"#FF7F00"` than in `COLOR_ORANGE`.
|
||||
- When reading the code -- `COLOR_ORANGE` is much more meaningful than `#FF7F00`.
|
||||
|
||||
When should we use capitals for a constant, and when -- name them normally? Let's make that clear.
|
||||
|
||||
Being a "constant" just means that the value never changes. But there are constants that are known prior to execution (like a hexadimal value for red), and there are those that are *calculated* during the execution, but do not change since then.
|
||||
Being a "constant" just means that the value never changes. But there are constants that are known prior to execution (like a hexadimal value for red), and there are those that are *calculated* in run-time, during the execution, but do not change after the assignment.
|
||||
|
||||
For instance:
|
||||
```js
|
||||
const ordinaryConst = /* an expression that uses the current date */;
|
||||
// the expression value is not known prior to execution
|
||||
// such a constant must be named normally
|
||||
const pageLoadTime = /* time taken by a webpage to load */;
|
||||
```
|
||||
|
||||
The value of `pageLoadTime` is not known prior to the page load, so it's named normally. But it's still a constant, because it doesn't change after assignment.
|
||||
|
||||
In other words, capital-named constants are only used as aliases for "hard-coded" values.
|
||||
|
||||
## Name things right
|
||||
|
||||
Talking about variables, there's one more exteremely important thing.
|
||||
|
||||
Please name the variables sensibly.
|
||||
Please name the variables sensibly. Take time to think if needed.
|
||||
|
||||
Variable naming is one of the most important and complex skills in programming. A quick glance at variable names can obviously show which code is written by a beginner and which by an experienced guru.
|
||||
Variable naming is one of the most important and complex skills in programming. A quick glance at variable names can reveal which code is written by a beginner and which by an experienced developer.
|
||||
|
||||
In a real project, most of the time is spent on modifying and extending the existing code base, rather than writing something completely separate of it. And when we return to the code after some time of doing something else, it's much easier to find the information that is well-labelled. Or, in other words, when the variables have good names.
|
||||
In a real project, most of the time is spent on modifying and extending the existing code base, rather than writing something completely separate from the scratch. And when we return to the code after some time of doing something else, it's much easier to find the information that is well-labelled. Or, in other words, when the variables have good names.
|
||||
|
||||
Please spend some time thinking about the right name for a variable before declaring it. That will repay you a lot.
|
||||
|
||||
Few good-to-follow rules are:
|
||||
Some good-to-follow rules are:
|
||||
|
||||
- Use human-readable names like `userName` or `shoppingCart`.
|
||||
- Stay away from abbreviations or short names `a`, `b`, `c`, unless you really know what you're doing.
|
||||
|
@ -313,7 +318,7 @@ Such a programmer saves a little bit on variable declaration, but looses ten tim
|
|||
|
||||
An extra variable is good, not evil.
|
||||
|
||||
Modern JavaScript minifiers and browsers optimize code well enough, so it won't create performance issues. Using different variables for values of different types can even help the engine to optimize better.
|
||||
Modern JavaScript minifiers and browsers optimize code well enough, so it won't create performance issues. Using different variables for different values can even help the engine to optimize.
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
@ -321,7 +326,7 @@ Modern JavaScript minifiers and browsers optimize code well enough, so it won't
|
|||
We can declare variables to store data. That can be done using `var` or `let` or `const`.
|
||||
|
||||
- `let` -- is a modern variable declaration. The code must be in strict mode to use `let` in Chrome (V8).
|
||||
- `var` -- is an old-school variable declaration. We'll study the subtle differences from `let` later.
|
||||
- `var` -- is an old-school variable declaration. Normally we don't use it at all, but we'll cover subtle differences from `let` in the chapter <info:var>, just in case if you'll need them.
|
||||
- `const` -- is like `let`, but the variable can't be changed.
|
||||
|
||||
Variables should be named in a way that allows to easily understand what's inside.
|
||||
|
|
|
@ -8,9 +8,9 @@ let message = "hello";
|
|||
message = 123456;
|
||||
```
|
||||
|
||||
Such languages are called "dynamically typed", meaning that there are language types, but variables are not bound to any of them.
|
||||
Programming languages that allow such thing are called "dynamically typed", meaning that there are data types, but variables are not bound to any of them.
|
||||
|
||||
There are 7 basic data types in JavaScript. Here we'll study the basics, and in the next chapters we'll talk about each of them in detail.
|
||||
There are 7 basic data types in JavaScript. Here we'll study the basics, and in next chapters we'll talk about each of them in detail.
|
||||
|
||||
[cut]
|
||||
|
||||
|
@ -21,11 +21,11 @@ let n = 123;
|
|||
n = 12.345;
|
||||
```
|
||||
|
||||
A *number* type serves both for integer and floating point numbers.
|
||||
The *number* type serves both for integer and floating point numbers.
|
||||
|
||||
There are many operations for numbers, e.g. multiplication `*`, division `/`, addition `+`, substraction `-` and so on.
|
||||
|
||||
Besides regular numbers there are so-called "special numeric values" which also belong to that type: `Infinity`, `-Infinity` and `NaN`.
|
||||
Besides regular numbers, there are so-called "special numeric values" which also belong to that type: `Infinity`, `-Infinity` and `NaN`.
|
||||
|
||||
- `Infinity` represents the mathematical [Infinity](https://en.wikipedia.org/wiki/Infinity) ∞. It is a special value that's greater than any number.
|
||||
|
||||
|
@ -80,23 +80,23 @@ In JavaScript, there are 3 types of quotes.
|
|||
2. Single quotes: `'Hello'`.
|
||||
3. Backticks: <code>`Hello`</code>.
|
||||
|
||||
Double and single quotes are "simple" quotes. They mark the beginning and the end of the string, that's all. There's no difference between them in JavaScript.
|
||||
Double and single quotes are "simple" quotes. There's no difference between them in JavaScript.
|
||||
|
||||
Backticks are "extended functionality" quotes. They allow to embed variables and expressions into a string by wrapping them in `${…}`, for example:
|
||||
|
||||
```js run
|
||||
let name = "John";
|
||||
|
||||
// embed variable
|
||||
alert( `Hello, ${name}!` ); // Hello, John!
|
||||
// embed a variable
|
||||
alert( `Hello, *!*${name}*/!*!` ); // Hello, John!
|
||||
|
||||
// embed expression
|
||||
alert( `the result is ${1 + 2}` ); // the result is 3
|
||||
// embed an expression
|
||||
alert( `the result is *!*${1 + 2}*/!*` ); // the result is 3
|
||||
```
|
||||
|
||||
The expression inside `${…}` is evaluated and the result becomes a part of the string. We can put anything there: a variable like `name` or an arithmetical expression like `1 + 2` or something more complex.
|
||||
|
||||
Please note that other quotes do not allow such embedding!
|
||||
Please note that this only can be done in backticks, other quotes do not allow such embedding!
|
||||
```js run
|
||||
alert( "the result is ${1 + 2}" ); // the result is ${1 + 2} (double quotes do nothing)
|
||||
```
|
||||
|
@ -109,7 +109,7 @@ In some languages, there is a special "character" type for a single character. F
|
|||
In JavaScript, there is no such type. There's only one type: `string`. A string may consist of only one character or many of them.
|
||||
```
|
||||
|
||||
## A boolean (logical)
|
||||
## A boolean (logical type)
|
||||
|
||||
The boolean type has only two values: `true` and `false`.
|
||||
|
||||
|
@ -118,11 +118,11 @@ This type is commonly used to store yes/no values: `true` means "yes, correct",
|
|||
For instance:
|
||||
|
||||
```js
|
||||
let nameChecked = true; // yes, the form field name is checked
|
||||
let ageChecked = false; // no, the form field age is not checked
|
||||
let nameFieldChecked = true; // yes, name field is checked
|
||||
let ageFieldChecked = false; // no, age field is not checked
|
||||
```
|
||||
|
||||
Boolean values also come as the result of comparisons:
|
||||
Boolean values also come as a result of comparisons:
|
||||
|
||||
```js run
|
||||
let isGreater = 4 > 1;
|
||||
|
@ -130,11 +130,11 @@ let isGreater = 4 > 1;
|
|||
alert( isGreater ); // true (the comparison result is "yes")
|
||||
```
|
||||
|
||||
We'll cover booleans more deeply later while discussing [logical operators](/logical-ops).
|
||||
We'll cover booleans more deeply later in the chapter <info:logical-operators>.
|
||||
|
||||
## The "null" value
|
||||
|
||||
The special `null` value does not belong to any type described above.
|
||||
The special `null` value does not belong to any type of those described above.
|
||||
|
||||
It forms a separate type of its own, which contains only the `null` value:
|
||||
|
||||
|
@ -152,24 +152,24 @@ The code above states that the `age` is unknown or empty for some reason.
|
|||
|
||||
The special value `undefined` stands apart. It makes a type of its own, just like `null`.
|
||||
|
||||
The sense of `undefined` is "value is not assigned".
|
||||
The meaning of `undefined` is "value is not assigned".
|
||||
|
||||
If a variable is declared, but not assigned, then its value is exactly `undefined`:
|
||||
|
||||
```js run
|
||||
let x;
|
||||
|
||||
alert( x ); // shows "undefined"
|
||||
alert(x); // shows "undefined"
|
||||
```
|
||||
|
||||
Technically, it is possible to assign to `undefined`:
|
||||
Technically, it is possible to assign any variable to `undefined`:
|
||||
|
||||
```js run
|
||||
let x = 123;
|
||||
|
||||
x = undefined;
|
||||
|
||||
alert( x ); // "undefined"
|
||||
alert(x); // "undefined"
|
||||
```
|
||||
|
||||
...But it's not recommended to do that. Normally, we use `null` to write an "empty" or an "unknown" value into the variable, and `undefined` is only used for checks, to see if the variable is assigned or similar.
|
||||
|
@ -178,9 +178,9 @@ alert( x ); // "undefined"
|
|||
|
||||
The `object` type is special.
|
||||
|
||||
All other types are called "primitive", because their values can contain only a single thing (be it a string or a number or whatever). In contrast, objects are used to store collections data and more complex entities. We'll deal with them later after we know enough about primitives.
|
||||
All other types are called "primitive", because their values can contain only a single thing (be it a string or a number or whatever). In contrast, objects are used to store collections data and more complex entities. We'll deal with them later in the chapter <info:object> after we know enough about primitives.
|
||||
|
||||
The `symbol` type is used to create unique identifiers for objects. We have to mention it here for completeness, but we'd better study them after covering objects.
|
||||
The `symbol` type is used to create unique identifiers for objects. We have to mention it here for completeness, but it's better to study them after objects.
|
||||
|
||||
## The typeof operator [#type-typeof]
|
||||
|
||||
|
@ -193,7 +193,7 @@ It supports two forms of syntax:
|
|||
|
||||
In other words, it works both with the brackets or without them. The result is the same.
|
||||
|
||||
The call to `typeof x` returns a string, which has the type name:
|
||||
The call to `typeof x` returns a string with the type name:
|
||||
|
||||
```js
|
||||
typeof undefined // "undefined"
|
||||
|
@ -219,22 +219,22 @@ typeof alert // "function" (3)
|
|||
*/!*
|
||||
```
|
||||
|
||||
The last three lines may be a little unobvious so here's explanations:
|
||||
The last three lines may need additional explanations:
|
||||
|
||||
1. `Math` is a built-in object that provides mathematical operations. We will learn it in the chapter <info:number>. Here it serves just as an example of an object.
|
||||
2. The result of `typeof null` equals to `"object"`. That's wrong. It is an officially recognized error in `typeof`, kept for compatibility. Of course, `null` is not an object. It is a special value with a separate type of its own. So, again, that's an error in the language.
|
||||
3. The result of `typeof alert` is `"function"`, because `alert` is a function of the language. We'll study functions in the near future and see that actually functions belong to the object type. But `typeof` treats them differently. That's very convenient in practice.
|
||||
2. The result of `typeof null` is `"object"`. That's wrong. It is an officially recognized error in `typeof`, kept for compatibility. Of course, `null` is not an object. It is a special value with a separate type of its own. So, again, that's an error in the language.
|
||||
3. The result of `typeof alert` is `"function"`, because `alert` is a function of the language. We'll study functions in the next chapters, and we'll see that there's no special "function" type in the language. Functions belong to the object type. But `typeof` treats them differently. Formally, it's incorrect, but very convenient in practice.
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
There are 7 basic types in JavaScript.
|
||||
|
||||
- `number` for numbers of any kind, can convert into it using `Number(value)`.
|
||||
- `string` for strings and characters, can convert into it using `String(value)`.
|
||||
- `boolean` for `true`/`false`, can convert into it using `Boolean(value)`.
|
||||
- `null` for unknown values (a standalone type that has a single value `null`).
|
||||
- `undefined` for unassigned values (a standalone type that has a single value `undefined`).
|
||||
- `number` for numbers of any kind: integer or floating-point.
|
||||
- `string` for strings. A string may have one more more characters, there's no separate single-character type.
|
||||
- `boolean` for `true`/`false`.
|
||||
- `null` for unknown values -- a standalone type that has a single value `null`.
|
||||
- `undefined` for unassigned values -- a standalone type that has a single value `undefined`.
|
||||
- `object` for more complex data structures.
|
||||
- `symbol` for unique identifiers.
|
||||
|
||||
|
@ -242,6 +242,6 @@ The `typeof` operator allows to see which type is stored in the variable.
|
|||
|
||||
- Two forms: `typeof x` or `typeof(x)`.
|
||||
- Returns a string with the name of the type, like `"string"`.
|
||||
- Mistreats `null` as an `object` -- the old official error in the language.
|
||||
- For `null` returns `"object"` -- that's the error in the language, it's not an object in fact.
|
||||
|
||||
In nearest chapters we'll concentrate on understanding how to operate on primitives and once we're familiar with that, then we'll move on to objects.
|
||||
In the next chapters we'll concentrate on primitive values and once we're familiar with that, then we'll move on to objects.
|
||||
|
|
|
@ -17,6 +17,6 @@ undefined + 1 = NaN // (4)
|
|||
```
|
||||
|
||||
1. The addition with a string `"" + 1` converts `1` to a string: `"" + 1 = "1"`, and then we have `"1" + 0`, the same rule is applied.
|
||||
2. The substruction `"-"` (like most math operations) only works with numbers, it converts an empty string `""` to zero immediately.
|
||||
2. The substruction `"-"` (like most math operations) only works with numbers, it converts an empty string `""` to `0`.
|
||||
3. `null` becomes `0` after the numeric conversion.
|
||||
4. `undefined` becomes `NaN` after the numeric conversion.
|
||||
|
|
|
@ -4,7 +4,7 @@ importance: 5
|
|||
|
||||
# Type conversions
|
||||
|
||||
What will be the result of these evaluation?
|
||||
What are results of these expressions?
|
||||
|
||||
```js no-beautify
|
||||
"" + 1 + 0
|
||||
|
|
|
@ -2,37 +2,31 @@
|
|||
|
||||
Most of time, operators and functions automatically convert a value to the right type. That's called "type coercion".
|
||||
|
||||
For example, `alert` automatically converts any value to a string, to show it. Or mathematical operations convert values to numbers.
|
||||
For example, `alert` automatically converts any value to a string to show it. Mathematical operations convert values to numbers.
|
||||
|
||||
There are also cases when we need to explicitly convert a value to put things right.
|
||||
|
||||
[cut]
|
||||
|
||||
```smart header="Not covering objects yet"
|
||||
In this chapter we don't cover objects yet. Here we study primitives first, and then we'll see what happens with objects in the chapter <info:object-toprimitive>.
|
||||
```smart header="Not talking about objects yet"
|
||||
In this chapter we don't cover objects yet. Here we study primitives first. Later, after we learn objects, we'll see how object conversion works in the chapter <info:object-toprimitive>.
|
||||
```
|
||||
|
||||
## ToString
|
||||
|
||||
The string conversion happens when we need a string form of a value.
|
||||
|
||||
For example, `alert` does it:
|
||||
|
||||
```js run
|
||||
let a = true;
|
||||
|
||||
alert(a); // "true"
|
||||
```
|
||||
For example, `alert(value)` does it to show the value.
|
||||
|
||||
We can also use a call `String(value)` function for that:
|
||||
|
||||
```js run
|
||||
let a = true;
|
||||
alert(typeof a); // boolean
|
||||
let value = true;
|
||||
alert(typeof value); // boolean
|
||||
|
||||
*!*
|
||||
a = String(a); // now: a = "true"
|
||||
alert(typeof a); // string
|
||||
value = String(value); // now value is a string "true"
|
||||
alert(typeof value); // string
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -42,7 +36,7 @@ The string conversion is mostly obvious. A `false` becomes `"false"`, `null` bec
|
|||
|
||||
Numeric conversion happens in mathematical functions and expressions automatically.
|
||||
|
||||
For example, when division '/' is applied to non-numbers:
|
||||
For example, when division `/` is applied to non-numbers:
|
||||
|
||||
```js run
|
||||
alert( "6" / "2" ); // 3, strings are converted to numbers
|
||||
|
@ -54,12 +48,12 @@ We can use a `Number(value)` function to explicitly convert a `value`:
|
|||
let str = "123";
|
||||
alert(typeof str); // string
|
||||
|
||||
let n = Number(str); // becomes a number 123
|
||||
let num = Number(str); // becomes a number 123
|
||||
|
||||
alert(typeof n); // number
|
||||
alert(typeof num); // number
|
||||
```
|
||||
|
||||
The explicit conversion is usually required when we read a value coming from a text form field or another string-based source, but we expect a number to be entered.
|
||||
The explicit conversion is usually required when we read a value from a string-based source like a text form, but we expect a number to be entered.
|
||||
|
||||
If the string is not a valid number, the result of such conversion is `NaN`, for instance:
|
||||
|
||||
|
@ -69,7 +63,7 @@ let age = Number("an arbitrary string instead of a number");
|
|||
alert(age); // NaN, conversion failed
|
||||
```
|
||||
|
||||
The numeric conversion rules:
|
||||
Numeric conversion rules:
|
||||
|
||||
| Value | Becomes... |
|
||||
|-------|-------------|
|
||||
|
@ -97,8 +91,6 @@ Then it concatenates (joins) them:
|
|||
```js run
|
||||
alert( 1 + '2' ); // '12' (string to the right)
|
||||
alert( '1' + 2 ); // '12' (string to the left)
|
||||
|
||||
alert( 1 + 2 ); // 3, numbers (for the contrast)
|
||||
```
|
||||
|
||||
That only happens when one of arguments is a string. Otherwise values are converted to numbers.
|
||||
|
@ -130,14 +122,14 @@ Some languages (namely PHP) treat `"0"` as `false`. But in JavaScript a non-empt
|
|||
|
||||
```js run
|
||||
alert( Boolean("0") ); // true
|
||||
alert( Boolean(" ") ); // also true (any non-empty string is true)
|
||||
alert( Boolean(" ") ); // spaces, also true (any non-empty string is true)
|
||||
```
|
||||
````
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
There exist three most widely used type conversions: to string, to number and to boolean.
|
||||
There are three most widely used type conversions: to string, to number and to boolean.
|
||||
|
||||
**`ToString`** -- occurs when we output something, can be performed with `String(value)`. The conversion to string is usually obvious for primitive values.
|
||||
|
||||
|
@ -164,7 +156,7 @@ Follows the rules:
|
|||
|
||||
Most of these rules are easy to understand and memorize. The notable exceptions where people usually make mistakes are:
|
||||
|
||||
- `undefined` is `NaN` as a number.
|
||||
- `"0"` is true as a boolean.
|
||||
- `undefined` is `NaN` as a number, not `0`.
|
||||
- `"0"` and space-only strings like `" "` are true as a boolean.
|
||||
|
||||
Objects are not covered here, we'll return to them later in the chapter <info:object-toprimitive>, devoted exclusively to objects, after we learn more basic things about JavaScript.
|
||||
Objects are not covered here, we'll return to them later in the chapter <info:object-toprimitive> that is devoted exclusively to objects, after we learn more basic things about JavaScript.
|
||||
|
|
|
@ -4,7 +4,7 @@ importance: 5
|
|||
|
||||
# The postfix and prefix forms
|
||||
|
||||
What are the final values of all variables in the code below?
|
||||
What are the final values of all variables `a`, `b`, `c` and `d` after the code below?
|
||||
|
||||
```js
|
||||
let a = 1, b = 1;
|
||||
|
@ -12,4 +12,3 @@ let a = 1, b = 1;
|
|||
let c = ++a; // ?
|
||||
let d = b++; // ?
|
||||
```
|
||||
|
||||
|
|
|
@ -4,11 +4,10 @@ importance: 3
|
|||
|
||||
# Assignment result
|
||||
|
||||
What will be values of `a` and `x` in the example below?
|
||||
What are the values of `a` and `x` after the code below?
|
||||
|
||||
```js
|
||||
let a = 2;
|
||||
|
||||
let x = 1 + (a *= 2);
|
||||
```
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Operators
|
||||
|
||||
Many operators are known to us from the school program. 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 substraction `-` and so on.
|
||||
|
||||
In this chapter we concentrate on aspects that are not covered by the school arithmetic.
|
||||
|
||||
|
@ -32,7 +32,7 @@ Before we move on, let's grasp the common terminology.
|
|||
|
||||
## Strings concatenation, binary +
|
||||
|
||||
Now let's see special features of JavaScript operators, beyond school arithmetics.
|
||||
Now let's see special features of JavaScript operators that are beyond school arithmetics.
|
||||
|
||||
Usually the plus operator `'+'` sums numbers.
|
||||
|
||||
|
@ -126,7 +126,7 @@ If an expression has more than one operator, the execution order is defined by t
|
|||
|
||||
From the school we all know that the multiplication in the expression `1 + 2 * 2` should be calculated before the addition. That's exactly the precedence thing. The multiplication is said to have *a higher precedence* than the addition.
|
||||
|
||||
Brackets override any precedence, so if we're not satisfied with the order, we can use them, like: `(1 + 2) * 2`.
|
||||
Parentheses override any precedence, so if we're not satisfied with the order, we can use them, like: `(1 + 2) * 2`.
|
||||
|
||||
There are many operators in JavaScript. Every operator has a corresponding precedence number. The one with the bigger number executes first. If the precedence is same -- the execution order is from left to right.
|
||||
|
||||
|
@ -173,14 +173,14 @@ alert( b ); // 4
|
|||
alert( c ); // 4
|
||||
```
|
||||
|
||||
Assignments always evaluate the right value first, then assign it to the left one. So the chain of assignments is executed from right to left: the rightmost expression `2+2` is calculated first, assigned to `c`, then `b = c` works, thus assigning it to `b`, and then `a = b`. At the end, all variables share a single value.
|
||||
Chained assignments evaluate from right to left. First the rightmost expression `2+2` is evaluated then assigned to the variables on the left: `c`, `b` and `a`. At the end, all variables share a single value.
|
||||
|
||||
````smart header="The assignment operator `\"=\"` returns a value"
|
||||
An operator always returns a value. That's obvious for most of them like an addition `+` or a multiplication `*`. But the assignment operator follows that rule too.
|
||||
|
||||
The call `x = value` writes the `value` into `x` *and then returns it*.
|
||||
|
||||
So it is actually possible to use an assignment as the part of a more complex expression:
|
||||
Here's the demo that uses an assignment as the part of a more complex expression:
|
||||
|
||||
```js run
|
||||
let a = 1;
|
||||
|
@ -196,7 +196,7 @@ 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`.
|
||||
|
||||
Funny code, isn't it? We should understand how it works, because sometimes we can see it in 3rd-party libraries, but don't write anything like that ourselves. Such tricks definitely don't make the code clearer and more readable.
|
||||
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.
|
||||
````
|
||||
|
||||
## Remainder %
|
||||
|
@ -215,7 +215,7 @@ alert( 6 % 3 ); // 0 is a remainder of 6 divided by 3
|
|||
|
||||
## Exponentiation **
|
||||
|
||||
The exponentiation operator `**` is a recent addition to the language. Not all browsers support it yet.
|
||||
The exponentiation operator `**` is a recent addition to the language.
|
||||
|
||||
For a natural number `b`, the result of `a ** b` is `a` multiplied by itself `b` times.
|
||||
|
||||
|
@ -227,14 +227,13 @@ alert( 2 ** 3 ); // 8 (2 * 2 * 2)
|
|||
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
|
||||
```
|
||||
|
||||
The operator works with non-integer numbers of `a` and `b` as well, for instance:
|
||||
The operator works for non-integer numbers of `a` and `b` as well, for instance:
|
||||
|
||||
```js run
|
||||
alert( 4 ** (1/2) ); // 2 (square root of 4)
|
||||
alert( 8 ** (1/3) ); // 2 (cubic root of 8)
|
||||
alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root, that's maths)
|
||||
alert( 8 ** (1/3) ); // 2 (power of 1/3 is the same as a cubic root)
|
||||
```
|
||||
|
||||
|
||||
## Increment/decrement: ++, --
|
||||
|
||||
Increasing or decreasing a number by one is among the most common numerical operations.
|
||||
|
@ -271,7 +270,7 @@ Is there any difference? Yes, but we can only see it if we use the retured value
|
|||
|
||||
Let's clarify. As we know, all operators return a value. Increment/decrement is not an exception here. The prefix form returns the new value, while the postfix form returns the old value (prior to increment/decrement).
|
||||
|
||||
Let's see the examples:
|
||||
To see the difference -- here's the example:
|
||||
|
||||
```js run
|
||||
let counter = 1;
|
||||
|
@ -303,7 +302,7 @@ To summarize:
|
|||
++counter;
|
||||
alert( counter ); // 2, the lines above did the same
|
||||
```
|
||||
- If we'd like to use the result of the operator right now, then we need the prefix form:
|
||||
- If we'd like to increase the value *and* use the result of the operator right now, then we need the prefix form:
|
||||
|
||||
```js run
|
||||
let counter = 0;
|
||||
|
@ -362,7 +361,7 @@ The list of operators:
|
|||
- RIGHT SHIFT ( `>>` )
|
||||
- ZERO-FILL RIGHT SHIFT ( `>>>` )
|
||||
|
||||
These operators are used very rarely. To understand them, we should delve into low-level number representation, and it would not be optimal to do that right now. Especially because we won't need them any time soon. If you're curious, you can read the [Bitwise Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) article in MDN. But it would be more practical to do that when a real need arises.
|
||||
These operators are used very rarely. To understand them, we should delve into low-level number representation, and it would not be optimal to do that right now. Especially because we won't need them any time soon. If you're curious, you can read the [Bitwise Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) article in MDN. It would be more practical to do that when a real need arises.
|
||||
|
||||
## Modify-in-place
|
||||
|
||||
|
@ -388,18 +387,19 @@ alert( n ); // 14
|
|||
|
||||
Short "modify-and-assign" operators exist for all arithmetical and bitwise operators: `/=`, `-=` etc.
|
||||
|
||||
The modify-and-assign call has the same precedence as a normal assignment, so it executes after most other calculations:
|
||||
Such operators have the same precedence as a normal assignment, so they run after most other calculations:
|
||||
|
||||
```js run
|
||||
let n = 2;
|
||||
|
||||
n *= 3 + 5;
|
||||
|
||||
alert( n ); // 16 (same as n *= 8)
|
||||
alert( n ); // 16 (right part evaluated first, same as n *= 8)
|
||||
```
|
||||
|
||||
## Comma
|
||||
|
||||
The comma operator `','` is one of most rare and unusual ones. Sometimes it's used to write shorter code, so we need to know it in order understand what's going on.
|
||||
The comma operator `','` is one of most rare and unusual operators. Sometimes it's used to write shorter code, so we need to know it in order to understand what's going on.
|
||||
|
||||
The comma operator allows to evaluate several expressions, dividing them with a comma `','`. Each of them is evaluated, but result of only the last one is returned.
|
||||
|
||||
|
@ -415,17 +415,23 @@ alert( a ); // 7 (the result of 3+4)
|
|||
|
||||
Here, the first expression `1+2` is evaluated, and it's result is thrown away, then `3+4` is evaluated and returned as the result.
|
||||
|
||||
```smart header="Comma has a very low precedence"
|
||||
Please note that the comma operator has very low precedence, lower than `=`, so parentheses are important in the example above.
|
||||
|
||||
Without them: `a=1+2,3+4` evaluates `+` first, summing the numbers into `a=3,7`, then the assignment operator `=` assigns `a=3`, and then the number after the comma `7` is not processed anyhow, so it's ignored.
|
||||
```
|
||||
|
||||
Why do we need such an operator which throws away everything except the last part?
|
||||
|
||||
Usually it is used in more complex constructs to put several actions in one line.
|
||||
Sometimes people use it in more complex constructs to put several actions in one line.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
// three operations in one line
|
||||
for (*!*a = 1, b = 3, c = a*b*/!*; a < 10; a++) {
|
||||
for (*!*a = 1, b = 3, c = a * b*/!*; a < 10; a++) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Such tricks are used in many JavaScript frameworks, that's why we mention about them. But usually they don't benefit to code readability, so take care.
|
||||
Such tricks are used in many JavaScript frameworks, that's why we mention about them. But usually they don't improve the code readability, so we should think well before writing like that.
|
||||
|
|
|
@ -5,7 +5,7 @@ Many comparison operators we know from maths:
|
|||
- Greater/less than: <code>a > b</code>, <code>a < b</code>.
|
||||
- Greater/less than or equals: <code>a >= b</code>, <code>a <= b</code>.
|
||||
- Equality check is written as `a == b` (please note the double equation sign `'='`. A single symbol `a = b` would mean an assignment).
|
||||
- Not equals. In maths the sign is <code>≠</code>, in JavaScript we use an assignment with an exclamation before it: <code>a != b</code>.
|
||||
- Not equals. In maths the notation is <code>≠</code>, in JavaScript it's written as an assignment with an exclamation sign before it: <code>a != b</code>.
|
||||
|
||||
[cut]
|
||||
|
||||
|
@ -24,7 +24,7 @@ alert( 2 == 1 ); // false (wrong)
|
|||
alert( 2 != 1 ); // true (correct)
|
||||
```
|
||||
|
||||
A result of a comparison can be assigned to a variable, just like any value:
|
||||
A comparison result can be assigned to a variable, just like any value:
|
||||
|
||||
```js run
|
||||
let result = 5 > 4; // assign the result of the comparison
|
||||
|
@ -48,7 +48,7 @@ alert( 'Bee' > 'Be' ); // true
|
|||
The algorithm to compare two strings is simple:
|
||||
|
||||
1. Compare first characters of both strings.
|
||||
2. If the first one is greater(or less), then the first string is greater(or less) than the second and we're done.
|
||||
2. If the first one is greater(or less), then the first string is greater(or less) than the second. We're done.
|
||||
3. Otherwise if first characters are equal, compare the second characters the same way.
|
||||
4. Repeat until the end of any string.
|
||||
5. If both strings ended simultaneously, then they are equal. Otherwise the longer string is greater.
|
||||
|
@ -120,7 +120,7 @@ The same thing with an empty string:
|
|||
alert( '' == false ); // true
|
||||
```
|
||||
|
||||
That's the natural consequence of what we've seen before. Operands of different types are converted to a number. An empty string, just like `false`, becomes a zero.
|
||||
That's because operands of different types are converted to a number by the assignment operator `=`. An empty string, just like `false`, becomes a zero.
|
||||
|
||||
What to do if we'd like to differentiate `0` from `false`?
|
||||
|
||||
|
@ -136,11 +136,11 @@ 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 more obvious what's going on.
|
||||
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.
|
||||
|
||||
## Comparison with null and undefined
|
||||
|
||||
Let's see more corner cases.
|
||||
Let's see more edge cases.
|
||||
|
||||
There's a non-intuitive behavior when `null` or `undefined` is compared with other values.
|
||||
|
||||
|
@ -148,13 +148,21 @@ There's a non-intuitive behavior when `null` or `undefined` is compared with oth
|
|||
For a strict equality check `===`
|
||||
: These values are different, because each of them belong to a separate type of it's own.
|
||||
|
||||
For a non-strict check `null == undefined`
|
||||
```js run
|
||||
alert( null === undefined ); // false
|
||||
```
|
||||
|
||||
For a non-strict check `==`
|
||||
: There's a special rule. These two are a "sweet couple": they equal each other (in the sense of `==`), but no any other value.
|
||||
|
||||
For maths and evaluation of other comparisons `< > <= >=`
|
||||
```js run
|
||||
alert( null == undefined ); // true
|
||||
```
|
||||
|
||||
For maths and other comparisons `< > <= >=`
|
||||
: Values `null/undefined` are converted to a number: `null` becomes `0`, while `undefined` becomes `NaN`.
|
||||
|
||||
Now let's see funny things that happen when we apply those rules. And, what's more important, how do not fall into a trap with unobvious language features.
|
||||
Now let's see funny things that happen when we apply those rules. And, what's more important, how do not fall into a trap with these features.
|
||||
|
||||
### Strange result: null vs 0
|
||||
|
||||
|
@ -195,7 +203,7 @@ Why did we observe these examples? Should we remember these pecularities all the
|
|||
|
||||
Just treat any comparison with `undefined/null` except the strict equality `===` with an exceptional care.
|
||||
|
||||
Don't use comparisons `>= > < <=` with a variable which may be `null/undefined`, unless you are really sure what you're doing. If a variable can have such values, then check it separately.
|
||||
Don't use comparisons `>= > < <=` with a variable which may be `null/undefined`, unless you are really sure what you're doing. If a variable can have such values, then check for them separately.
|
||||
|
||||
## Summary
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ JavaScript-code:
|
|||
|
||||
```js demo run
|
||||
let name = prompt("What is your name?", "");
|
||||
alert( name );
|
||||
alert(name);
|
||||
```
|
||||
|
||||
The full page:
|
||||
|
@ -10,18 +10,15 @@ The full page:
|
|||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
let name = prompt("What is your name?", "");
|
||||
alert( name );
|
||||
alert(name);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ importance: 4
|
|||
|
||||
# A simple page
|
||||
|
||||
Create a web-page which asks for a name and outputs it.
|
||||
Create a web-page that asks for a name and outputs it.
|
||||
|
||||
[demo]
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ For example:
|
|||
alert("Hello");
|
||||
```
|
||||
|
||||
The small 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 he deals with the window. In this case -- until he presses "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 he deals with the window. In this case -- until he presses "OK".
|
||||
|
||||
## prompt
|
||||
|
||||
|
@ -34,19 +34,19 @@ Function `prompt` accepts two arguments:
|
|||
result = prompt(title[, default]);
|
||||
```
|
||||
|
||||
It shows a modal window with a field for text and buttons OK/CANCEL.
|
||||
It shows a modal window with a text message, an input field for the visitor and buttons OK/CANCEL.
|
||||
|
||||
`title`
|
||||
: Is a modal window title
|
||||
: The text to show to the visitor.
|
||||
|
||||
`default`
|
||||
: An optional second parameter, the initial value for the text field.
|
||||
: An optional second parameter, the initial value for the input field.
|
||||
|
||||
The visitor may type something in the field and press OK. Or he can cancel the input by pressing a CANCEL button or hitting the `key:Esc` key.
|
||||
The visitor may type something in the prompt input field and press OK. Or he can cancel the input by pressing a CANCEL button or hitting the `key:Esc` key.
|
||||
|
||||
The call to `prompt` returns the text from the field or `null` if the input is canceled.
|
||||
The call to `prompt` returns the text from the field or `null` if the input was canceled.
|
||||
|
||||
As with `alert`, the `prompt` window is modal.
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
let age = prompt('How old are you?', 100);
|
||||
|
@ -92,6 +92,8 @@ alert( isBoss ); // true is OK is pressed
|
|||
|
||||
## Summary
|
||||
|
||||
We covered 3 browser-specific functions to interact with the visitor:
|
||||
|
||||
`alert`
|
||||
: shows a message.
|
||||
|
||||
|
@ -101,6 +103,8 @@ alert( isBoss ); // true is OK is pressed
|
|||
`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.
|
||||
|
||||
There are two limitations shared by all the methods above:
|
||||
|
||||
1. The exact location of the modal window is determined by the browser. Usually it's in the center.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
@ -10,7 +10,7 @@
|
|||
if (value == 'ECMAScript') {
|
||||
alert('Right!');
|
||||
} else {
|
||||
alert("Didn't know? ECMAScript!");
|
||||
alert("You don't know? ECMAScript!");
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 56 KiB |
|
@ -1,7 +1,7 @@
|
|||
|
||||
|
||||
```js run demo
|
||||
let userName = prompt('Who's there?', '');
|
||||
let userName = prompt("Who's there?", '');
|
||||
|
||||
if (userName == 'Admin') {
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ importance: 5
|
|||
|
||||
Rewrite `if..else` using multiple ternary operators `'?'`.
|
||||
|
||||
For readability, it's recommended to split the code span over lines.
|
||||
For readability, it's recommended to split the code into multiple lines.
|
||||
|
||||
```js
|
||||
let message;
|
||||
|
@ -21,4 +21,3 @@ if (login == 'Employee') {
|
|||
message = '';
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Conditional operators: if, '?'
|
||||
|
||||
Sometimes we need to perform different actions basing on a condition.
|
||||
Sometimes we need to perform different actions basing on a condition.
|
||||
|
||||
There's an `if` operator for that and also the "question mark" operator: `"?"` for conditional evaluation.
|
||||
|
||||
|
@ -35,9 +35,9 @@ It is recommended to use figure brackets every time with `if`, even if there's o
|
|||
|
||||
## Boolean conversion
|
||||
|
||||
The `if (…)` operator evaluates the condition in brackets and converts it to boolean type.
|
||||
The `if (…)` operator evaluates the expression in parentheses and converts it to the boolean type.
|
||||
|
||||
Let's recall the rules. In the logical context:
|
||||
Let's recall the conversion rules:
|
||||
|
||||
- A number `0`, an empty string `""`, `null`, `undefined` and `NaN` are `false`,
|
||||
- Other values -- `true`.
|
||||
|
@ -58,7 +58,7 @@ if (1) { // 1 is truthy
|
|||
}
|
||||
```
|
||||
|
||||
We can also pass a pre-evaluated logical value to `if`, like here:
|
||||
We can also pass a pre-evaluated boolean value to `if`, like here:
|
||||
|
||||
```js
|
||||
let cond = (year == 2015); // equality evaluates to true or false
|
||||
|
@ -101,7 +101,9 @@ if (year < 2015) {
|
|||
}
|
||||
```
|
||||
|
||||
In the code above JavaScript first checks `year < 2015`, if it is falsy then goes to the next condition `year > 2015`. Any number of `else if` may follow with an optional last `else`.
|
||||
In the code above JavaScript first checks `year < 2015`, if it is falsy then goes to the next condition `year > 2015`, and otherwise shows the last `alert`.
|
||||
|
||||
There can be more `else if` blocks. The ending `else` is optional.
|
||||
|
||||
## Ternary operator '?'
|
||||
|
||||
|
@ -110,21 +112,21 @@ Sometimes we need to assign a variable depending on a condition.
|
|||
For instance:
|
||||
|
||||
```js run no-beautify
|
||||
let hasAccess;
|
||||
let accessAllowed;
|
||||
let age = prompt('How old are you?', '');
|
||||
|
||||
*!*
|
||||
if (age > 18) {
|
||||
hasAccess = true;
|
||||
accessAllowed = true;
|
||||
} else {
|
||||
hasAccess = false;
|
||||
accessAllowed = false;
|
||||
}
|
||||
*/!*
|
||||
|
||||
alert(hasAccess);
|
||||
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 allows to 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.
|
||||
|
||||
|
@ -138,24 +140,25 @@ The `condition` is evaluated, if it's truthy then `value1` is returned, otherwis
|
|||
For example:
|
||||
|
||||
```js
|
||||
let hasAccess = (age > 18) ? true : false;
|
||||
let accessAllowed = (age > 18) ? true : false;
|
||||
```
|
||||
|
||||
We can omit brackets around `age > 14`, because the question mark operator has a low precedence. It executes after comparisons, so:
|
||||
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:
|
||||
|
||||
```js
|
||||
// the same
|
||||
let hasAccess = age > 18 ? true : false;
|
||||
// the comparison operator "age > 18" executes first anyway
|
||||
// (no need to wrap it into parentheses)
|
||||
let accessAllowed = age > 18 ? true : false;
|
||||
```
|
||||
|
||||
...But brackets make the code more readable. So it's recommended to put them.
|
||||
...But parentheses make the code more readable. So it's recommended to put them.
|
||||
|
||||
````smart
|
||||
In the described case it is possible to evade the question mark operator, because the comparison by itself returns `true/false`:
|
||||
In the example above it's possible to evade the question mark operator, because the comparison by itself returns `true/false`:
|
||||
|
||||
```js
|
||||
// the same
|
||||
let hasAccess = age > 18;
|
||||
let accessAllowed = age > 18;
|
||||
```
|
||||
````
|
||||
|
||||
|
@ -175,12 +178,12 @@ let message = (age < 3) ? 'Hi, baby!' :
|
|||
alert( message );
|
||||
```
|
||||
|
||||
It may be difficult at first to grasp what's going on. But looking more carefully we note that it's just an ordinary sequence of tests.
|
||||
It may be difficult at first to grasp what's going on. But after a closer look we can see that it's just an ordinary sequence of tests.
|
||||
|
||||
1. The first question mark checks for `age < 3`.
|
||||
2. If true -- returns `'Hi, baby!'`, otherwise -- goes to the right side of the colon `":"` and checks for `age < 18`.
|
||||
3. If that's true -- returns `'Hello!'`, otherwise checks for `age < 100` and returns `'Greetings!'` if that is so...
|
||||
4. At last, if all checks are falsy, the `message` becomes `'What an unusual age!'`.
|
||||
1. The first question mark checks whether `age < 3`.
|
||||
2. If true -- returns `'Hi, baby!'`, otherwise -- goes after the colon `":"` and checks for `age < 18`.
|
||||
3. If that's true -- returns `'Hello!'`, otherwise -- goes after the next colon `":"` and checks for `age < 100`.
|
||||
4. If that's true -- returns `'Greetings!'`, otherwise -- goes after the last colon `":"` and returns `'What an unusual age!'`.
|
||||
|
||||
The same logic using `if..else`:
|
||||
|
||||
|
@ -211,7 +214,7 @@ let company = prompt('Which company created JavaScript?', '');
|
|||
|
||||
Depending on the condition `company == 'Netscape'`, either the first or the second part after `"?"` gets executed and shows the alert.
|
||||
|
||||
We don't assign a result to a variable here, cause the `alert` doesn't return anything anyway, our purpose is only to execute it.
|
||||
We don't assign a result to a variable here, the idea is to execute different code depending on the condition.
|
||||
|
||||
**It is not recommended to use the question mark operator in this way.**
|
||||
|
||||
|
@ -234,4 +237,3 @@ if (company == 'Netscape') {
|
|||
Our eyes scan the code vertically. The constructs which span several lines are easier to understand than a long horizontal instruction set.
|
||||
|
||||
The idea of a question mark `'?'` is to return one or another value depending on the condition. Please use it for exactly that. There's `if` to execute different branches of the code.
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ alert( alert(1) || 2 || alert(3) );
|
|||
The call to `alert` does not return a value. Or, in other words, it returns `undefined`.
|
||||
|
||||
1. The first OR `||` evaluates it's left operand `alert(1)`. That shows the first message with `1`.
|
||||
2. The `alert` returns `undefined`, so OR goes on to the second operand in it's search of a truthy value.
|
||||
2. The `alert` returns `undefined`, so OR goes on to the second operand searching for a truthy value.
|
||||
3. The second operand `2` is truthy, so the execution is halted, `2` is returned and then shown by the outer alert.
|
||||
|
||||
There will be no `3`, because the evaluation does not reach `alert(3)`.
|
||||
|
|
|
@ -18,9 +18,9 @@ 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 JavaScript the operator is a little bit more tricky and powerful. But first let's see what happens with logical values.
|
||||
In JavaScript the operator is a little bit more tricky and powerful. But first let's see what happens with boolean values.
|
||||
|
||||
A table of possible logical combinations:
|
||||
There are four possible logical combinations:
|
||||
|
||||
```js run
|
||||
alert( true || true ); // true
|
||||
|
@ -41,7 +41,7 @@ if (1 || 0) { // works just like if( true || false )
|
|||
}
|
||||
```
|
||||
|
||||
Most of time, OR `||` is used in the `if` expression to test if *any* of given conditions is correct.
|
||||
Most of time, OR `||` is used in `if` to test if *any* of given conditions is correct.
|
||||
|
||||
For example:
|
||||
|
||||
|
@ -81,31 +81,31 @@ result = value1 || value2 || value3;
|
|||
The OR `"||"` operator is doing the following:
|
||||
|
||||
- Evalutes operands from left to right.
|
||||
- For each value converts it to boolean and stops immediately returning it if it's true.
|
||||
- The value is returned in it's original form, without the conversion.
|
||||
- For each value -- converts it to boolean. If it's true then stops and returns that value.
|
||||
- If operands finished, returns the last value.
|
||||
|
||||
In other words, it returns the first truthy value or the last one if no such value found.
|
||||
A value is returned in it's 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.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
alert( 1 || 0 ); // 1 (is truthy)
|
||||
alert( 1 || 0 ); // 1 (1 is truthy)
|
||||
alert( true || 'no matter what' ); // (true is truthy)
|
||||
|
||||
alert( null || 1 ); // 1 (1 is the first truthy)
|
||||
alert( null || 0 || 1 ); // 1 (the first truthy)
|
||||
alert( null || 1 ); // 1 (1 is the first truthy value)
|
||||
alert( null || 0 || 1 ); // 1 (the first truthy value)
|
||||
alert( undefined || null || 0 ); // 0 (all falsy, returns the last value)
|
||||
```
|
||||
|
||||
This logic does not contradict to what was spoken above. If you check this behavior with the boolean table, you see that it still works the same.
|
||||
|
||||
But there leads to some interesting usages compared to a "pure, classical, boolean-only OR".
|
||||
That leads to some interesting usages compared to a "pure, classical, boolean-only OR".
|
||||
|
||||
1. **Getting the first truthy value from the list of variables or expressions.**
|
||||
|
||||
Imagine we have several variables, which can either contain the data or be `null/undefined`. And we need to choose the first one with data.
|
||||
|
||||
Using OR `||` for that:
|
||||
We can use OR `||` for that:
|
||||
|
||||
```js run
|
||||
let currentUser = null;
|
||||
|
@ -135,7 +135,7 @@ But there leads to some interesting usages compared to a "pure, classical, boole
|
|||
alert(x); // undefined, because (x = 1) not evaluated
|
||||
```
|
||||
|
||||
...And if the first argument were `false`, then `OR` would goes on and evaluate the second one thus running the assignment:
|
||||
...And if the first argument is `false`, then `OR` goes on and evaluates the second one thus running the assignment:
|
||||
|
||||
```js run no-beautify
|
||||
let x;
|
||||
|
@ -147,9 +147,9 @@ But there leads to some interesting usages compared to a "pure, classical, boole
|
|||
|
||||
An assignment is a simple case, other side effects can be involved.
|
||||
|
||||
As we can see, such use case is a "shorter way to do `if`". The first operand is converted to boolean and if it's false then the second one is evaluated.
|
||||
As we can see, such use case is a "shorter way to do `if`". The first operand is converted to boolean and if it's false then the second one is evaluated.
|
||||
|
||||
Most of time it's better to use `if` for that for code clarity.
|
||||
Most of time it's better to use a "regular" `if` to keep the code easy to understand, but sometimes that can be handy.
|
||||
|
||||
## && (AND)
|
||||
|
||||
|
@ -159,7 +159,7 @@ The AND operator is represented with two ampersands `&&`:
|
|||
result = a && b;
|
||||
```
|
||||
|
||||
In classic 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
|
||||
|
@ -179,7 +179,7 @@ if (hour == 12 && minute == 30) {
|
|||
}
|
||||
```
|
||||
|
||||
Just as for OR, any value is allowed as an operand of AND and gets converted to a boolean in the process:
|
||||
Just as for OR, any value is allowed as an operand of AND:
|
||||
|
||||
```js run
|
||||
if (1 && 0) { // evaluated as true && false
|
||||
|
@ -199,10 +199,10 @@ result = value1 && value2 && value3;
|
|||
The AND `"&&"` operator is doing the following:
|
||||
|
||||
- Evalutes operands from left to right.
|
||||
- For each value converts it to a boolean. If the result is `false`, stops and returns it without conversion.
|
||||
- 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.
|
||||
|
||||
In other words, AND returns the first falsy value or the last one if none found.
|
||||
In other words, AND returns the first falsy value or the last value if none 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,
|
||||
// && returns the second one.
|
||||
// AND returns the second one:
|
||||
alert( 1 && 0 ); // 0
|
||||
alert( 1 && 5 ); // 5
|
||||
|
||||
// now the first operand is falsy,
|
||||
// it is returned, and the second one is ignored
|
||||
// if the first operand is falsy,
|
||||
// AND returns it, and the second one is ignored
|
||||
alert( null && 5 ); // null
|
||||
alert( 0 && "no matter what" ); // 0
|
||||
```
|
||||
|
@ -226,7 +226,7 @@ We can also pass several values in a row. See how the first falsy one is returne
|
|||
alert( 1 && 2 && null && 3 ); // null
|
||||
```
|
||||
|
||||
...And now when all of them are truthy:
|
||||
When all values are truthy, the last value is returned:
|
||||
|
||||
```js run
|
||||
alert( 1 && 2 && 3 ); // 3, the last one
|
||||
|
@ -272,7 +272,7 @@ So it is recommended to use every construct for it's purpose. Use `if` if we wan
|
|||
|
||||
The boolean NOT operator is represented with an exclamation sign `"!"`.
|
||||
|
||||
The syntax is one of the simplest:
|
||||
The syntax is pretty simple:
|
||||
|
||||
```js
|
||||
result = !value;
|
||||
|
@ -290,14 +290,14 @@ alert( !true ); // false
|
|||
alert( !0 ); // true
|
||||
```
|
||||
|
||||
A double NOT is sometimes used for converting a value to boolean type:
|
||||
A double NOT `!!` is sometimes used for converting a value to boolean type:
|
||||
|
||||
```js run
|
||||
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, so 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:
|
||||
|
||||
|
@ -305,4 +305,3 @@ There's a little more verbose to do the same -- a built-in `Boolean` function:
|
|||
alert( Boolean("non-empty string") ); // true
|
||||
alert( Boolean(null) ); // false
|
||||
```
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ while (i) {
|
|||
|
||||
Every loop iteration decreases `i` by `1`. The check `while(i)` stops the loop when `i = 0`.
|
||||
|
||||
Hence, the steps of the loop make the following sequence ("loop unrolled"):
|
||||
Hence, the steps of the loop form the following sequence ("loop unrolled"):
|
||||
|
||||
```js
|
||||
let i = 3;
|
||||
|
@ -23,4 +23,3 @@ alert(i--) // shows 1, decreases i to 0
|
|||
|
||||
// done, while(i) check stops the loop
|
||||
```
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ importance: 3
|
|||
|
||||
# Last loop value
|
||||
|
||||
What is be the last value alerted by this code? Why?
|
||||
What is the last value alerted by this code? Why?
|
||||
|
||||
```js
|
||||
let i = 3;
|
||||
|
@ -13,4 +13,3 @@ while (i) {
|
|||
alert( i-- );
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ The task demonstrates how postfix/prefix forms can lead to different results whe
|
|||
|
||||
Then follow `2,3,4…` -- the values show up one after another. The comparison always uses the incremented value, because `++` is before the variable.
|
||||
|
||||
Finally, `i=4` is incremented to `5`, the comparison `while(5 < 5)` fails and the loop stops. So `5` is not shown.
|
||||
Finally, `i=4` is incremented to `5`, the comparison `while(5 < 5)` fails, and the loop stops. So `5` is not shown.
|
||||
2. **From 1 to 5**
|
||||
|
||||
```js run
|
||||
|
@ -28,4 +28,3 @@ The task demonstrates how postfix/prefix forms can lead to different results whe
|
|||
Let's stop on `i=4`. The prefix form `++i` would increment it and use `5` in the comparison. But here we have the postfix form `i++`. So it increments `i` to `5`, but returns the old value. Hence the comparison is actually `while(4 < 5)` -- true, and the control goes on to `alert`.
|
||||
|
||||
The value `i=5` is the last one, because on the next step `while(5 < 5)` is false.
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ importance: 4
|
|||
|
||||
# Which values shows the while?
|
||||
|
||||
For every loop, scribe down which values it shows, in your opinion.
|
||||
For every loop, write down which values it shows, in your opinion. And then compare with the answer.
|
||||
|
||||
And then compare with the answer.
|
||||
Both loops `alert` same values or not?
|
||||
|
||||
1. The prefix form `++i`:
|
||||
|
||||
|
@ -20,4 +20,3 @@ And then compare with the answer.
|
|||
let i = 0;
|
||||
while (i++ < 5) alert( i );
|
||||
```
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ for (let i = 0; i < 5; i++) alert( i );
|
|||
|
||||
That can be easily deducted from the algorithm of `for`:
|
||||
|
||||
1. Execute once `i=0` before everything.
|
||||
1. Execute once `i=0` before everything (begin).
|
||||
2. Check the condition `i<5`
|
||||
3. If `true` -- execute the loop body `alert(i)`, and then `i++`
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ importance: 4
|
|||
|
||||
# Which values get shown by the "for" loop?
|
||||
|
||||
For each loop scribe down which values it is going to show.
|
||||
For each loop write down which values it is going to show. Then compare with the answer.
|
||||
|
||||
Then compare with the answer.
|
||||
Both loops `alert` same values or not?
|
||||
|
||||
1. The postfix form:
|
||||
|
||||
|
@ -18,4 +18,3 @@ Then compare with the answer.
|
|||
```js
|
||||
for (let i = 0; i < 5; ++i) alert( i );
|
||||
```
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@ do {
|
|||
The loop `do..while` repeats while both checks are truthy:
|
||||
|
||||
1. The check for `num <= 100` -- that is, the entered value is still not greater than `100`.
|
||||
2. The check for a truthiness of `num` checks that `num != null` and `num != ""` simultaneously.
|
||||
2. The check `&& num` is false when `num` is `null` or a empty strig. Then the `while` loop stops too.
|
||||
|
||||
P.S. By the way, if `num` is `null` then `num <= 100` would return `false`, not `true`!
|
||||
P.S. If `num` is `null` then `num <= 100` is `false`, so without the 2nd check the loop wouldn't stop if the user clicks CANCEL. Both checks are required.
|
||||
|
|
|
@ -4,11 +4,10 @@ importance: 5
|
|||
|
||||
# Repeat until the input is incorrect
|
||||
|
||||
Write a loop which prompts for a number greater than `100`. If the visitor enters another number -- ask him to repeat the input, and so on.
|
||||
Write a loop which prompts for a number greater than `100`. If the visitor enters another number -- ask him to input again.
|
||||
|
||||
The loop must ask for a number until either the visitor enters a number greater than `100` or cancels the input/enters an empty line.
|
||||
|
||||
Here we can assume that the visitor only inputs numbers. There's no need to implement the special handling for a non-numeric input in this task.
|
||||
Here we can assume that the visitor only inputs numbers. There's no need to implement a special handling for a non-numeric input in this task.
|
||||
|
||||
[demo]
|
||||
|
||||
|
|
|
@ -13,8 +13,10 @@ For each i in the interval {
|
|||
The code using a label:
|
||||
|
||||
```js run
|
||||
let n = 10;
|
||||
|
||||
nextPrime:
|
||||
for (let i = 2; i <= 10; i++) { // for each i...
|
||||
for (let i = 2; i <= n; i++) { // for each i...
|
||||
|
||||
for (let j = 2; j < i; j++) { // look for a divisor..
|
||||
if (i % j == 0) continue nextPrime; // not a prime, go next i
|
||||
|
@ -24,5 +26,4 @@ for (let i = 2; i <= 10; i++) { // for each i...
|
|||
}
|
||||
```
|
||||
|
||||
Surely, there's a lot of space to opimize it. Like, we could look for the divisors from `2` to square root of `i`. But anyway, if we want to be really efficient for large intervals, we need change the approach and rely heavily on advanced maths and algorithms like [Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve) etc.
|
||||
|
||||
There's a lot of space to opimize it. For instance, we could look for the divisors from `2` to square root of `i`. But anyway, if we want to be really efficient for large intervals, we need change the approach and rely on advanced maths and complex algorithms like [Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve) etc.
|
||||
|
|
|
@ -4,15 +4,14 @@ importance: 3
|
|||
|
||||
# Output prime numbers
|
||||
|
||||
An integer number greater than `1` is called a [prime](https://en.wikipedia.org/wiki/Prime_number) if it cannot be not divided without a remainder by anything except `1` and itself.
|
||||
An integer number greater than `1` is called a [prime](https://en.wikipedia.org/wiki/Prime_number) if it cannot be divided without a remainder by anything except `1` and itself.
|
||||
|
||||
In other words, `n>1` is a prime if the result of it's division by anything except `1` and `n` is not integer.
|
||||
In other words, `n>1` is a prime if it can't be evenly divided by anything except `1` and `n`.
|
||||
|
||||
For example, `5` is a prime, because it cannot be divided without a remainder by `2`, `3` and `4`.
|
||||
|
||||
**Write the code which outputs prime numbers in the interval from `2` to `10`.**
|
||||
**Write the code which outputs prime numbers in the interval from `2` to `n`.**
|
||||
|
||||
The result will be `2,3,5,7`.
|
||||
|
||||
P.S. The code should be easily modifiable for other intervals.
|
||||
For `n=10` the result will be `2,3,5,7`.
|
||||
|
||||
P.S. The code should work for any `n`, not be hard-tuned for any fixed value.
|
||||
|
|
|
@ -14,7 +14,8 @@ The `while` loop has the following syntax:
|
|||
|
||||
```js
|
||||
while (condition) {
|
||||
// code ("loop body")
|
||||
// code
|
||||
// so-called "loop body"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -30,18 +31,18 @@ while (i < 3) { // shows 0, then 1, then 2
|
|||
}
|
||||
```
|
||||
|
||||
There's a special term *iteration* for each loop run. The loop in the example above makes 3 iterations.
|
||||
A single execution of the loop body is called *an iteration*. The loop in the example above makes 3 iterations.
|
||||
|
||||
If there were no `i++` in the example above, the loop would repeat (in theory) forever, eating 100% CPU. In practice, the browser would show a message about a "hanging" script and let the user stop it.
|
||||
If there were no `i++` in the example above, the loop would repeat (in theory) forever. In practice, the browser provides ways to stop such loops, and for server-side JavaScript we can kill the process.
|
||||
|
||||
The `while` converts `condition` to a logical value. It can be any expression, not just a comparison.
|
||||
Any expression or a variable can be a loop condition, not just a comparison. They are evaluated and converted to boolean by `while`.
|
||||
|
||||
For instance, the shorter way to write `while (i!=0)` could be `while (i)`:
|
||||
|
||||
```js run
|
||||
let i = 3;
|
||||
*!*
|
||||
while (i) { // when i becomes 0, the condition is falsy and the loop stops
|
||||
while (i) { // when i becomes 0, the condition becomes falsy, and the loop stops
|
||||
*/!*
|
||||
alert( i );
|
||||
i--;
|
||||
|
@ -69,7 +70,7 @@ do {
|
|||
} while (condition);
|
||||
```
|
||||
|
||||
The loop will first execute the body and then check the condition.
|
||||
The loop will first execute the body, then check the condition, and while it's truthy -- execute it again and again.
|
||||
|
||||
For example:
|
||||
|
||||
|
@ -81,11 +82,11 @@ do {
|
|||
} while (i < 3);
|
||||
```
|
||||
|
||||
This form of syntax is rarely used, because the ordinary `while` is more obvious. We don't need to scroll down the code looking for the condition.
|
||||
This form of syntax is rarely used. Usually, if there's no special reason, the other form is preferred: `while(…) {…}`.
|
||||
|
||||
## The "for" loop
|
||||
|
||||
The `for` loop is actually the most often used one.
|
||||
The `for` loop is the most often used one.
|
||||
|
||||
It looks like this:
|
||||
|
||||
|
@ -95,7 +96,7 @@ for (begin; condition; step) {
|
|||
}
|
||||
```
|
||||
|
||||
Let's see these parts in an example. For instance, the loop below runs `alert(i)` for `i` from `0` up to (but not including) `3`:
|
||||
Let's learn the meaning of these parts by example. The loop below runs `alert(i)` for `i` from `0` up to (but not including) `3`:
|
||||
|
||||
```js run
|
||||
for (let i = 0; i < 3; i++) { // shows 0, then 1, then 2
|
||||
|
@ -103,42 +104,45 @@ for (let i = 0; i < 3; i++) { // shows 0, then 1, then 2
|
|||
}
|
||||
```
|
||||
|
||||
Let's examine the last example part-by-part:
|
||||
Let's examine the `for` statement part by part:
|
||||
|
||||
| part | | |
|
||||
|-------|----------|----------------------------------------------------------------------------|
|
||||
| begin | `i=0` | Executes once upon entering the loop. |
|
||||
| condition | `i<3`| Checked before every loop iteration, if fails the loop stops. |
|
||||
| body | `alert(i)`| Runs again and again while the condition is truthy |
|
||||
| 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 |
|
||||
|
||||
|
||||
The general loop algorithm works like this:
|
||||
```
|
||||
Begin
|
||||
Run begin
|
||||
→ (if condition → run body and run step)
|
||||
→ ... repeat while the condition is truthy
|
||||
→ (if condition → run body and run step)
|
||||
→ (if condition → run body and run step)
|
||||
→ ...
|
||||
```
|
||||
|
||||
If you are new to loops, then maybe it would help if you go back to the example and reproduce how it runs step-by-step on a piece of paper.
|
||||
|
||||
That's what exactly happens in our case:
|
||||
Here's what exactly happens in our case:
|
||||
|
||||
```js
|
||||
// for (let i = 0; i < 3; i++) alert(i)
|
||||
|
||||
// begin
|
||||
// run begin
|
||||
let i = 0
|
||||
// if condition → run body and run step
|
||||
if (i < 3) { alert(i); i++ }
|
||||
// repeat while the condition is truthy
|
||||
// if condition → run body and run step
|
||||
if (i < 3) { alert(i); i++ }
|
||||
// if condition → run body and run step
|
||||
if (i < 3) { alert(i); i++ }
|
||||
// ...finish, because now i == 3
|
||||
```
|
||||
|
||||
````smart header="Inline variable declaration"
|
||||
Here the "counter" variable `i` is declared right in the 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 variable is visible only inside the loop.
|
||||
|
||||
```js run
|
||||
for (*!*let*/!* i = 0; i < 3; i++) {
|
||||
|
@ -147,13 +151,15 @@ for (*!*let*/!* i = 0; i < 3; i++) {
|
|||
alert(i); // error, no such variable
|
||||
```
|
||||
|
||||
We can use an existing variable as well:
|
||||
Instead of defining a variable, we can use an existing one:
|
||||
|
||||
```js run
|
||||
let i = 0;
|
||||
|
||||
for (i = 0; i < 3; i++) { // use an existing variable
|
||||
alert(i); // 0, 1, 2
|
||||
}
|
||||
|
||||
alert(i); // 3, visible, because declared outside of the loop
|
||||
```
|
||||
|
||||
|
@ -162,14 +168,14 @@ alert(i); // 3, visible, because declared outside of the loop
|
|||
|
||||
### Skipping parts
|
||||
|
||||
Any part of the `for` can be skipped.
|
||||
Any part of `for` can be skipped.
|
||||
|
||||
For example, we can omit `begin` if we don't need to do anything at the loop start.
|
||||
|
||||
Like here:
|
||||
|
||||
```js run
|
||||
let i = 0; // imagine we have i already declared and assigned
|
||||
let i = 0; // we have i already declared and assigned
|
||||
|
||||
for (; i < 3; i++) { // no need for "begin"
|
||||
alert( i ); // 0, 1, 2
|
||||
|
@ -223,7 +229,7 @@ while (true) {
|
|||
alert( 'Sum: ' + sum );
|
||||
```
|
||||
|
||||
The `break` directive is activated in the line `(*)` if the user enters an empty line or cancels the input. It stops the loop immediately, passing the control to the first line after it's loop. Namely, `alert`.
|
||||
The `break` directive is activated in the line `(*)` if the user enters an empty line or cancels the input. It stops the loop immediately, passing the control to the first line after the loop. Namely, `alert`.
|
||||
|
||||
The combination: "infinite loop + `break` as needed" is great for situations when the condition must be checked not in beginning/end of the loop, but in the middle. Or even in several places of the body.
|
||||
|
||||
|
@ -248,7 +254,7 @@ for (let i = 0; i < 10; i++) {
|
|||
For even values of `i` the `continue` directive stops body execution, passing the control to the next iteration of `for` (with the next number). So the `alert` is only called for odd values.
|
||||
|
||||
````smart header="The directive `continue` helps to decrease nesting level"
|
||||
A loop for odd-only values could look like this:
|
||||
A loop that shows odd values could look like this:
|
||||
|
||||
```js
|
||||
for (let i = 0; i < 10; i++) {
|
||||
|
@ -268,7 +274,7 @@ But as a side-effect we got one more figure brackets nesting level. If the code
|
|||
````warn header="No `break/continue` to the right side of '?'"
|
||||
Please note that syntax constructs that are not expressions cannot be used in `'?'`. In particular, directives `break/continue` are disallowed there.
|
||||
|
||||
For example, if one we take this code:
|
||||
For example, if we take this code:
|
||||
|
||||
```js
|
||||
if (i > 5) {
|
||||
|
@ -295,7 +301,7 @@ That's just another reason not to use a 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` asking for values on coordinates `(i, j)` from `(0,0)` to `(3,3)`:
|
||||
For example, in the code below we loop over `i` and `j` prompting for coordinates `(i, j)` from `(0,0)` to `(3,3)`:
|
||||
|
||||
```js run no-beautify
|
||||
for (let i = 0; i < 3; i++) {
|
||||
|
@ -312,7 +318,7 @@ for (let i = 0; i < 3; i++) {
|
|||
alert('Done!');
|
||||
```
|
||||
|
||||
Let's say we need a way to stop the process. Like if we user decides to cancel the input.
|
||||
We need a way to stop the process if the user cancels the input.
|
||||
|
||||
The ordinary `break` after `input` would only break the inner loop. That's not sufficient. Labels come to the rescue.
|
||||
|
||||
|
@ -323,7 +329,7 @@ labelName: for(...) {
|
|||
}
|
||||
```
|
||||
|
||||
We can put the `labelName` after a break statement, and it will break out of the labelled loop.
|
||||
The `break <labelName>` statement in the loop breaks out to the label.
|
||||
|
||||
Like here:
|
||||
|
||||
|
@ -354,7 +360,7 @@ outer:
|
|||
for (let i = 0; i < 3; i++) { ... }
|
||||
```
|
||||
|
||||
The `continue` directive can also be used with a label. In this case the execution would jump onto the next iteration of the labelled loop.
|
||||
The `continue` directive can also be used with a label. In this case the execution jumps to the next iteration of the labelled loop.
|
||||
|
||||
````warn header="Labels are not a \"goto\""
|
||||
Labels do not allow to jump into an arbitrary place of code.
|
||||
|
@ -379,6 +385,6 @@ We covered 3 types of loops:
|
|||
|
||||
To make an "infinite" loop, usually the `while(true)` construct is used. Such a loop, just like any other, can be stopped with the `break` directive.
|
||||
|
||||
If we don't want to do anything more on this iteration and would like to forward on to the next one -- the `continue` directive does it.
|
||||
If we don't want to do anything on the current iteration and would like to forward to the next one -- the `continue` directive does it.
|
||||
|
||||
`Break/continue` support labels before the loop. A label is the only way for `break/continue` to escape the nesting and go to the outer loop.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
To be precise, the `if` must use a strict comparison `'==='`.
|
||||
To precisely match the functionality of `switch`, the `if` must use a strict comparison `'==='`.
|
||||
|
||||
In reality though, probably a simple `'=='` would do.
|
||||
For given strings though, a simple `'=='` works too.
|
||||
|
||||
```js no-beautify
|
||||
if(browser == 'Edge') {
|
||||
|
@ -17,4 +17,4 @@ if(browser == 'Edge') {
|
|||
|
||||
Please note: the construct `browser == 'Chrome' || browser == 'Firefox' …` is split into multiple lines for better readability.
|
||||
|
||||
But the `switch` is still neater and more descriptive.
|
||||
But the `switch` construct is still cleaner and more descriptive.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
The first two checks are a usual `case`. The third one is split into two cases:
|
||||
The first two checks turn into two `case`. The third check is split into two cases:
|
||||
|
||||
```js run
|
||||
let a = +prompt('a?', '');
|
||||
|
@ -24,4 +24,3 @@ switch (a) {
|
|||
Please note: the `break` at the bottom is not required. But we put it to make the code future-proof.
|
||||
|
||||
In the future, there is a chance that we'd want to add one more `case`, for example `case 4`. And if we forget to add a break before it, at the end of `case 3`, there will be an error. So that's a kind of self-insurance.
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ It gives a more descriptive way to compare a value with multiple variants.
|
|||
|
||||
## The syntax
|
||||
|
||||
The `switch` has one or more `case` blocks and an optional default.
|
||||
The `switch` has one or more `case` blocks and an optional default.
|
||||
|
||||
It looks like this:
|
||||
|
||||
|
@ -142,7 +142,7 @@ Now both `3` and `5` show the same message.
|
|||
|
||||
The ability to "group" cases a side-effect of how `switch/case` works without `break`. Here the execution of `case 3` starts from the line `(*)` and goes through `case 5`, because there's no `break`.
|
||||
|
||||
## The type matters
|
||||
## Type matters
|
||||
|
||||
Let's emphase that the equality check is always strict. The values must be of the same type to match.
|
||||
|
||||
|
@ -170,4 +170,3 @@ switch (arg) {
|
|||
1. For `0`, `1`, the first `alert` runs.
|
||||
2. For `2` the second `alert` runs.
|
||||
3. But for `3`, the result of the `prompt` is a string `"3"`, which is not strictly equal `===` to the number `3`. So we've got a dead code in `case 3`! The `default` variant will execite.
|
||||
|
||||
|
|
|
@ -14,4 +14,4 @@ function checkAge(age) {
|
|||
}
|
||||
```
|
||||
|
||||
Note that the brackets around `age > 18` are not required here. They exist for better readabilty.
|
||||
Note that the parentheses around `age > 18` are not required here. They exist for better readabilty.
|
||||
|
|
|
@ -16,4 +16,4 @@ Create a web-page that prompts for `x` and `n`, and then shows the result of `po
|
|||
|
||||
[demo]
|
||||
|
||||
P.S. In this task the function is allowed to support only natural values of `n`: integers up from `1`.
|
||||
P.S. In this task the function should support only natural values of `n`: integers up from `1`.
|
||||
|
|
|
@ -26,7 +26,7 @@ The `function` keyword goes first, then goes the *name of the function*, then a
|
|||
|
||||

|
||||
|
||||
Our new function can be called by it's name.
|
||||
Our new function can be called by its name: `showMessage()`.
|
||||
|
||||
For instance:
|
||||
|
||||
|
@ -43,7 +43,7 @@ showMessage();
|
|||
|
||||
The call `showMessage()` executes the code of the function. Here we will see the message two times.
|
||||
|
||||
This example clearly demonstrates one of the main purposes of the functions: to evade code duplication.
|
||||
This example clearly demonstrates one of the main purposes of functions: to evade code duplication.
|
||||
|
||||
If we ever need to change the message or the way it is shown -- it's enough to modify the code in one place: the function which outputs it.
|
||||
|
||||
|
@ -82,7 +82,7 @@ function showMessage() {
|
|||
showMessage(); // Hello, my name is John
|
||||
```
|
||||
|
||||
The function has a full access to an outer variable. It can modify it as well.
|
||||
The function has full access to the outer variable. It can modify it as well.
|
||||
|
||||
For instance:
|
||||
|
||||
|
@ -103,11 +103,9 @@ showMessage();
|
|||
alert( userName ); // *!*Bob*/!*, the value was modified by the function
|
||||
```
|
||||
|
||||
Sometimes that happens when we forget `let`. Because the outer variable is only used if there's no local one.
|
||||
The outer variable is only used if there's no local one. So an occasional modification may happen if we forget `let`.
|
||||
|
||||
For example, if we had `let` before `userName` in the line (1) then the function would have a local variable `userName` and use it instead. This process is called "shadowing".
|
||||
|
||||
In the code below the local `userName` *shadows* the outer one:
|
||||
If a same-named variable is declared inside the function then it *shadows* the outer one. For instance, in the code below the function uses the local `userName`, the outer one is ignored:
|
||||
|
||||
```js run
|
||||
let userName = 'John';
|
||||
|
@ -132,12 +130,12 @@ Variables declared outside of any function, such as the outer `userName` in the
|
|||
|
||||
Global variables are visible from any function (unless shadowed by locals).
|
||||
|
||||
Usually, a function declares all variables specific to its task, and global variables only store the data so important that it really must be seen from anywhere. Modern code has little to no globals, most variables reside in their functions.
|
||||
Usually, a function declares all variables specific to its task, and global variables only store project-level data, so important that it really must be seen from anywhere. Modern code has few or no globals, most variables reside in their functions.
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
We can pass arbitrary data to function using it's parameters (also called *function arguments*) .
|
||||
We can pass arbitrary data to function using parameters (also called *function arguments*) .
|
||||
|
||||
In the example below, the function has two parameters: `from` and `text`.
|
||||
|
||||
|
@ -147,14 +145,14 @@ function showMessage(*!*from, text*/!*) { // arguments: from, text
|
|||
}
|
||||
|
||||
*!*
|
||||
showMessage('Ann', 'Hello!'); // Ann: Hello!
|
||||
showMessage('Ann', "What's up?"); // Ann: What's up?
|
||||
showMessage('Ann', 'Hello!'); // Ann: Hello! (*)
|
||||
showMessage('Ann', "What's up?"); // Ann: What's up? (**)
|
||||
*/!*
|
||||
```
|
||||
|
||||
When the function is called, the values in the brackets are copied to local variables `from` and `next`.
|
||||
When the function is called in lines `(*)` and `(**)`, the given values are copied to local variables `from` and `next`. Then the function uses them.
|
||||
|
||||
Please note that because the function can modify them. The changes are made to copies, so they won't affect anything outside:
|
||||
Here's one more example: we have a variable `from` and pass it to the function. Please note: the function changes `from`, but the change is not seen outside, because a function always gets a copy of the value:
|
||||
|
||||
|
||||
```js run
|
||||
|
@ -185,23 +183,26 @@ For instance, the aforementioned function `showMessage(from, text)` can be calle
|
|||
showMessage("Ann");
|
||||
```
|
||||
|
||||
That's not an error. Such call would output `"Ann: undefined"`, because `text === undefined`.
|
||||
That's not an error. Such call would output `"Ann: undefined"`. There's no `text`, so it's assumed that `text === undefined`.
|
||||
|
||||
If we want to use a "default" `text` in this case, then we can specify it after `=`:
|
||||
|
||||
```js run
|
||||
function showMessage(from, *!*text = 'no text given'*/!*) {
|
||||
function showMessage(from, *!*text = "no text given"*/!*) {
|
||||
alert( from + ": " + text );
|
||||
}
|
||||
|
||||
showMessage("Ann"); // Ann: no text given
|
||||
```
|
||||
|
||||
Here `'no text given'` is a string, but it can be a more complex expression, which is only evaluated and assigned if the parameter is missing. So, this is also possible:
|
||||
Now if the `text` parameter is not passed, it will get the value `"no text given"`
|
||||
|
||||
Here `"no text given"` is a string, but it can be a more complex expression, which is only evaluated and assigned if the parameter is missing. So, this is also possible:
|
||||
|
||||
```js run
|
||||
function showMessage(from, text = anotherFunction()) {
|
||||
// anotherFunction() only executed if no text given
|
||||
// its result becomes the value of text
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -223,15 +224,17 @@ function showMessage(from, text) {
|
|||
}
|
||||
```
|
||||
|
||||
...Or operator `||`:
|
||||
...Or the `||` operator:
|
||||
|
||||
```js
|
||||
function showMessage(from, text) {
|
||||
// the argument is considered missing if it's falsy
|
||||
// if text is falsy then text gets the "default" value
|
||||
text = text || 'no text given';
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
````
|
||||
|
||||
|
||||
|
@ -315,14 +318,14 @@ alert( doNothing() === undefined ); // true
|
|||
```
|
||||
````
|
||||
|
||||
````warn header="Never line-break between `return` and its value"
|
||||
For long expressions, it may be tempting sometimes to put them on a separate line, like this:
|
||||
````warn header="Never add a newline between `return` and the value"
|
||||
For a long expression in `return`, it might be tempting to put it on a separate line, like this:
|
||||
|
||||
```js
|
||||
return
|
||||
(some + long + expression + or + whatever * f(a) + f(b))
|
||||
```
|
||||
That doesn't work, because JavaScript assumes a semicolon after `return` in that case:
|
||||
That doesn't work, because JavaScript assumes a semicolon after `return`. That'll work the same as:
|
||||
|
||||
```js
|
||||
return*!*;*/!*
|
||||
|
@ -341,10 +344,10 @@ For instance, functions that start with `"show"` -- usually show something.
|
|||
|
||||
Function starting with...
|
||||
|
||||
- `"get"` -- allow to get something,
|
||||
- `"calc"` -- calculate something,
|
||||
- `"create"` -- create something,
|
||||
- `"check"` -- check something and return a boolean, etc.
|
||||
- `"get…"` -- return a value,
|
||||
- `"calc…"` -- calculate something,
|
||||
- `"create…"` -- create something,
|
||||
- `"check…"` -- check something and return a boolean, etc.
|
||||
|
||||
Examples of such names:
|
||||
|
||||
|
@ -361,7 +364,7 @@ With prefixes at place, a glance at a function name gives an understanding what
|
|||
```smart header="One function -- one action"
|
||||
A function should do exactly what is suggested by its name, no more.
|
||||
|
||||
Two independant actions usually deserve two functions, even if they are usually called together (in that case we can make a 3rd function calling those two).
|
||||
Two independant actions usually deserve two functions, even if they are usually called together (in that case we can make a 3rd function that calls those two).
|
||||
|
||||
Few examples of breaking this rule:
|
||||
|
||||
|
@ -369,7 +372,7 @@ Few examples of breaking this rule:
|
|||
- `createForm` -- would be bad if it modifies the document, adding a form to it (should only create it and return).
|
||||
- `checkPermission` -- would be bad if displays the `access granted/denied` message (should only perform the check and return the result).
|
||||
|
||||
These examples reflect few common meanings of prefixes, the final word comes from you and your team. Maybe it's pretty normal for your code to behave differently. But you should to have a firm understanding what a prefix means, what a prefixed function can and what it can not do. All same-prefixed functions should obey the rules. And the team should share the knowledge.
|
||||
These examples assume common meanings of prefixes. What they mean for you is determined by you and your team. Maybe it's pretty normal for your code to behave differently. But you should to have a firm understanding what a prefix means, what a prefixed function can and what it can not do. All same-prefixed functions should obey the rules. And the team should share the knowledge.
|
||||
```
|
||||
|
||||
```smart header="Ultrashort function names"
|
||||
|
@ -382,11 +385,7 @@ These are exceptions. Generally functions names should be concise, but descripti
|
|||
|
||||
## Functions == Comments
|
||||
|
||||
Functions should be short and do exactly one thing. If that thing is big, maybe it's worth to split the function into parts.
|
||||
|
||||
Sometimes following this rule may be not easy, but it's a definitely good thing.
|
||||
|
||||
...So why functions equal comments?
|
||||
Functions should be short and do exactly one thing. If that thing is big, maybe it's worth to split the function into few smaller functions. Sometimes following this rule may be not easy, but it's a definitely good thing.
|
||||
|
||||
A separate function is not only easier to test and debug -- its very existence is a great comment!
|
||||
|
||||
|
@ -429,9 +428,7 @@ function isPrime(n) {
|
|||
|
||||
The second variant is easier to understand isn't it? Instead of the code piece we see a name of the action (`isPrime`). Sometimes people refer to such code as *self-describing*.
|
||||
|
||||
```summary
|
||||
So the idea is: functions can be created even if we don't intend to reuse them. They structure the code and make it readable.
|
||||
```
|
||||
So, functions can be created even if we don't intend to reuse them. They structure the code and make it readable.
|
||||
|
||||
## Summary
|
||||
|
||||
|
@ -444,12 +441,10 @@ function name(parameters, delimited, by, comma) {
|
|||
```
|
||||
|
||||
- Values passed to function as parameters are copied to its local variables.
|
||||
- A function may access outer variables. But it works only one-way. The code outside of the function doesn't see its local variables.
|
||||
- A function may access outer variables. But it works only from inside out. The code outside of the function doesn't see its local variables.
|
||||
- A function can return a value. If it doesn't then its result is `undefined`.
|
||||
|
||||
It is possible for a function to access variables defined outside of it.
|
||||
|
||||
But to make the code cleaner and easier to understand, it's recommended to use local variables and parameters instead as much as possible.
|
||||
To make the code clean and easy to understand, it's recommended to use mainly local variables and parameters in the function, not outer variables.
|
||||
|
||||
It is always easier to understand a function which gets parameters, works with them and returns a result than a function which gets no parameters, but modifies outer variables as a side-effect.
|
||||
|
||||
|
@ -457,6 +452,6 @@ Function naming:
|
|||
|
||||
- A name should clearly describe what the function does. When we see a function call in the code, a good name instantly gives us an understanding what it does and returns.
|
||||
- A function is an action, so function names are usually verbal.
|
||||
- There exist many widespread function prefixes like `create…`, `show…`, `get…`, `check…` and so on. Use them to hint what a function does.
|
||||
- There exist many well-known function prefixes like `create…`, `show…`, `get…`, `check…` and so on. Use them to hint what a function does.
|
||||
|
||||
Functions are the main building blocks of scripts. Now we covered the basics, so we actually can start creating and using them. But that's only the beginning of the path. We are going to return to them many times, going more deeply in their advanced features.
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
```js run
|
||||
function ask(question, yes, no) {
|
||||
if (confirm(question)) yes()
|
||||
else no();
|
||||
}
|
||||
|
||||
ask(
|
||||
"Do you agree?",
|
||||
*!*
|
||||
() => alert("You agreed."),
|
||||
() => alert("You canceled the execution.")
|
||||
*/!*
|
||||
);
|
||||
```
|
||||
|
||||
Looks short and clean, right?
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
# Rewrite with arrow functions
|
||||
|
||||
Replace Function Expressions with arrow functions in the code:
|
||||
|
||||
```js run
|
||||
function ask(question, yes, no) {
|
||||
if (confirm(question)) yes()
|
||||
else no();
|
||||
}
|
||||
|
||||
ask(
|
||||
"Do you agree?",
|
||||
function() { alert("You agreed."); },
|
||||
function() { alert("You canceled the execution."); }
|
||||
);
|
||||
```
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
In JavaScript a function is not a "magical language structure", but a special kind of value.
|
||||
|
||||
[cut]
|
||||
|
||||
The syntax that we used before is called *Function Declaration*:
|
||||
|
||||
```js
|
||||
|
@ -10,9 +12,7 @@ function sayHi() {
|
|||
}
|
||||
```
|
||||
|
||||
There is another way of creating a function that is called *Function Expression*.
|
||||
|
||||
[cut]
|
||||
There is another syntax of creating a function that is called *Function Expression*.
|
||||
|
||||
It looks like this:
|
||||
|
||||
|
@ -22,9 +22,10 @@ let sayHi = function() {
|
|||
};
|
||||
```
|
||||
|
||||
The meaning of these code samples is the same: "create a function and put it into the variable `sayHi`".
|
||||
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`.
|
||||
|
||||
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`:
|
||||
|
||||
|
@ -38,9 +39,11 @@ alert( sayHi ); // shows the function code
|
|||
*/!*
|
||||
```
|
||||
|
||||
Note that there are no brackets after `sayHi` in the last line, because we do not intend to run the function. There are programming languages where any mention of a function name causes it's call, but JavaScript is not like that. In JavaScript, a function is a value and we can deal with that as a value. The code above shows its string representation, that is its source code.
|
||||
Please note that the last line does not run the function, because there are no parentheses after `sayHi`. There are programming languages where any mention of a function name causes the execution, but JavaScript is not like that.
|
||||
|
||||
It is a special value of course, in the sense that we can call it using brackets: `"sayHi()"`.
|
||||
In JavaScript, a function is a value and we can deal with that as a value. The code above shows its string representation, that is the source code.
|
||||
|
||||
It is a special value of course, 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.
|
||||
|
||||
|
@ -53,8 +56,8 @@ function sayHi() { // (1) create
|
|||
|
||||
let func = sayHi; // (2) copy
|
||||
|
||||
func(); // Hello // (3) call the copy (it works)!
|
||||
sayHi(); // Hello // this works too (why wouldn't it)
|
||||
func(); // Hello // (3) run the copy (it works)!
|
||||
sayHi(); // Hello // this still works too (why wouldn't it)
|
||||
```
|
||||
|
||||
That's what happens above in detail:
|
||||
|
@ -62,7 +65,7 @@ That's what happens above in detail:
|
|||
1. Function Declaration `(1)` creates the function and puts it into the variable named `sayHi`.
|
||||
2. Line `(2)` copies it into variable `func`.
|
||||
|
||||
Please note again: there are no brackets after `sayHi`. If they were, then `func = sayHi()` would write *the result of the call* `sayHi()` into `func`, not *the function* `sayHi` itself.
|
||||
Please note again: there are no parentheses after `sayHi`. If they 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 both as `sayHi()` and `func()`.
|
||||
|
||||
Note, that we could also have used a Function Expression to declare `sayHi`, in the first line:
|
||||
|
@ -77,7 +80,7 @@ let func = sayHi;
|
|||
Everything would work the same. Even more obvious what's going on, right?
|
||||
|
||||
|
||||
````smart header="Why semicolon?"
|
||||
````smart header="Why there's a semicolon at the end?"
|
||||
There might be a question, why Function Expression has a semicolon `;` at the end, and Function Declaration does not:
|
||||
|
||||
```js
|
||||
|
@ -97,7 +100,7 @@ The answer is simple:
|
|||
|
||||
## Callback functions
|
||||
|
||||
Let's see an example where function expressions come really handy.
|
||||
Let's see more examples of passing functions as values and using function expressions.
|
||||
|
||||
We'll write a function `ask(question, yes, no)` with three parameters:
|
||||
|
||||
|
@ -110,7 +113,7 @@ We'll write a function `ask(question, yes, no)` with three parameters:
|
|||
`no`
|
||||
: Function to run if the answer is "No"
|
||||
|
||||
The function should ask the `question` and, depending on the user's agreement, call `yes()` or `no()`:
|
||||
The function should ask the `question` and, depending on the user's answer, call `yes()` or `no()`:
|
||||
|
||||
```js run
|
||||
*!*
|
||||
|
@ -128,15 +131,15 @@ function showCancel() {
|
|||
alert( "You canceled the execution." );
|
||||
}
|
||||
|
||||
// usage
|
||||
// usage: functions showOk, showCancel are passed as arguments to ask
|
||||
ask("Do you agree?", showOk, showCancel);
|
||||
```
|
||||
|
||||
The code looks kind of too simple, right? Why would anyone need such `ask`?
|
||||
Before we'll 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.
|
||||
|
||||
...It turns out 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.
|
||||
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.
|
||||
|
||||
The arguments of `ask` are called *callback functions* or just *callbacks*. The idea is that we pass the functions and expect them to be "called back" in certain circumstances.
|
||||
**The arguments of `ask` are called *callback functions* or just *callbacks*. The idea is that we pass a function and expect it to be "called back" in certain circumstances.**
|
||||
|
||||
So, `showOk` becomes the callback for the "yes" answer and `showCancel` -- for the "no" answer.
|
||||
|
||||
|
@ -157,7 +160,7 @@ 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`, but that's just what we want here.
|
||||
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.
|
||||
|
||||
|
@ -185,9 +188,9 @@ First, the syntax: how to see what is what in the code.
|
|||
return a + b;
|
||||
}
|
||||
```
|
||||
- *Function Expression:* a function, created in the context of an expression.
|
||||
- *Function Expression:* a function, created inside an expression or inside another syntax construct.
|
||||
|
||||
Here the function is created in the context of an "assignment expression =":
|
||||
Here the function is created at the right side of the "assignment expression =":
|
||||
```js
|
||||
// Function Expression
|
||||
let sum = function(a, b) {
|
||||
|
@ -195,19 +198,19 @@ First, the syntax: how to see what is what in the code.
|
|||
}
|
||||
```
|
||||
|
||||
The more subtle difference is when they are actualy created by the JavaScript engine.
|
||||
The more subtle difference is *when* a function is created by JavaScript engine.
|
||||
|
||||
**Function Expressions are created when the execution reaches them and are usable since then.**
|
||||
**Function Expression is created when the execution reaches it and is usable since then.**
|
||||
|
||||
That's kind of obvious. 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.
|
||||
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.
|
||||
|
||||
**Function Declarations are usable in the whole script/code block.**
|
||||
**Function Declaration is usable in the whole script/code block.**
|
||||
|
||||
In other words, when JavaScript *prepares* to run the script/code block, it first looks for Function Declarations in it and creates the functions. We can think of it as an "initialization stage".
|
||||
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".
|
||||
|
||||
And after all Function Declarations are processed, it actually executes it.
|
||||
And after all Function Declarations are processed, the execution goes on.
|
||||
|
||||
As a natural effect, a function declared as Function Declaration can be called earlier than it is defined.
|
||||
|
||||
|
@ -244,9 +247,9 @@ Function Expressions are created when the execution reaches them. That would hap
|
|||
|
||||
When Function Declaration is made within a code block, it is visible everywhere inside that block. But not outside of it.
|
||||
|
||||
Sometimes that's handy to declare a local function, only needed in that only block. But can also be a problem.
|
||||
Sometimes that's handy to declare a local function only needed in that only block. But that feature may also cause problems.
|
||||
|
||||
For instance, let's imagine that we need to declare a function `welcome()` depending on the `age` variable that we get in run time. And then use it sometimes later.
|
||||
For instance, let's imagine that we need to declare a function `welcome()` depending on the `age` variable that we get in run time. And then we plan to use it sometimes later.
|
||||
|
||||
The code below doesn't work:
|
||||
|
||||
|
@ -286,7 +289,7 @@ if (age < 18) {
|
|||
// |
|
||||
function welcome() { // |
|
||||
alert("Hello!"); // | Function Declaration is available
|
||||
} // | everywhere in the block when it's declared
|
||||
} // | everywhere in the block where it's declared
|
||||
// |
|
||||
*!*
|
||||
welcome(); // / (runs)
|
||||
|
@ -295,12 +298,12 @@ if (age < 18) {
|
|||
} else {
|
||||
// \
|
||||
function welcome() { // |
|
||||
alert("Greetings!"); // | in this if test we don't enter this block,
|
||||
alert("Greetings!"); // | if age=16, the the execution does not go here,
|
||||
} // | so this "welcome" is never created
|
||||
// /
|
||||
}
|
||||
|
||||
// Now we're out of figure brackets,
|
||||
// Here we're out of figure brackets,
|
||||
// so we can not see Function Declarations made inside of them.
|
||||
|
||||
*!*
|
||||
|
@ -308,7 +311,7 @@ welcome(); // Error: welcome is not defined
|
|||
*/!*
|
||||
```
|
||||
|
||||
What can we do to make `welcome` visible outside?
|
||||
What can we do to make `welcome` visible outside of `if`?
|
||||
|
||||
The right thing would be to use a Function Expression and assign `welcome` to the variable which is declared outside of `if` and has the proper visibility:
|
||||
|
||||
|
@ -321,13 +324,13 @@ if (age < 18) {
|
|||
|
||||
welcome = function() {
|
||||
alert("Hello!");
|
||||
}
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
welcome = function() {
|
||||
alert("Greetings!");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -336,13 +339,14 @@ welcome(); // ok now
|
|||
*/!*
|
||||
```
|
||||
|
||||
Or we could go on to simplify it even further using a question mark operator `?`:
|
||||
Or we could simplify it even further using a question mark operator `?`:
|
||||
|
||||
```js run
|
||||
let age = prompt("What is your age?", 18);
|
||||
|
||||
let welcome = (age < 18) ?
|
||||
function() { alert("Hello!"); } : function() { alert("Greetings!"); }
|
||||
function() { alert("Hello!"); } :
|
||||
function() { alert("Greetings!"); };
|
||||
|
||||
*!*
|
||||
welcome(); // ok now
|
||||
|
@ -350,22 +354,19 @@ welcome(); // ok now
|
|||
```
|
||||
|
||||
|
||||
```smart header="What to choose: a Declaration or an Expression?"
|
||||
As a rule of thumb, a Function Declaration is prefered. It gives more freedom in how to organize our code, because we can call it both above and below.
|
||||
```smart header="What to choose: Function Declaration or 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.
|
||||
|
||||
It's also a little bit easier to look up Function Declarations in the code, they increase readability of the code.
|
||||
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".
|
||||
|
||||
But if a Function Declaration does not fit for some reason (we've seen an example), then a Function Expression should be used.
|
||||
...But if Function Declaration does not suit us for some reason (we've seen an example above), then Function Expression should be used.
|
||||
```
|
||||
|
||||
|
||||
## Arrow functions [#arrow-functions]
|
||||
|
||||
Enough with the complexities for now. Let's relax with another syntax of functions that can make our code shorter.
|
||||
There's one more syntax for creating functions -- very simple and concise. It's called "arrow functions", because it looks like this:
|
||||
|
||||
Arrow functions act like a function expression, but look a little bit differently.
|
||||
|
||||
The syntax is:
|
||||
|
||||
```js
|
||||
let func = (arg1, arg2, ...argN) => expression
|
||||
|
@ -381,6 +382,8 @@ let func = function(arg1, arg2, ...argN) {
|
|||
}
|
||||
```
|
||||
|
||||
...But much shorter.
|
||||
|
||||
Let's see the example:
|
||||
|
||||
```js run
|
||||
|
@ -397,7 +400,7 @@ let sum = function(a, b) {
|
|||
};
|
||||
```
|
||||
|
||||
If we have only one argument, then brackets can be omitted, making that even shorter:
|
||||
If we have only one argument, then parentheses can be omitted, making that even shorter:
|
||||
|
||||
```js run
|
||||
// same as
|
||||
|
@ -409,7 +412,7 @@ let double = n => n*2;
|
|||
alert( double(3) ); // 6
|
||||
```
|
||||
|
||||
If there are no arguments, we can put empty brackets:
|
||||
If there are no arguments, we can put empty parentheses:
|
||||
|
||||
```js run
|
||||
let sayHi = () => alert("Hello!");
|
||||
|
@ -424,7 +427,9 @@ For instance, here's the rewritten example with `welcome()`:
|
|||
```js run
|
||||
let age = prompt("What is your age?", 18);
|
||||
|
||||
let welcome = (age < 18) ? () => alert('Hello') : () => alert("Greetings!");
|
||||
let welcome = (age < 18) ?
|
||||
() => alert('Hello') :
|
||||
() => alert("Greetings!");
|
||||
|
||||
welcome(); // ok now
|
||||
```
|
||||
|
@ -453,7 +458,7 @@ alert( sum(1, 2) ); // 3
|
|||
```
|
||||
|
||||
```smart header="More to come"
|
||||
Here we praised arrow functions for shortness. But that's not all! Arrow functions have other interesting features. We'll return to them later in the chapter <info:arrow-functions>.
|
||||
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 <info:arrow-functions>.
|
||||
|
||||
As for now, we can already use them for one-line actions and callbacks.
|
||||
```
|
||||
|
@ -461,18 +466,17 @@ As for now, we can already use them for one-line actions and callbacks.
|
|||
## Summary
|
||||
|
||||
- Functions are values. They can be assigned, copied or declared in any place of the code.
|
||||
- If the function is declared as a separate statement, in the main code flow -- that's called a Function Declaration.
|
||||
- If the function is created as a part of an expression -- it's a Function Expression.
|
||||
- If the function is declared as a separate statement, in the main code flow -- that's called "Function Declaration".
|
||||
- If the function is created as a part of an expression -- it's "Function Expression".
|
||||
- Function Declarations are processed before the code block is executed. They are visible everywhere in the block.
|
||||
- Function Expressions are created when the execution flow reaches them.
|
||||
- Function Expressions allow to specify an optional name for internal needs (Named Function Expression).
|
||||
|
||||
|
||||
In most cases Function Declaration is preferable, because it is visible prior to the declaration itself. And is usually more readable.
|
||||
In most cases when we need to declare a function, Function Declaration is preferable, because it is visible prior to the declaration itself. That gives more flexibility in code organization. And is usually more readable.
|
||||
|
||||
So we should use Function Expression only when Function Declaration does not fit the task. We've seen a couple of examples of that in the chapter. And will see more in the future.
|
||||
|
||||
Arrow functions are handy for one-liners. The come in two flavors:
|
||||
|
||||
1. Without figure brackets: `(...args) => expression` -- returns the evaluated `expression`. The right side must be a single expression.
|
||||
2. With figure brackets: `(...args) => { body }` -- they need an explicit `return` statement to return something, but can be more complex and contain multiple statements.
|
||||
1. Without figure brackets: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result.
|
||||
2. With figure brackets: `(...args) => { body }` -- brackets allow to write multiple statements inside the function, but we need an explicit `return` to return something.
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# JavaScript specials
|
||||
|
||||
This chapter aims to list features of JavaScript that we've learned, paying special attention to subtle moments.
|
||||
|
||||
That's especially useful if you came from another language or just as a recap.
|
||||
This chapter briefly recaps the features of JavaScript that we've learned by now, paying special attention to subtle moments.
|
||||
|
||||
[cut]
|
||||
|
||||
|
@ -31,14 +29,16 @@ alert("There will be an error after this message")
|
|||
|
||||
Most codestyle guides agree that we should put a semicolon after each statement.
|
||||
|
||||
Semicolons are not required after code blocks `{...}` and syntax constructs with them:
|
||||
Semicolons are not required after code blocks `{...}` and syntax constructs with them like loops:
|
||||
|
||||
```js
|
||||
function f() {
|
||||
// no semicolon needed after function declaration
|
||||
}
|
||||
|
||||
for(;;) { /* no semicolon after the loop */ }
|
||||
for(;;) {
|
||||
// no semicolon needed after the loop
|
||||
}
|
||||
```
|
||||
|
||||
...But even if we can put an "extra" semicolon somewhere, that's not an error, it will be ignored.
|
||||
|
@ -59,7 +59,7 @@ The directive must be at the top of a script or at the beginning of a function.
|
|||
|
||||
Without `"use strict"`, everything still works, but some features behave in old-fasion, "compatible" way. We'd generally prefer the modern behavior.
|
||||
|
||||
Advanced features of the language (like classes that we'll study in the future) that enable strict mode implicitly.
|
||||
Some modern features of the language (like classes that we'll study in the future) enable strict mode implicitly.
|
||||
|
||||
More in: <info:strict-mode>.
|
||||
|
||||
|
@ -67,8 +67,8 @@ More in: <info:strict-mode>.
|
|||
|
||||
Can be declared using:
|
||||
|
||||
- `let` (block-level visibility)
|
||||
- `const` (can't be changed)
|
||||
- `let`
|
||||
- `const` (constant, can't be changed)
|
||||
- `var` (old-style, will see later)
|
||||
|
||||
A variable name can include:
|
||||
|
@ -92,7 +92,7 @@ There are 7 data types:
|
|||
- `undefined` -- a type with a single value `undefined`, meaning "not assigned",
|
||||
- `object` and `symbol` -- for complex data structures and unique identifiers, we didn't learn them yet.
|
||||
|
||||
The `typeof` operator returns the type for a value, with two special behaviors:
|
||||
The `typeof` operator returns the type for a value, with two exceptions:
|
||||
```js
|
||||
typeof null == "object" // error in the language
|
||||
typeof function(){} == "function" // functions are treated specially
|
||||
|
@ -125,7 +125,7 @@ alert( "Visitor: " + userName ); // Alice
|
|||
alert( "Tea wanted: " + isTeaWanted ); // true
|
||||
```
|
||||
|
||||
More in: <info:uibasic>.
|
||||
More in: <info:alert-prompt-confirm>.
|
||||
|
||||
## Operators
|
||||
|
||||
|
@ -134,9 +134,7 @@ JavaScript supports following operators:
|
|||
Arithmetical
|
||||
: Regular: `* + - /`, also `%` for the remainder and `**` for power of a number.
|
||||
|
||||
Binary plus `+` concatenates strings.
|
||||
|
||||
If any of the operands is a string -- the other one is converted to string too:
|
||||
Binary plus `+` concatenates strings. And if any of the operands is a string -- the other one is converted to string too:
|
||||
|
||||
```js run
|
||||
alert( '1' + 2 ); // '12', string
|
||||
|
@ -147,11 +145,10 @@ Assignments
|
|||
: There is a simple assignment: `a = b` and combined ones like `a *= 2`.
|
||||
|
||||
Bitwise
|
||||
: Bitwise operators work with integers on bit-level: see the [docs](mdn:JavaScript/Refereno
|
||||
ce/Operators/Bitwise_Operators) when they are needed.
|
||||
: Bitwise operators work with integers on bit-level: see the [docs](mdn:/JavaScript/Reference/Operators/Bitwise_Operators) when they are needed.
|
||||
|
||||
Ternary
|
||||
: The only operator with three parameters: `cond ? resultA : result B`
|
||||
: The only operator with three parameters: `cond ? resultA : result B`. If `cond` is truthy, returns `resultA`, otherwise `resultB`.
|
||||
|
||||
Logical operators
|
||||
: Logical AND `&&` and OR `||` perform short-circuit evaluation and then return the value where it stopped.
|
||||
|
@ -168,8 +165,6 @@ Comparisons
|
|||
|
||||
The strict equality operator `===` doesn't do the conversion: different types always mean different values for it, so:
|
||||
|
||||
|
||||
|
||||
Values `null` and `undefined` are special: they equal `==` each other and don't equal anything else.
|
||||
|
||||
Greater/less comparisons compare strings character-by-character, other types are converted to a number.
|
||||
|
@ -177,7 +172,7 @@ Comparisons
|
|||
Logical operators
|
||||
: There are few others, like a comma operator.
|
||||
|
||||
More in: <info:operators>, <info:comparison>, <info:logical-ops>.
|
||||
More in: <info:operators>, <info:comparison>, <info:logical-operators>.
|
||||
|
||||
## Loops
|
||||
|
||||
|
@ -218,7 +213,7 @@ let age = prompt('Your age?', 18);
|
|||
|
||||
switch (age) {
|
||||
case 18:
|
||||
alert("Won't work"); // the result of prompt is a string, not a number
|
||||
alert("Won't work"); // the result of prompt is a string, not a number
|
||||
|
||||
case "18":
|
||||
alert("This works!"");
|
||||
|
@ -291,6 +286,4 @@ More: see <info:function-basics>, <info:function-expressions-arrows>.
|
|||
|
||||
## More to come
|
||||
|
||||
That was a brief list of JavaScript specials that we need to know to code well.
|
||||
|
||||
As of now that were only basics. Further in the tutorial you'll find more specials and advanced features of JavaScript.
|
||||
That was a brief list of JavaScript features. As of now we studied only basics. Further in the tutorial you'll find more specials and advanced features of JavaScript.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue