Compare commits

..

8 commits

Author SHA1 Message Date
Ilya Kantor
fe7e84b260 minor fixes 2021-06-14 00:52:35 +03:00
Ilya Kantor
d20a6e3d5e minor fixes 2021-06-09 07:07:18 +03:00
Ilya Kantor
5a024624af minor fixes 2021-01-23 23:30:28 +03:00
Ilya Kantor
51edbb1236 minor fixes 2021-01-19 14:09:58 +03:00
Ilya Kantor
06cdd5b84a taskui 2020-11-21 20:38:22 +03:00
Ilya Kantor
db4a880974 WIP 2020-10-29 21:46:52 +03:00
Ilya Kantor
b5cb105843 Merge branch 'master' of github.com:javascript-tutorial/en.javascript.info into sync-181cc781 2020-10-05 05:07:51 +00:00
Ilya Kantor
6a891403fd readme 2020-09-27 13:18:00 +03:00
564 changed files with 3255 additions and 4840 deletions

1
.gitignore vendored
View file

@ -21,4 +21,3 @@ sftp-config.json
Thumbs.db
/svgs

View file

@ -0,0 +1,27 @@
# Hello, JavaScript!
JavaScript was created in 1995 as a simple language exclusively for web browsers, to "make web pages alive". Since then it has greatly evolved, it's quite far from there it started.
Today we can use JavaScript on many platforms:
- In a web-browser, by embedding it into a web page.
- On a general purpose computer or a server, using [Node.js](https://nodejs.org) and other means.
- ...Or actually on any device that has a special piece of software, called "a JavaScript engine".
Technically, even a coffee machine can include its own JavaScript engine to allow programming of coffee recipes.
![](javascript-engine.svg)
```smart header="Where to read?"
There's a formal language description called [ECMAScript Language Specification](https://tc39.es/ecma262/), it describes how a JavaScript engine works. Sometimes we'll give references to it, but, though technically correct, it's hard to read for humans.
Also, there's a good JavaScript reference at [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference). One can type `mdn <a javascript term>` in an internet search engine to find the information about that term there.
```
Programs in JavaScript are called "scripts".
**In this tutorial we concentrate on the "core" JavaScript, that works mostly everywhere.**
Then, after you're familiar with it, you'll be able to move in any direction: browsers, servers and so on.
Turn the page to start learning JavaScript!

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="453" height="129" viewBox="0 0 453 129"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="v2" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="javascript-engine.svg"><g id="noun_Server_1653092" fill="#000" fill-rule="nonzero" opacity=".812" transform="translate(366 15)"><path id="Shape" d="M13 86a6 6 0 016-6h16a6 6 0 016 6v2h13V0H0v88h13v-2zm37-2h-5.2a10 10 0 00-1.8-4h7v4zM4 4h46v72H4V4zm5.2 80H4v-4h7a10 10 0 00-1.8 4z"/><path id="Rectangle" d="M12 10h30v4H12zM12 20h30v4H12zM12 30h30v4H12zM12 40h30v4H12zM12 50h30v4H12zM27 63h8v4h-8z"/><circle id="Oval" cx="14" cy="65" r="2"/><circle id="Oval" cx="22" cy="65" r="2"/><circle id="Oval" cx="40" cy="65" r="2"/></g><g id="noun_Coffee-Machine_1997833" fill="#000" fill-rule="nonzero" opacity=".812" transform="translate(187 15)"><path id="Shape" d="M88.577 0H5.423C2.428 0 0 2.63 0 5.875V23.5c0 3.245 2.428 5.875 5.423 5.875v48.958C2.428 78.333 0 80.963 0 84.208v3.917C0 91.37 2.428 94 5.423 94h83.154C91.572 94 94 91.37 94 88.125v-3.917c0-3.244-2.428-5.875-5.423-5.875V29.375c2.995 0 5.423-2.63 5.423-5.875V5.875C94 2.63 91.572 0 88.577 0zm1.808 84.208v3.917c0 1.082-.81 1.958-1.808 1.958H5.423c-.998 0-1.808-.876-1.808-1.958v-3.917c0-1.081.81-1.958 1.808-1.958h83.154c.998 0 1.808.877 1.808 1.958zm-56.039-11.75V56.792c0-2.163 1.619-3.917 3.616-3.917h18.076c1.997 0 3.616 1.754 3.616 3.917v15.666c0 3.245-2.428 5.875-5.423 5.875H39.769c-2.995 0-5.423-2.63-5.423-5.875zm50.616 5.875h-23.5a9.973 9.973 0 001.102-1.958c5.444-.252 9.739-5.103 9.744-11.006V63.9c0-6.028-4.469-10.94-10.033-11.025-1.287-2.415-3.662-3.907-6.237-3.917H37.962c-3.994 0-7.231 3.507-7.231 7.834v15.666c0 2.119.634 4.18 1.807 5.875h-23.5V29.375h75.924v48.958zM68.692 63.9v1.47c-.004 3.446-2.29 6.392-5.423 6.99V56.89c3.14.599 5.428 3.557 5.423 7.01zm21.693-40.4c0 1.082-.81 1.958-1.808 1.958H5.423c-.998 0-1.808-.876-1.808-1.958V5.875c0-1.082.81-1.958 1.808-1.958h83.154c.998 0 1.808.876 1.808 1.958V23.5z"/></g><g id="noun_Browser_1327494" fill="#000" fill-rule="nonzero" opacity=".812" transform="translate(14 16)"><g id="Group"><path id="Shape" d="M86 .523c1.105 0 2 1.294 2 2.889V87.19c0 1.595-.895 2.889-2 2.889H2c-1.105 0-2-1.294-2-2.89V3.413C0 1.817.895.523 2 .523h84zm-2 5.778H4v11.194h80V6.301zm0 16.972H4v61.028h80V23.273z"/><path id="Shape" d="M78.75 8.106c1.515 0 2.781 1.85 2.781 4.018 0 2.167-1.235 4.017-2.781 4.017s-2.781-1.85-2.781-4.017c0-2.168 1.266-4.018 2.781-4.018zm0 2.257c-.686 0-1.219.864-1.219 1.76 0 .897.564 1.761 1.219 1.761.655 0 1.219-.864 1.219-1.76 0-.897-.533-1.76-1.219-1.76zM63.625 8.106c1.5 0 2.812 1.85 2.812 4.018 0 2.167-1.281 4.017-2.812 4.017-1.546 0-2.781-1.85-2.781-4.017 0-2.168 1.266-4.018 2.781-4.018zm0 2.257c-.651 0-1.188.864-1.188 1.76 0 .897.567 1.761 1.188 1.761.655 0 1.219-.864 1.219-1.76 0-.897-.533-1.76-1.219-1.76zM71.187 8.106c1.516 0 2.782 1.85 2.782 4.018 0 2.167-1.235 4.017-2.782 4.017-1.53 0-2.78-1.85-2.78-4.017 0-2.168 1.28-4.018 2.78-4.018zm0 2.257c-.686 0-1.218.864-1.218 1.76 0 .897.563 1.761 1.218 1.761.621 0 1.22-.864 1.22-1.76 0-.897-.569-1.76-1.22-1.76z"/></g></g><text id="javascript-engine" fill="#8A704D" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="26.376" y="62">javascript</tspan> <tspan x="35.447" y="81">engine</tspan></text><text id="javascript-engine" fill="#8A704D" font-family="OpenSans-Bold, Open Sans" font-size="18" font-weight="bold"><tspan x="349.225" y="59">javascript</tspan> <tspan x="363.204" y="83">engine</tspan></text><text id="javascript-engine" fill="#8A704D" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="199.064" y="59">javascript</tspan> <tspan x="209.937" y="78">engine</tspan></text></g></g></svg>

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -0,0 +1 @@
console.log("It works");

View file

@ -0,0 +1,5 @@
Congratulations!
This task was simple though.
Go ahead to learn more.

View file

@ -0,0 +1,11 @@
# Hello, world!
Welcome to the tasks!
Practicing will help you to understand theory and hone your skills!
The first task is simple, just to get acquainted.
Write the code to `console.log` a message "Hello" (you actually saw the correct right in the tutorial).

View file

@ -0,0 +1,7 @@
// TODO: tests are executed after code (See evalWorker.js)
//
window.addEventListener('message', event => {
// event.name = message or log or whatever?
// check that console.log happened
console.error(event);
});

View file

@ -0,0 +1,131 @@
# Statements
Just like a human speech consists of sentences, JavaScript code consists of *statements*.
Here's an example of a statement:
```js run
console.log("Hello, world!");
```
Click the "run" icon ▷ in the right-upper corner to see how it works.
In this particular statement `console.log` is the command to show a message, and `"Hello, world!"` is the string to show. We'll learn more about commands and strings soon.
We can have as many statements as we want.
For example, let's make it two separate messages, one after the other:
```js run
console.log("Hello"); console.log("World");
```
Usually, statements are written on separate lines to make the code more readable, like this:
```js run no-beautify
console.log("Hello");
console.log("World");
```
Please note: every statement ends with a semicolon `;`.
## Semicolons..or not?
Technically, a semicolon may be unnecessary, if there's a line break between statements.
Here's the same code as above, but without semicolons:
```js run no-beautify
console.log("Hello")
console.log("World")
```
It also works, because usually JavaScript interprets a line break as an "implicit" semicolon. This language feature is called the "semicolon auto-insertion".
There are exceptions for that auto-insertion, for example:
```js run no-beautify
console.log(1 +
2);
```
This code outputs `3`, same as a single-line `console.log(1 + 2)`. Here JavaScript assumes that the line-break after `+` doesn't end the statement.
Why so? For us humans, it's intuitively obvious that if the line ends with a plus `+`, then the expression is incomplete and will be continued on the next line. JavaScript has internal grammar rules for that.
Although, these rules aren't perfect.
**There are situations where our intuition differs from JavaScript semicolon auto-insertion rules.**
That may lead to subtle errors.
To prevent them, we recommend putting semicolons between statements, even if they are separated by newlines. Most of the JavaScript codebase follows this convention.
````spoiler header="See an example of such error"
If you're curious to see a concrete example of such an error, check this code out:
```js run
console.log("Hello");
[1, 2].forEach(console.log);
```
That's some advanced code, but noo need to think about the meaning of the brackets `[]` and `forEach` yet. Well study them later.
For now just remember the result of running the code: it shows `Hello`, then `1`, then `2`.
Now lets remove one semicolon after the console.log, and see how it fails:
```js run
console.log("Hello")
[1, 2].forEach(console.log);
```
The difference compared to the code above is only one character: the semicolon at the end of the first line is gone.
If we run this code, only the first `Hello` shows, and then there's an error. There are no numbers any more!
That's because JavaScript doesn't auto-insert a semicolon before square brackets [...]. So, the code in the last example is treated as a single statement, as if there were no line break at all.
In other words, JavaScript
```js
console.log("Hello")[1, 2].forEach(console.log);
```
The code may be too advanced to understand right now, but that's all right.
All you need to do is to run the code and remember the result: it shows `1` then `2`.
Let's add an `console.log` before the code and *not* finish it with a semicolon:
```js run no-beautify
console.log("Without a semicolon after the console.log - error")
[1, 2].forEach(console.log)
```
Now if you run the code, only the first `console.log` is shown and then there's an error!
...But everything becomes fine again we add a semicolon after the `console.log`:
```js run
console.log("With a semicolon after me - all ok");
[1, 2].forEach(console.log)
```
The error in the no-semicolon variant occurs because JavaScript doesn't "auto-insert" a semicolon if a newline is followed by squares brackets `[...]`.
So, because the semicolon is not auto-inserted, the code in the first example is treated as a single statement. Here's how the engine sees it:
```js run no-beautify
console.log("There will be an error")[1, 2].forEach(console.log)
```
But such a merge in this case is just wrong, hence the error. This can happen in other situations as well.
````
Let's note once again -- *it is possible* to leave out semicolons most of the time. But it's safer, especially for a beginner, to use them.

View file

@ -0,0 +1,66 @@
# Comments
As time goes on, scripts tend to become more complex. We can add *comments* to describe what the code does and why.
Comments can be put into any place of a script. They don't affect its execution because the engine simply ignores them.
**One-line comments start with two forward slash characters `//`. The rest of the line is a comment.**
Such comment may occupy a full line of its own or follow a statement.
Like here:
```js run
// This comment occupies a line of its own
console.log("Hello");
console.log("World"); // This comment follows the statement
```
For longer, descriptive comments that span multiple lines, we can use the `/* ... */` syntax.
**Multiline comments start with a forward slash and an asterisk <code>/&#42;</code> and end with an asterisk and a forward slash <code>&#42;/</code>.**
Like this:
```js run
/* An example with two messages.
This is a multiline comment.
*/
console.log("Hello");
console.log("World");
```
The content of comments is ignored, so if we wrap a piece of code into `/* ... */`, it won't execute.
It can be handy to temporarily disable ("comment out") a part of code:
```js run
/* Commenting out the code
console.log("Hello");
*/
console.log("World");
```
```smart header="Use hotkeys!"
In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey).
For Mac, try `key:Cmd` instead of `key:Ctrl` and `key:Option` instead of `key:Shift`.
```
````warn header="Nested comments are not supported!"
There may not be `/*...*/` inside another `/*...*/`.
Such code will die with an error:
```js run no-beautify
/*
/* nested comment leads to an error! */
*/
console.log( "World" );
```
````
Please, don't hesitate to comment your code.
Comments increase the overall code footprint, but that's not a problem at all. There are many tools which minify code before publishing to a production server. They remove comments, so they don't appear in the working scripts. Therefore, comments do not have negative effects on production at all.

View file

@ -0,0 +1,2 @@
let admin;
let user;

View file

@ -0,0 +1,4 @@
# Working with variables
Declare two variables: `admin` and `user`.

View file

@ -0,0 +1,9 @@
describe("Test", function() {
it("declares `admin`", function() {
admin; // error if not declared
});
it("declares `user`", function() {
user; // error if not declared
});
});

View file

@ -0,0 +1,4 @@
let user;
let admin;
user = "John";

View file

@ -0,0 +1 @@
Assign the value `"John"` to `user`.

View file

@ -0,0 +1,5 @@
describe("Test", function() {
it(`user has a value: "John"`, function() {
expect(user).toEqual("John");
});
});

View file

@ -0,0 +1,5 @@
let user, admin;
user = "John";
admin = user;

View file

@ -0,0 +1 @@
Copy the value from `user` to `admin`.

View file

@ -0,0 +1,6 @@
describe("Test", function() {
it(`user and admin have value "John"`, function() {
expect(user).toEqual("John");
expect(admin).toEqual("John");
});
});

View file

@ -0,0 +1,7 @@
let user, admin;
user = "John";
admin = user;
alert(admin);

View file

@ -0,0 +1 @@
Show the value of `admin` using `alert` (will show "John").

View file

@ -0,0 +1,14 @@
let nativeAlert = globalThis.alert;
globalThis.alert = jasmine.createSpy();
describe("Test", function() {
after(function() {
globalThis.alert = this.alert;
});
it(`user and admin equal "John"`, function() {
expect(user).toEqual("John");
expect(admin).toEqual("John");
});
});

View file

@ -0,0 +1,291 @@
# Variables
Depending on our application, scripts need to store and manipulate different kinds of data.
For example:
- An online shop -- the data includes goods being sold and the shopping cart content.
- A chat application -- the data includes users, messages, etc.
A [variable](https://en.wikipedia.org/wiki/Variable_(computer_science)) is a "named storage" for data.
To create a variable in JavaScript, use the `let` keyword.
The statement below creates (in formal terms: *declares*) a variable with the name "message":
```js
let message;
```
Now we can store some data into it by using the assignment `=`:
```js
let message;
*!*
message = "Hello"; // store the string "Hello"
*/!*
```
The string is now saved into the memory area associated with the variable. We can access it using the variable name:
```js run
let message;
message = "Hello!";
*!*
console.log(message); // shows the variable content
*/!*
```
To be concise, we can combine the variable declaration and assignment into a single line:
```js run
*!*
let message = "Hello!"; // declare the variable and assign the value to it
*/!*
console.log(message); // Hello!
```
One can also declare multiple variables in one line:
```js no-beautify
let user = "John", age = 25, message = "Hello";
```
That might seem shorter, but we don't recommend it. For the sake of better readability, it's better to use a single line per variable.
The multiline variant is a bit longer, but easier to read:
```js
let user = "John";
let age = 25;
let message = "Hello";
```
## A real-life analogy
We can easily grasp the concept of a "variable" if we imagine it as a "box" for data, with a named sticker on it.
For instance, the variable `message` can be imagined as a box labeled `"message"` with the value `"Hello!"` in it:
![](variable.svg)
We can put any value in the box.
We can also change it as many times as we want:
```js run
let message;
message = "Hello!";
message = "World!"; // value changed
console.log(message);
```
When the value is changed, the old data is removed from the variable:
![](variable-change.svg)
We can also declare two variables and copy data from one into the other.
```js run
let hello = "Hello!";
let message;
*!*
// copy "Hello!" from hello into message
message = hello;
*/!*
// now two variables hold the same data
console.log(hello); // Hello!
console.log(message); // Hello!
```
Now we have two variables, both store the same string:
![](variable-copy-value.svg)
````warn header="Re-declaration triggers an error"
A variable can be declared only once.
A repeated declaration of the same variable is an error:
```js run
let message = "One";
// repeated 'let' leads to an error
let message = "Two"; // SyntaxError: 'message' has already been declared
```
So, we should declare a variable once and then refer to it without `let`.
````
## Variable naming
Technically, a variable name can be any word.
There's just a couple of limitations:
1. The name must be made of letters, digits, or symbols `$` and `_`.
2. The first character must not be a digit.
Examples of valid names:
```js
let userName;
let test123;
```
When the name contains multiple words, [camelCase](https://en.wikipedia.org/wiki/CamelCase) is commonly used. That is: words go one after another, each word after the first one starting with a capital letter: `myVeryLongName`.
What's interesting -- the dollar sign `'$'` and the underscore `'_'` can also be used in names. They are regular symbols, just like letters, without any special meaning.
These names are valid:
```js run untrusted
let $ = 1; // declared a variable with the name "$"
let _ = 2; // and now a variable with the name "_"
console.log($ + _); // 3
```
Examples of incorrect variable names:
```js no-beautify
let 1a; // cannot start with a digit
let my-name; // hyphens '-' aren't allowed in the name
```
```smart header="Case matters"
Variables named `apple` and `AppLE` are two different variables.
```
````smart header="Non-Latin letters are allowed, but not recommended"
It is possible to use any language, including cyrillic letters or even hieroglyphs, like this:
```js
let имя = '...';
let 我 = '...';
```
Technically, there is no error here. Such names are allowed, but there is an international convention to use English in variable names. Even if you're writing a small script, it may have a long life ahead. People from other countries may need to read it in the future.
````
````warn header="Reserved names"
There is a [list of reserved words](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords), which cannot be used as variable names because they are used by the language itself.
For example: `let`, `class`, `return`, and `function` are reserved.
The code below gives a syntax error:
```js run no-beautify
let let = 5; // can't name a variable "let", error!
let return = 5; // also can't name it "return", error!
```
````
## Constants
There are information pieces that aren't expected to change.
For example, a date of birth is a fixed point of time.
To declare a variable that isn't expected to change, use `const` instead of `let`:
```js
const myBirthdate = '18.04.1982';
```
Variables declared using `const` are called "constants". They cannot be reassigned. An attempt to do so would cause an error:
```js run
const myBirthdate = '18.04.1982';
myBirthdate = '01.01.2001'; // error, can't reassign the constant!
```
Here's why using `const` for such variables is a good thing.
1. It gives a hint to every person who reads the code, that the value isn't going to change. So that they can safely eye-jump while reading the code and assume it's still the same.
2. It insures against programming mistakes: if we (or another person who supports our code) attempt to change it, there'll be an error.
## Uppercase constants
There is a widespread practice to use constants as aliases for difficult-to-remember values that are known prior to execution.
Such constants are named using capital letters and underscores.
For instance, let's make constants for hexadecimal color codes (these codes are used in web programming and other areas):
```js run
const COLOR_RED = "#F00";
const COLOR_GREEN = "#0F0";
const COLOR_BLUE = "#00F";
const COLOR_ORANGE = "#FF7F00";
// ...when we need to pick a color:
let color = COLOR_ORANGE; // (instead of the hexadecimal code)
console.log(color); // #FF7F00
```
Benefits:
- `COLOR_ORANGE` is much easier to remember than `"#FF7F00"`.
- It is much easier to mistype `"#FF7F00"` than `COLOR_ORANGE`, so it's also more reliable.
- When reading the code, `COLOR_ORANGE` is much more meaningful than `#FF7F00`.
When should we use capitals for a constant and when should we name it normally? Let's make that clear.
Being a "constant" just means that a variable's value never changes. But there are constants that are known prior to execution (like a hexadecimal value for the orange color) and there are constants that are *calculated* in run-time, during the execution, but do not change after their initial assignment.
For instance:
```js
const currentDate = /* assign the current date here */;
```
The value of `currentDate` is a constant because it doesn't change after assignment, but it may differ from day to day. So it's lowercased.
In other words, capital-named constants are only used as aliases for "hard-coded" values, known prior to execution.
## Name things right
Talking about variables, there's one more extremely important thing.
A variable name should have a clean, obvious meaning, describing the data that it stores.
Variable naming is one of the most important and complex skills in programming. A quick glance at variable names can reveal which code was written by a beginner versus an experienced developer.
In a real project, most of the time is spent modifying and extending an existing code base rather than writing something completely new from scratch. When we look at someone else's code, and even if we return to our code after a while, it's much easier to find information that is well-labeled. Or, in other words, when the variables have good names.
Please spend time thinking about the right name for a variable before declaring it. Doing so will repay you handsomely.
Some good-to-follow rules are:
- Use human-readable names like `userName` or `shoppingCart`.
- Stay away from abbreviations or short names like `a`, `b`, `c`, unless you really know what you're doing.
- Make names maximally descriptive and concise. Examples of bad names are `data` and `value`. Such names say nothing. It's only okay to use them if the context of the code makes it exceptionally obvious which data or value the variable is referencing.
- Agree on terms within your team and in your own mind. If a site visitor is called a "user" then we should name related variables `currentUser` or `newUser` instead of `currentVisitor` or `newManInTown`.
Sounds simple? Indeed it is, but creating descriptive and concise variable names in practice is not. Go for it.
```smart header="Create, don't reuse"
And the last note. There are some lazy programmers who, instead of declaring new variables, tend to reuse existing ones, write new values into them.
As a result, their variables are like boxes into which people throw different things without changing their stickers. What's inside the box now? Who knows? We need to come closer and check.
Such programmers save a little bit when writing code, but lose ten times more when reading it.
An extra variable is good, not evil.
Modern JavaScript tools and browsers optimize code well enough, so it won't create performance issues. Using different variables for different values can even help the engine optimize your code.
```

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="392" height="192" viewBox="0 0 392 192"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="v2" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="variable-change.svg"><g id="noun_1211_cc" transform="translate(52 -5)"><path id="Shape" fill="#E8C48F" d="M25 94.196h112.558v42.95c0 .373-.079.862-.279 1.294-.2.433-16.574 35.56-16.574 35.56v-54.36l16.854-25.444L156 66H43.44L25 94.196zM25 123V95l-15 28"/><g id="Rectangle-5-+-&quot;World!&quot;" transform="translate(0 57)"><path id="Rectangle-5" fill="#FFF9EB" stroke="#8A704D" stroke-width="2" d="M18.861 1.809L2 17.533l53.14 56.986L72 58.794 18.861 1.81z"/><text id="&quot;World!&quot;" fill="#8A704D" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold" transform="rotate(47 40.083 39.762)"><tspan x="10.591" y="46.262">&quot;World!&quot;</tspan></text></g><g id="Rectangle-5-+-&quot;World!&quot;-2" transform="rotate(-67 96.824 -33.912)"><path id="Rectangle-5" fill="#FFF9EB" stroke="#8A704D" stroke-width="2" d="M18.861 1.809L2 17.533l53.14 56.986L72 58.794 18.861 1.81z"/><text id="&quot;Hello!&quot;" fill="#8A704D" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold" transform="rotate(47 40.083 39.762)"><tspan x="10.591" y="46.262">&quot;Hello!&quot;</tspan></text></g><path id="Shape" fill="#E8C48F" d="M8 125v54.73c0 3.42 1.484 5.27 4.387 5.27h100.086c3.122 0 5.527-2.548 5.527-3.476V125H8z"/></g><text id="message" fill="#FFF" font-family="OpenSans-Bold, Open Sans" font-size="18" font-weight="bold"><tspan x="77" y="157">message</tspan></text><path id="Fill-54" fill="#E8C48F" d="M58.112 51.808S47.657 40.623 40.719 36.155l-.505 5.542a76.036 76.036 0 00-33.769 4.595l4.169 11.032a64.248 64.248 0 0128.531-3.882l-.505 5.542c5.581-3.329 19.472-7.176 19.472-7.176" transform="rotate(11 32.278 47.57)"/><path id="Fill-54" fill="#E8C48F" d="M287.797 28.186s-10.454-11.185-17.393-15.653l-.505 5.541a76.036 76.036 0 00-33.769 4.596l4.169 11.032a64.248 64.248 0 0128.531-3.882l-.504 5.541c5.58-3.328 19.47-7.175 19.47-7.175" transform="rotate(2 261.964 23.947)"/><g id="noun_48910_cc" transform="translate(298 5)"><path id="Shape" d="M50.983 6H36.016C35.456 6 35 6.626 35 7.395V12h17V7.395C52 6.626 51.543 6 50.983 6z"/><path id="Shape" fill="#E8C48F" d="M84.193 9.36h-26.39V6.085C57.803 2.729 54.99 0 51.528 0H36.47c-3.46 0-6.275 2.729-6.275 6.085V9.36H3.807C1.705 9.36 0 11.012 0 13.05v.26C0 15.348 1.705 17 3.807 17h80.386C86.295 17 88 15.348 88 13.31v-.26c0-2.038-1.706-3.69-3.807-3.69zM53 12H36V7.395C36 6.626 36.457 6 37.016 6h14.968C52.544 6 53 6.626 53 7.395V12zM74.955 20.045H8.044c-3.89 0-7.044-.68-7.044 3.266l5.282 78.382c0 3.943 3.155 7.307 7.045 7.307h56.347c3.89 0 7.044-3.364 7.044-7.307L82 23.31c-.001-3.947-3.155-3.266-7.045-3.266zM26.757 98.999c-1.283.039-2.353-.8-2.396-1.878l-2.36-61.095c-.041-1.078.964-1.985 2.242-2.025 1.283-.04 2.353.801 2.396 1.879l2.36 61.096c.041 1.076-.963 1.984-2.242 2.023zM43 97.049C43 98.126 42.328 99 41.5 99s-1.5-.876-1.5-1.951V35.95c0-1.078.672-1.951 1.5-1.951s1.5.873 1.5 1.951V97.05zm18.639.072c-.042 1.078-1.113 1.917-2.396 1.878-1.28-.04-2.283-.947-2.242-2.024l2.36-61.095c.042-1.078 1.112-1.919 2.394-1.879 1.28.042 2.285.947 2.244 2.025l-2.36 61.095z"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="359" height="143" viewBox="0 0 359 143"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="v2" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="variable-copy-value.svg"><g id="noun_1211_cc-+-Message" transform="translate(11 6)"><g id="noun_1211_cc"><path id="Shape" fill="#E8C48F" d="M17 37.196h112.558v42.95c0 .373-.079.862-.279 1.294-.2.433-16.574 35.56-16.574 35.56V62.64l16.854-25.444L148 9H35.44L17 37.196zM17 66V38L2 66"/><g id="Rectangle-5-+-&quot;World!&quot;" transform="translate(15)"><path id="Rectangle-5" fill="#FFF9EB" stroke="#8A704D" stroke-width="2" d="M18.861 1.809L2 17.533l53.14 56.986L72 58.794 18.861 1.81z"/><text id="&quot;Hello!&quot;" fill="#8A704D" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold" transform="rotate(47 38.202 38.946)"><tspan x="2.822" y="43.482">&quot;Hello!&quot;</tspan></text></g><path id="Shape" fill="#E8C48F" d="M0 68v54.73c0 3.42 1.484 5.27 4.387 5.27h100.086c3.122 0 5.527-2.548 5.527-3.476V68H0z"/></g><text id="message" fill="#FFF" font-family="OpenSans-Bold, Open Sans" font-size="18" font-weight="bold"><tspan x="17" y="105">message</tspan></text></g><g id="Group" transform="translate(210 6)"><path id="Shape" fill="#E8C48F" d="M17 37.196h113.417v42.95c0 .373-.08.862-.28 1.294-.202.433-16.702 35.56-16.702 35.56V62.64l16.983-25.444L149 9H35.582L17 37.196z"/><path id="Shape" fill="#E8C48F" d="M18 66V38L2 66"/><g id="Rectangle-5-+-&quot;World!&quot;" transform="translate(15)"><path id="Rectangle-5" fill="#FFF9EB" stroke="#8A704D" stroke-width="2" d="M19.117 1.8l-17.1 15.734 53.866 56.994 17.1-15.734L19.118 1.799z"/><text id="&quot;Hello!&quot;" fill="#8A704D" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold" transform="rotate(47 38.162 37.693)"><tspan x="2.782" y="42.23">&quot;Hello!&quot;</tspan></text></g><path id="Shape" fill="#E8C48F" d="M0 68v54.73c0 3.42 1.497 5.27 4.427 5.27h100.996c3.15 0 5.577-2.548 5.577-3.476V68H0z"/><text id="hello" fill="#FFF" font-family="OpenSans-Bold, Open Sans" font-size="18" font-weight="bold"><tspan x="25" y="105">hello</tspan></text></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="166" height="145" viewBox="0 0 166 145"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="v2" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="variable.svg"><g id="noun_1211_cc-+-Message" transform="translate(13 3)"><g id="noun_1211_cc"><path id="Shape" fill="#E8C48F" d="M17 37.196h112.558v42.95c0 .373-.079.862-.279 1.294-.2.433-16.574 35.56-16.574 35.56V62.64l16.854-25.444L148 9H35.44L17 37.196zM17 66V38L2 66"/><g id="Rectangle-5-+-&quot;World!&quot;" transform="translate(15)"><path id="Rectangle-5" fill="#FFF9EB" stroke="#8A704D" stroke-width="2" d="M18.861 1.809L2 17.533l53.14 56.986L72 58.794 18.861 1.81z"/><text id="&quot;Hello!&quot;" fill="#8A704D" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold" transform="rotate(47 40.083 39.762)"><tspan x="10.591" y="46.262">&quot;Hello!&quot;</tspan></text></g><path id="Shape" fill="#E8C48F" d="M0 68v54.73c0 3.42 1.484 5.27 4.387 5.27h100.086c3.122 0 5.527-2.548 5.527-3.476V68H0z"/></g><text id="message" fill="#FFF" font-family="OpenSans-Bold, Open Sans" font-size="18" font-weight="bold"><tspan x="17" y="105">message</tspan></text></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,73 @@
# Strict mode
JavaScript appeared in 1995 as a simple, browser-only language. Then, for a long time, it evolved without compatibility issues. New features were added to the language while old functionality didn't change.
That had the benefit of never breaking existing code. But the downside was that any mistake or an imperfect decision made by JavaScript creators got stuck in the language forever.
This was the case until 2009, when the 5th version of the standard appeared. It added new features to the language and modified some of the existing ones. Also made some syntax more strict.
Now the important part about it.
**To avoid breaking the old code, the newer modifications and restrictions are off by default.**
The good thing is: there aren't many such modifications. Also, newly introduced language features do work. The disabled things are only those that were *changed* in the language in a way that may break the code written before them.
For example, in dark old times JavaScript allowed variables to be assigned without a declaration.
Like this:
```js no-strict
*!*
user = "John";
*/!*
console.log(user); // John
```
As we can see, it should be `let user`. But JavaScript was forgiving.
This feature of the language was frowned upon, because it made code more error-prone.
Imagine, if you have a variable named `user`, and then mistype, e.g. assign to `usr` instead:
```js no-strict
let user;
usr = "John"; // mistype!
// (technically, not an error, a new variable usr is created)
```
After 2009, the language started to protect against such mistypes by requiring all variables to be declared and triggering an error otherwise.
Although, as there were many old scripts, to keep them functioning, this change, along with others, is off by default.
## Use strict
To enable all the modern changes, we need to start a script with a special directive: `"use strict"`.
Like this:
```js
"use strict";
console.log("This script works in the strict mode");
```
Please note: the directive must be at the very top, only comments are allowed above it.
With `"use strict"`, a mistype in the variable name causes an error:
```js no-strict
"use strict";
let user;
usr = "John"; // Error
```
In the future, when we learn some advanced language features (such as classes and modules), you'll see that they enable strict mode automatically. Until then, it's a good rule to start scripts with `"use strict"`.
**Here, in the tutorial, we'll always use strict mode, unless explicitly stated otherwise.**
We're studying modern JavaScript after all. But you'll also see notes about how things work without `use strict`, so that you're aware, just in case you forget to put that directive or meet a script without it.

View file

@ -1,122 +0,0 @@
# An Introduction to JavaScript
Let's see what's so special about JavaScript, what we can achieve with it, and what other technologies play well with it.
## What is JavaScript?
*JavaScript* was initially created to "make web pages alive".
The programs in this language are called *scripts*. They can be written right in a web page's HTML and run automatically as the page loads.
Scripts are provided and executed as plain text. They don't need special preparation or compilation to run.
In this aspect, JavaScript is very different from another language called [Java](https://en.wikipedia.org/wiki/Java_(programming_language)).
```smart header="Why is it called <u>Java</u>Script?"
When JavaScript was created, it initially had another name: "LiveScript". But Java was very popular at that time, so it was decided that positioning a new language as a "younger brother" of Java would help.
But as it evolved, JavaScript became a fully independent language with its own specification called [ECMAScript](http://en.wikipedia.org/wiki/ECMAScript), and now it has no relation to Java at all.
```
Today, JavaScript can execute not only in the browser, but also on the server, or actually on any device that has a special program called [the JavaScript engine](https://en.wikipedia.org/wiki/JavaScript_engine).
The browser has an embedded engine sometimes called a "JavaScript virtual machine".
Different engines have different "codenames". For example:
- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- in Chrome, Opera and Edge.
- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- in Firefox.
- ...There are other codenames like "Chakra" for IE, "JavaScriptCore", "Nitro" and "SquirrelFish" for Safari, etc.
The terms above are good to remember because they are used in developer articles on the internet. We'll use them too. For instance, if "a feature X is supported by V8", then it probably works in Chrome, Opera and Edge.
```smart header="How do engines work?"
Engines are complicated. But the basics are easy.
1. The engine (embedded if it's a browser) reads ("parses") the script.
2. Then it converts ("compiles") the script to machine code.
3. And then the machine code runs, pretty fast.
The engine applies optimizations at each step of the process. It even watches the compiled script as it runs, analyzes the data that flows through it, and further optimizes the machine code based on that knowledge.
```
## What can in-browser JavaScript do?
Modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or the CPU, because it was initially created for browsers which do not require it.
JavaScript's capabilities greatly depend on the environment it's running in. For instance, [Node.js](https://wikipedia.org/wiki/Node.js) supports functions that allow JavaScript to read/write arbitrary files, perform network requests, etc.
In-browser JavaScript can do everything related to webpage manipulation, interaction with the user, and the webserver.
For instance, in-browser JavaScript is able to:
- Add new HTML to the page, change the existing content, modify styles.
- React to user actions, run on mouse clicks, pointer movements, key presses.
- Send requests over the network to remote servers, download and upload files (so-called [AJAX](https://en.wikipedia.org/wiki/Ajax_(programming)) and [COMET](https://en.wikipedia.org/wiki/Comet_(programming)) technologies).
- Get and set cookies, ask questions to the visitor, show messages.
- Remember the data on the client-side ("local storage").
## What CAN'T in-browser JavaScript do?
JavaScript's abilities in the browser are limited to protect the user's safety. The aim is to prevent an evil webpage from accessing private information or harming the user's data.
Examples of such restrictions include:
- JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS functions.
Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like "dropping" a file into a browser window or selecting it via an `<input>` tag.
There are ways to interact with the camera/microphone and other devices, but they require a user's explicit permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the [NSA](https://en.wikipedia.org/wiki/National_Security_Agency).
- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other page if they come from different sites (from a different domain, protocol or port).
This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and must contain special JavaScript code that handles it. We'll cover that in the tutorial.
This limitation is, again, for the user's safety. A page from `http://anysite.com` which a user has opened must not be able to access another browser tab with the URL `http://gmail.com`, for example, and steal information from there.
- JavaScript can easily communicate over the net to the server where the current page came from. But its ability to receive data from other sites/domains is crippled. Though possible, it requires explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's a safety limitation.
![](limitations.svg)
Such limitations do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow plugins/extensions which may ask for extended permissions.
## What makes JavaScript unique?
There are at least *three* great things about JavaScript:
```compare
+ Full integration with HTML/CSS.
+ Simple things are done simply.
+ Supported by all major browsers and enabled by default.
```
JavaScript is the only browser technology that combines these three things.
That's what makes JavaScript unique. That's why it's the most widespread tool for creating browser interfaces.
That said, JavaScript can be used to create servers, mobile applications, etc.
## Languages "over" JavaScript
The syntax of JavaScript does not suit everyone's needs. Different people want different features.
That's to be expected, because projects and requirements are different for everyone.
So, recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run in the browser.
Modern tools make the transpilation very fast and transparent, actually allowing developers to code in another language and auto-converting it "under the hood".
Examples of such languages:
- [CoffeeScript](https://coffeescript.org/) is "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it.
- [TypeScript](https://www.typescriptlang.org/) is concentrated on adding "strict data typing" to simplify the development and support of complex systems. It is developed by Microsoft.
- [Flow](https://flow.org/) also adds data typing, but in a different way. Developed by Facebook.
- [Dart](https://www.dartlang.org/) is a standalone language that has its own engine that runs in non-browser environments (like mobile apps), but also can be transpiled to JavaScript. Developed by Google.
- [Brython](https://brython.info/) is a Python transpiler to JavaScript that enables the writing of applications in pure Python without JavaScript.
- [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) is a modern, concise and safe programming language that can target the browser or Node.
There are more. Of course, even if we use one of these transpiled languages, we should also know JavaScript to really understand what we're doing.
## Summary
- JavaScript was initially created as a browser-only language, but it is now used in many other environments as well.
- Today, JavaScript has a unique position as the most widely-adopted browser language, fully integrated with HTML/CSS.
- There are many languages that get "transpiled" to JavaScript and provide certain features. It is recommended to take a look at them, at least briefly, after mastering JavaScript.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,37 +0,0 @@
# Manuals and specifications
This book is a *tutorial*. It aims to help you gradually learn the language. But once you're familiar with the basics, you'll need other resources.
## Specification
[The ECMA-262 specification](https://www.ecma-international.org/publications/standards/Ecma-262.htm) contains the most in-depth, detailed and formalized information about JavaScript. It defines the language.
But being that formalized, it's difficult to understand at first. So if you need the most trustworthy source of information about the language details, the specification is the right place. But it's not for everyday use.
A new specification version is released every year. Between these releases, the latest specification draft is at <https://tc39.es/ecma262/>.
To read about new bleeding-edge features, including those that are "almost standard" (so-called "stage 3"), see proposals at <https://github.com/tc39/proposals>.
Also, if you're developing for the browser, then there are other specifications covered in the [second part](info:browser-environment) of the tutorial.
## Manuals
- **MDN (Mozilla) JavaScript Reference** is the main manual with examples and other information. It's great to get in-depth information about individual language functions, methods etc.
You can find it at <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference>.
Although, it's often best to use an internet search instead. Just use "MDN [term]" in the query, e.g. <https://google.com/search?q=MDN+parseInt> to search for the `parseInt` function.
## Compatibility tables
JavaScript is a developing language, new features get added regularly.
To see their support among browser-based and other engines, see:
- <https://caniuse.com> - per-feature tables of support, e.g. to see which engines support modern cryptography functions: <https://caniuse.com/#feat=cryptography>.
- <https://kangax.github.io/compat-table> - a table with language features and engines that support those or don't support.
All these resources are useful in real-life development, as they contain valuable information about language details, their support, etc.
Please remember them (or this page) for the cases when you need in-depth information about a particular feature.

View file

@ -1,44 +0,0 @@
# Code editors
A code editor is the place where programmers spend most of their time.
There are two main types of code editors: IDEs and lightweight editors. Many people use one tool of each type.
## IDE
The term [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) (Integrated Development Environment) refers to a powerful editor with many features that usually operates on a "whole project." As the name suggests, it's not just an editor, but a full-scale "development environment."
An IDE loads the project (which can be many files), allows navigation between files, provides autocompletion based on the whole project (not just the open file), and integrates with a version management system (like [git](https://git-scm.com/)), a testing environment, and other "project-level" stuff.
If you haven't selected an IDE yet, consider the following options:
- [Visual Studio Code](https://code.visualstudio.com/) (cross-platform, free).
- [WebStorm](https://www.jetbrains.com/webstorm/) (cross-platform, paid).
For Windows, there's also "Visual Studio", not to be confused with "Visual Studio Code". "Visual Studio" is a paid and mighty Windows-only editor, well-suited for the .NET platform. It's also good at JavaScript. There's also a free version [Visual Studio Community](https://www.visualstudio.com/vs/community/).
Many IDEs are paid, but have a trial period. Their cost is usually negligible compared to a qualified developer's salary, so just choose the best one for you.
## Lightweight editors
"Lightweight editors" are not as powerful as IDEs, but they're fast, elegant and simple.
They are mainly used to open and edit a file instantly.
The main difference between a "lightweight editor" and an "IDE" is that an IDE works on a project-level, so it loads much more data on start, analyzes the project structure if needed and so on. A lightweight editor is much faster if we need only one file.
In practice, lightweight editors may have a lot of plugins including directory-level syntax analyzers and autocompleters, so there's no strict border between a lightweight editor and an IDE.
The following options deserve your attention:
- [Sublime Text](http://www.sublimetext.com) (cross-platform, shareware).
- [Notepad++](https://notepad-plus-plus.org/) (Windows, free).
- [Vim](http://www.vim.org/) and [Emacs](https://www.gnu.org/software/emacs/) are also cool if you know how to use them.
## Let's not argue
The editors in the lists above are those that either I or my friends whom I consider good developers have been using for a long time and are happy with.
There are other great editors in our big world. Please choose the one you like the most.
The choice of an editor, like any other tool, is individual and depends on your projects, habits, and personal preferences.

View file

@ -1,63 +0,0 @@
# Developer console
Code is prone to errors. You will quite likely make errors... Oh, what am I talking about? You are *absolutely* going to make errors, at least if you're a human, not a [robot](https://en.wikipedia.org/wiki/Bender_(Futurama)).
But in the browser, users don't see errors by default. So, if something goes wrong in the script, we won't see what's broken and can't fix it.
To see errors and get a lot of other useful information about scripts, "developer tools" have been embedded in browsers.
Most developers lean towards Chrome or Firefox for development because those browsers have the best developer tools. Other browsers also provide developer tools, sometimes with special features, but are usually playing "catch-up" to Chrome or Firefox. So most developers have a "favorite" browser and switch to others if a problem is browser-specific.
Developer tools are potent; they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands.
## Google Chrome
Open the page [bug.html](bug.html).
There's an error in the JavaScript code on it. It's hidden from a regular visitor's eyes, so let's open developer tools to see it.
Press `key:F12` or, if you're on Mac, then `key:Cmd+Opt+J`.
The developer tools will open on the Console tab by default.
It looks somewhat like this:
![chrome](chrome.png)
The exact look of developer tools depends on your version of Chrome. It changes from time to time but should be similar.
- Here we can see the red-colored error message. In this case, the script contains an unknown "lalala" command.
- On the right, there is a clickable link to the source `bug.html:12` with the line number where the error has occurred.
Below the error message, there is a blue `>` symbol. It marks a "command line" where we can type JavaScript commands. Press `key:Enter` to run them.
Now we can see errors, and that's enough for a start. We'll come back to developer tools later and cover debugging more in-depth in the chapter <info:debugging-chrome>.
```smart header="Multi-line input"
Usually, when we put a line of code into the console, and then press `key:Enter`, it executes.
To insert multiple lines, press `key:Shift+Enter`. This way one can enter long fragments of JavaScript code.
```
## Firefox, Edge, and others
Most other browsers use `key:F12` to open developer tools.
The look & feel of them is quite similar. Once you know how to use one of these tools (you can start with Chrome), you can easily switch to another.
## Safari
Safari (Mac browser, not supported by Windows/Linux) is a little bit special here. We need to enable the "Develop menu" first.
Open Preferences and go to the "Advanced" pane. There's a checkbox at the bottom:
![safari](safari.png)
Now `key:Cmd+Opt+C` can toggle the console. Also, note that the new top menu item named "Develop" has appeared. It has many commands and options.
## Summary
- Developer tools allow us to see errors, run commands, examine variables, and much more.
- They can be opened with `key:F12` for most browsers on Windows. Chrome for Mac needs `key:Cmd+Opt+J`, Safari: `key:Cmd+Opt+C` (need to enable first).
Now we have the environment ready. In the next section, we'll get down to JavaScript.

View file

@ -1,17 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
There is an error in the script on this page.
<script>
lalala
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

View file

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<script>
alert( "I'm JavaScript!" );
</script>
</body>
</html>

View file

@ -1,2 +0,0 @@
[html src="index.html"]

View file

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<script>
alert( "I'm JavaScript!" );
</script>
</body>
</html>

View file

@ -1,12 +0,0 @@
importance: 5
---
# Show an alert
Create a page that shows a message "I'm JavaScript!".
Do it in a sandbox, or on your hard drive, doesn't matter, just ensure that it works.
[demo src="solution"]

View file

@ -1 +0,0 @@
alert("I'm JavaScript!");

View file

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<script src="alert.js"></script>
</body>
</html>

View file

@ -1,8 +0,0 @@
The HTML code:
[html src="index.html"]
For the file `alert.js` in the same folder:
[js src="alert.js"]

View file

@ -1,9 +0,0 @@
importance: 5
---
# Show an alert with an external script
Take the solution of the previous task <info:task/hello-alert>. Modify it by extracting the script content into an external file `alert.js`, residing in the same folder.
Open the page, ensure that the alert works.

View file

@ -1,132 +0,0 @@
# Hello, world!
This part of the tutorial is about core JavaScript, the language itself.
But we need a working environment to run our scripts and, since this book is online, the browser is a good choice. We'll keep the amount of browser-specific commands (like `alert`) to a minimum so that you don't spend time on them if you plan to concentrate on another environment (like Node.js). We'll focus on JavaScript in the browser in the [next part](/ui) of the tutorial.
So first, let's see how we attach a script to a webpage. For server-side environments (like Node.js), you can execute the script with a command like `"node my.js"`.
## The "script" tag
JavaScript programs can be inserted almost anywhere into an HTML document using the `<script>` tag.
For instance:
```html run height=100
<!DOCTYPE HTML>
<html>
<body>
<p>Before the script...</p>
*!*
<script>
alert( 'Hello, world!' );
</script>
*/!*
<p>...After the script.</p>
</body>
</html>
```
```online
You can run the example by clicking the "Play" button in the right-top corner of the box above.
```
The `<script>` tag contains JavaScript code which is automatically executed when the browser processes the tag.
## Modern markup
The `<script>` tag has a few attributes that are rarely used nowadays but can still be found in old code:
The `type` attribute: <code>&lt;script <u>type</u>=...&gt;</code>
: The old HTML standard, HTML4, required a script to have a `type`. Usually it was `type="text/javascript"`. It's not required anymore. Also, the modern HTML standard totally changed the meaning of this attribute. Now, it can be used for JavaScript modules. But that's an advanced topic, we'll talk about modules in another part of the tutorial.
The `language` attribute: <code>&lt;script <u>language</u>=...&gt;</code>
: This attribute was meant to show the language of the script. This attribute no longer makes sense because JavaScript is the default language. There is no need to use it.
Comments before and after scripts.
: In really ancient books and guides, you may find comments inside `<script>` tags, like this:
```html no-beautify
<script type="text/javascript"><!--
...
//--></script>
```
This trick isn't used in modern JavaScript. These comments hide JavaScript code from old browsers that didn't know how to process the `<script>` tag. Since browsers released in the last 15 years don't have this issue, this kind of comment can help you identify really old code.
## External scripts
If we have a lot of JavaScript code, we can put it into a separate file.
Script files are attached to HTML with the `src` attribute:
```html
<script src="/path/to/script.js"></script>
```
Here, `/path/to/script.js` is an absolute path to the script from the site root. One can also provide a relative path from the current page. For instance, `src="script.js"`, just like `src="./script.js"`, would mean a file `"script.js"` in the current folder.
We can give a full URL as well. For instance:
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
```
To attach several scripts, use multiple tags:
```html
<script src="/js/script1.js"></script>
<script src="/js/script2.js"></script>
```
```smart
As a rule, only the simplest scripts are put into HTML. More complex ones reside in separate files.
The benefit of a separate file is that the browser will download it and store it in its [cache](https://en.wikipedia.org/wiki/Web_cache).
Other pages that reference the same script will take it from the cache instead of downloading it, so the file is actually downloaded only once.
That reduces traffic and makes pages faster.
```
````warn header="If `src` is set, the script content is ignored."
A single `<script>` tag can't have both the `src` attribute and code inside.
This won't work:
```html
<script *!*src*/!*="file.js">
alert(1); // the content is ignored, because src is set
</script>
```
We must choose either an external `<script src="…">` or a regular `<script>` with code.
The example above can be split into two scripts to work:
```html
<script src="file.js"></script>
<script>
alert(1);
</script>
```
````
## Summary
- We can use a `<script>` tag to add JavaScript code to a page.
- The `type` and `language` attributes are not required.
- A script in an external file can be inserted with `<script src="path/to/script.js"></script>`.
There is much more to learn about browser scripts and their interaction with the webpage. But let's keep in mind that this part of the tutorial is devoted to the JavaScript language, so we shouldn't distract ourselves with browser-specific implementations of it. We'll be using the browser as a way to run JavaScript, which is very convenient for online reading, but only one of many.

View file

@ -1,155 +0,0 @@
# Code structure
The first thing we'll study is the building blocks of code.
## Statements
Statements are syntax constructs and commands that perform actions.
We've already seen a statement, `alert('Hello, world!')`, which shows the message "Hello, world!".
We can have as many statements in our code as we want. Statements can be separated with a semicolon.
For example, here we split "Hello World" into two alerts:
```js run no-beautify
alert('Hello'); alert('World');
```
Usually, statements are written on separate lines to make the code more readable:
```js run no-beautify
alert('Hello');
alert('World');
```
## Semicolons [#semicolon]
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')
```
Here, JavaScript interprets the line break as an "implicit" semicolon. This is called an [automatic semicolon insertion](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion).
**In most cases, a newline implies a semicolon. But "in most cases" does not mean "always"!**
There are cases when a newline does not mean a semicolon. For example:
```js run no-beautify
alert(3 +
1
+ 2);
```
The code outputs `6` because JavaScript does not insert semicolons here. It is intuitively obvious that if the line ends with a plus `"+"`, then it is an "incomplete expression", so a semicolon there would be incorrect. And in this case, that works as intended.
**But there are situations where JavaScript "fails" to assume a semicolon where it is really needed.**
Errors which occur in such cases are quite hard to find and fix.
````smart header="An example of an error"
If you're curious to see a concrete example of such an error, check this code out:
```js run
alert("Hello");
[1, 2].forEach(alert);
```
No need to think about the meaning of the brackets `[]` and `forEach` yet. We'll study them later. For now, just remember the result of running the code: it shows `Hello`, then `1`, then `2`.
Now let's remove the semicolon after the `alert`:
```js run no-beautify
alert("Hello")
[1, 2].forEach(alert);
```
The difference compared to the code above is only one character: the semicolon at the end of the first line is gone.
If we run this code, only the first `Hello` shows (and there's an error, you may need to open the console to see it). There are no numbers any more.
That's because JavaScript does not assume a semicolon before square brackets `[...]`. So, the code in the last example is treated as a single statement.
Here's how the engine sees it:
```js run no-beautify
alert("Hello")[1, 2].forEach(alert);
```
Looks weird, right? Such merging in this case is just wrong. We need to put a semicolon after `alert` for the code to work correctly.
This can happen in other situations also.
````
We recommend putting semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community. Let's note once again -- *it is possible* to leave out semicolons most of the time. But it's safer -- especially for a beginner -- to use them.
## Comments [#code-comments]
As time goes on, programs become more and more complex. It becomes necessary to add *comments* which describe what the code does and why.
Comments can be put into any place of a script. They don't affect its execution because the engine simply ignores them.
**One-line comments start with two forward slash characters `//`.**
The rest of the line is a comment. It may occupy a full line of its own or follow a statement.
Like here:
```js run
// This comment occupies a line of its own
alert('Hello');
alert('World'); // This comment follows the statement
```
**Multiline comments start with a forward slash and an asterisk <code>/&#42;</code> and end with an asterisk and a forward slash <code>&#42;/</code>.**
Like this:
```js run
/* An example with two messages.
This is a multiline comment.
*/
alert('Hello');
alert('World');
```
The content of comments is ignored, so if we put code inside <code>/&#42; ... &#42;/</code>, it won't execute.
Sometimes it can be handy to temporarily disable a part of code:
```js run
/* Commenting out the code
alert('Hello');
*/
alert('World');
```
```smart header="Use hotkeys!"
In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey). For Mac, try `key:Cmd` instead of `key:Ctrl` and `key:Option` instead of `key:Shift`.
```
````warn header="Nested comments are not supported!"
There may not be `/*...*/` inside another `/*...*/`.
Such code will die with an error:
```js run no-beautify
/*
/* nested comment ?!? */
*/
alert( 'World' );
```
````
Please, don't hesitate to comment your code.
Comments increase the overall code footprint, but that's not a problem at all. There are many tools which minify code before publishing to a production server. They remove comments, so they don't appear in the working scripts. Therefore, comments do not have negative effects on production at all.
Later in the tutorial there will be a chapter <info:code-quality> that also explains how to write better comments.

View file

@ -1,89 +0,0 @@
# The modern mode, "use strict"
For a long time, JavaScript evolved without compatibility issues. New features were added to the language while old functionality didn't change.
That had the benefit of never breaking existing code. But the downside was that any mistake or an imperfect decision made by JavaScript's creators got stuck in the language forever.
This was the case until 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 such modifications are off by default. You need to explicitly enable them with a special directive: `"use strict"`.
## "use strict"
The directive looks like a string: `"use strict"` or `'use strict'`. When it is located at the top of a script, the whole script works the "modern" way.
For example:
```js
"use strict";
// this code works the modern way
...
```
Quite soon we're going to learn functions (a way to group commands), so let's note in advance that `"use strict"` can be put at the beginning of a function. Doing that enables strict mode in that function only. But usually people use it for the whole script.
````warn header="Ensure that \"use strict\" is at the top"
Please make sure that `"use strict"` is at the top of your scripts, otherwise strict mode may not be enabled.
Strict mode isn't enabled here:
```js no-strict
alert("some code");
// "use strict" below is ignored--it must be at the top
"use strict";
// strict mode is not activated
```
Only comments may appear above `"use strict"`.
````
```warn header="There's no way to cancel `use strict`"
There is no directive like `"no use strict"` that reverts the engine to old behavior.
Once we enter strict mode, there's no going back.
```
## Browser console
When you use a [developer console](info:devtools) to run code, please note that it doesn't `use strict` by default.
Sometimes, when `use strict` makes a difference, you'll get incorrect results.
So, how to actually `use strict` in the console?
First, you can try to press `key:Shift+Enter` to input multiple lines, and put `use strict` on top, like this:
```js
'use strict'; <Shift+Enter for a newline>
// ...your code
<Enter to run>
```
It works in most browsers, namely Firefox and Chrome.
If it doesn't, e.g. in an old browser, there's an ugly, but reliable way to ensure `use strict`. Put it inside this kind of wrapper:
```js
(function() {
'use strict';
// ...your code here...
})()
```
## Should we "use strict"?
The question may sound obvious, but it's not so.
One could recommend to start scripts with `"use strict"`... But you know what's cool?
Modern JavaScript supports "classes" and "modules" - advanced language structures (we'll surely get to them), that enable `use strict` automatically. So we don't need to add the `"use strict"` directive, if we use them.
**So, for now `"use strict";` is a welcome guest at the top of your scripts. Later, when your code is all in classes and modules, you may omit it.**
As of now, we've got to know about `use strict` in general.
In the next chapters, as we learn language features, we'll see the differences between the strict and old modes. Luckily, there aren't many and they actually make our lives better.
All examples in this tutorial assume strict mode unless (very rarely) specified otherwise.

View file

@ -1,12 +0,0 @@
In the code below, each line corresponds to the item in the task list.
```js run
let admin, name; // can declare two variables at once
name = "John";
admin = name;
alert( admin ); // "John"
```

View file

@ -1,10 +0,0 @@
importance: 2
---
# Working with variables
1. Declare two variables: `admin` and `name`.
2. Assign the value `"John"` to `name`.
3. Copy the value from `name` to `admin`.
4. Show the value of `admin` using `alert` (must output "John").

View file

@ -1,21 +0,0 @@
## The variable for our planet
That's simple:
```js
let ourPlanetName = "Earth";
```
Note, we could use a shorter name `planet`, but it might not be obvious what planet it refers to. It's nice to be more verbose. At least until the variable isNotTooLong.
## The name of the current visitor
```js
let currentUserName = "John";
```
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. A name with 3 words in it is fine.
And if your editor does not have proper autocompletion, get [a new one](/code-editors).

View file

@ -1,8 +0,0 @@
importance: 3
---
# Giving the right name
1. Create a variable with the name of our planet. How would you name such a variable?
2. Create a variable to store the name of a current visitor to a website. How would you name that variable?

View file

@ -1,5 +0,0 @@
We generally use upper case for constants that are "hard-coded". Or, in other words, when the value is known prior to execution and directly written into the code.
In this code, `birthday` is exactly like that. So we could use the upper case for it.
In contrast, `age` is evaluated in run-time. Today we have one age, a year after we'll have another one. It is constant in a sense that it does not change through the code execution. But it is a bit "less of a constant" than `birthday`: it is calculated, so we should keep the lower case for it.

View file

@ -1,25 +0,0 @@
importance: 4
---
# Uppercase const?
Examine the following code:
```js
const birthday = '18.04.1982';
const age = someCode(birthday);
```
Here we have a constant `birthday` for the date, and also the `age` constant.
The `age` is calculated from `birthday` using `someCode()`, which means a function call that we didn't explain yet (we will soon!), but the details don't matter here, the point is that `age` is calculated somehow based on the `birthday`.
Would it be right to use upper case for `birthday`? For `age`? Or even for both?
```js
const BIRTHDAY = '18.04.1982'; // make birthday uppercase?
const AGE = someCode(BIRTHDAY); // make age uppercase?
```

View file

@ -1,345 +0,0 @@
# Variables
Most of the time, a JavaScript application needs to work with information. Here are two examples:
1. An online shop -- the information might include goods being sold and a shopping cart.
2. A chat application -- the information might include users, messages, and much more.
Variables are used to store this information.
## A variable
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, use the `let` keyword.
The statement below creates (in other words: *declares*) a variable with the name "message":
```js
let message;
```
Now, we can put some data into it by using the assignment operator `=`:
```js
let message;
*!*
message = 'Hello'; // store the string 'Hello' in the variable named message
*/!*
```
The string is now saved into the memory area associated with the variable. We can access it using the variable name:
```js run
let message;
message = 'Hello!';
*!*
alert(message); // shows the variable content
*/!*
```
To be concise, we can combine the variable declaration and assignment into a single line:
```js run
let message = 'Hello!'; // define the variable and assign the value
alert(message); // Hello!
```
We can also declare multiple variables in one line:
```js no-beautify
let user = 'John', age = 25, message = 'Hello';
```
That might seem shorter, but we don't recommend it. For the sake of better readability, please use a single line per variable.
The multiline variant is a bit longer, but easier to read:
```js
let user = 'John';
let age = 25;
let message = 'Hello';
```
Some people also define multiple variables in this multiline style:
```js no-beautify
let user = 'John',
age = 25,
message = 'Hello';
```
...Or even in the "comma-first" style:
```js no-beautify
let user = 'John'
, age = 25
, message = 'Hello';
```
Technically, all these variants do the same thing. So, it's a matter of personal taste and aesthetics.
````smart header="`var` instead of `let`"
In older scripts, you may also find another keyword: `var` instead of `let`:
```js
*!*var*/!* message = 'Hello';
```
The `var` keyword is *almost* the same as `let`. It also declares a variable, but in a slightly different, "old-school" way.
There are subtle differences between `let` and `var`, but they do not matter for us yet. We'll cover them in detail 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 data, with a uniquely-named sticker on it.
For instance, the variable `message` can be imagined as a box labeled `"message"` with the value `"Hello!"` in it:
![](variable.svg)
We can put any value in the box.
We can also change it as many times as we want:
```js run
let message;
message = 'Hello!';
message = 'World!'; // value changed
alert(message);
```
When the value is changed, the old data is removed from the variable:
![](variable-change.svg)
We can also declare two variables and copy data from one into the other.
```js run
let hello = 'Hello world!';
let message;
*!*
// copy 'Hello world' from hello into message
message = hello;
*/!*
// now two variables hold the same data
alert(hello); // Hello world!
alert(message); // Hello world!
```
````warn header="Declaring twice triggers an error"
A variable should be declared only once.
A repeated declaration of the same variable is an error:
```js run
let message = "This";
// repeated 'let' leads to an error
let message = "That"; // SyntaxError: 'message' has already been declared
```
So, we should declare a variable once and then refer to it without `let`.
````
```smart header="Functional languages"
It's interesting to note that there exist [functional](https://en.wikipedia.org/wiki/Functional_programming) programming languages, like [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/) that forbid changing variable values.
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 us to create a new box (declare a new variable). We can't reuse the old one.
Though it may seem a little odd at first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation confers certain benefits. Studying such a language (even if you're not planning to use it soon) is recommended to broaden the mind.
```
## Variable naming [#variable-naming]
There are two limitations on variable names in JavaScript:
1. The name must contain only letters, digits, or the symbols `$` and `_`.
2. The first character must not be a digit.
Examples of valid names:
```js
let userName;
let test123;
```
When the name contains multiple words, [camelCase](https://en.wikipedia.org/wiki/CamelCase) is commonly used. That is: words go one after another, each word except first starting with a capital letter: `myVeryLongName`.
What's interesting -- the dollar sign `'$'` and the underscore `'_'` can also be used in names. They are regular symbols, just like letters, without any special meaning.
These names are valid:
```js run untrusted
let $ = 1; // declared a variable with the name "$"
let _ = 2; // and now a variable with the name "_"
alert($ + _); // 3
```
Examples of incorrect variable names:
```js no-beautify
let 1a; // cannot start with a digit
let my-name; // hyphens '-' aren't allowed in the name
```
```smart header="Case matters"
Variables named `apple` and `APPLE` are two different variables.
```
````smart header="Non-Latin letters are allowed, but not recommended"
It is possible to use any language, including cyrillic letters or even hieroglyphs, like this:
```js
let имя = '...';
let 我 = '...';
```
Technically, there is no error here. Such names are allowed, but there is an international convention to use English in variable names. Even if we're writing a small script, it may have a long life ahead. People from other countries may need to read it some time.
````
````warn header="Reserved names"
There is a [list of reserved words](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords), which cannot be used as variable names because they are used by the language itself.
For example: `let`, `class`, `return`, and `function` are reserved.
The code below gives a syntax error:
```js run no-beautify
let let = 5; // can't name a variable "let", error!
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 without using `let`. This still works now if we don't put `use strict` in our scripts to maintain compatibility with old scripts.
```js run no-strict
// note: no "use strict" in this example
num = 5; // the variable "num" is created if it didn't exist
alert(num); // 5
```
This is a bad practice and would cause an error in strict mode:
```js
"use strict";
*!*
num = 5; // error: num is not defined
*/!*
```
````
## Constants
To declare a constant (unchanging) variable, use `const` instead of `let`:
```js
const myBirthday = '18.04.1982';
```
Variables declared using `const` are called "constants". They cannot be reassigned. An attempt to do so would cause an error:
```js run
const myBirthday = '18.04.1982';
myBirthday = '01.01.2001'; // error, can't reassign the constant!
```
When a programmer is sure that a variable will never change, they can declare it with `const` to guarantee and clearly communicate that fact to everyone.
### Uppercase constants
There is a widespread practice to use constants as aliases for difficult-to-remember values that are known prior to execution.
Such constants are named using capital letters and underscores.
For instance, let's make constants for colors in so-called "web" (hexadecimal) format:
```js run
const COLOR_RED = "#F00";
const COLOR_GREEN = "#0F0";
const COLOR_BLUE = "#00F";
const COLOR_ORANGE = "#FF7F00";
// ...when we need to pick a color
let color = COLOR_ORANGE;
alert(color); // #FF7F00
```
Benefits:
- `COLOR_ORANGE` is much easier to remember than `"#FF7F00"`.
- It is much easier to mistype `"#FF7F00"` than `COLOR_ORANGE`.
- When reading the code, `COLOR_ORANGE` is much more meaningful than `#FF7F00`.
When should we use capitals for a constant and when should we name it normally? Let's make that clear.
Being a "constant" just means that a variable's value never changes. But there are constants that are known prior to execution (like a hexadecimal value for red) and there are constants that are *calculated* in run-time, during the execution, but do not change after their initial assignment.
For instance:
```js
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 extremely important thing.
A variable name should have a clean, obvious meaning, describing the data that it stores.
Variable naming is one of the most important and complex skills in programming. A quick glance at variable names can reveal which code was written by a beginner versus an experienced developer.
In a real project, most of the time is spent modifying and extending an existing code base rather than writing something completely separate from scratch. When we return to some code after doing something else for a while, it's much easier to find information that is well-labeled. Or, in other words, when the variables have good names.
Please spend time thinking about the right name for a variable before declaring it. Doing so will repay you handsomely.
Some good-to-follow rules are:
- Use human-readable names like `userName` or `shoppingCart`.
- Stay away from abbreviations or short names like `a`, `b`, `c`, unless you really know what you're doing.
- Make names maximally descriptive and concise. Examples of bad names are `data` and `value`. Such names say nothing. It's only okay to use them if the context of the code makes it exceptionally obvious which data or value the variable is referencing.
- Agree on terms within your team and in your own mind. If a site visitor is called a "user" then we should name related variables `currentUser` or `newUser` instead of `currentVisitor` or `newManInTown`.
Sounds simple? Indeed it is, but creating descriptive and concise variable names in practice is not. Go for it.
```smart header="Reuse or create?"
And the last note. There are some lazy programmers who, instead of declaring new variables, tend to reuse existing ones.
As a result, their variables are like boxes into which people throw different things without changing their stickers. What's inside the box now? Who knows? We need to come closer and check.
Such programmers save a little bit on variable declaration but lose ten times more on debugging.
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 different values can even help the engine optimize your code.
```
## Summary
We can declare variables to store data by using the `var`, `let`, or `const` keywords.
- `let` -- is a modern variable declaration.
- `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 you need them.
- `const` -- is like `let`, but the value of the variable can't be changed.
Variables should be named in a way that allows us to easily understand what's inside them.

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="392" height="192" viewBox="0 0 392 192"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="variable-change.svg"><g id="noun_1211_cc" transform="translate(52.585 -3.958)"><path id="Shape" fill="#DBAF88" d="M24.415 93.154h112.557v42.95c0 .373-.078.863-.278 1.295-.2.432-16.575 35.56-16.575 35.56v-54.36l16.855-25.445 18.44-28.196H42.856l-18.44 28.196zM24.415 121.958v-28l-15 28"/><g id="Rectangle-5-+-&quot;World!&quot;" transform="translate(0 56.354)"><path id="Rectangle-5" fill="#FBF2EC" stroke="#AF6E24" stroke-width="2" d="M18.276 1.413L71.416 58.4 54.553 74.124 1.413 17.138 18.276 1.413z"/><text id="&quot;World!&quot;" fill="#AF6E24" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold" transform="rotate(47 38.498 40.367)"><tspan x="9.006" y="46.867">&quot;World!&quot;</tspan></text></g><g id="Rectangle-5-+-&quot;World!&quot;-2" transform="rotate(-67 95.75 -34.63)"><path id="Rectangle-5" fill="#FBF2EC" stroke="#AF6E24" stroke-width="2" d="M18.276 1.413L71.416 58.4 54.553 74.124 1.413 17.138 18.276 1.413z"/><text id="&quot;Hello!&quot;" fill="#AF6E24" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold" transform="rotate(47 38.578 39.758)"><tspan x="9.085" y="46.258">&quot;Hello!&quot;</tspan></text></g><path id="Shape" fill="#DBAF88" d="M7.415 123.958v54.73c0 3.42 1.483 5.27 4.387 5.27h100.086c3.122 0 5.527-2.547 5.527-3.475v-56.525h-110z"/></g><text id="message" fill="#FFF" font-family="OpenSans-Bold, Open Sans" font-size="18" font-weight="bold"><tspan x="77" y="157">message</tspan></text><path id="Fill-54" fill="#DBAF88" d="M58.112 51.808S47.657 40.623 40.719 36.155l-.505 5.542a76.036 76.036 0 00-33.769 4.595l4.169 11.032a64.248 64.248 0 0128.531-3.882l-.505 5.542c5.581-3.329 19.472-7.176 19.472-7.176" transform="rotate(11 32.278 47.57)"/><path id="Fill-54" fill="#DBAF88" d="M287.797 28.186s-10.454-11.185-17.393-15.653l-.505 5.541a76.036 76.036 0 00-33.769 4.596l4.169 11.032a64.248 64.248 0 0128.531-3.882l-.504 5.541c5.58-3.328 19.47-7.175 19.47-7.175" transform="rotate(2 261.964 23.947)"/><g id="noun_48910_cc" transform="translate(298 5)"><path id="Shape" d="M50.983 6H36.016C35.456 6 35 6.626 35 7.395V12h17V7.395C52 6.626 51.543 6 50.983 6z"/><path id="Shape" fill="#DBAF88" d="M84.193 9.36h-26.39V6.085C57.803 2.729 54.99 0 51.528 0H36.47c-3.46 0-6.275 2.729-6.275 6.085V9.36H3.807C1.705 9.36 0 11.012 0 13.05v.26C0 15.348 1.705 17 3.807 17h80.386C86.295 17 88 15.348 88 13.31v-.26c0-2.038-1.706-3.69-3.807-3.69zM53 12H36V7.395C36 6.626 36.457 6 37.016 6h14.968C52.544 6 53 6.626 53 7.395V12zM74.955 20.045H8.044c-3.89 0-7.044-.68-7.044 3.266l5.282 78.382c0 3.943 3.155 7.307 7.045 7.307h56.347c3.89 0 7.044-3.364 7.044-7.307L82 23.31c-.001-3.947-3.155-3.266-7.045-3.266zM26.757 98.999c-1.283.039-2.353-.8-2.396-1.878l-2.36-61.095c-.041-1.078.964-1.985 2.242-2.025 1.283-.04 2.353.801 2.396 1.879l2.36 61.096c.041 1.076-.963 1.984-2.242 2.023zM43 97.049C43 98.126 42.328 99 41.5 99s-1.5-.876-1.5-1.951V35.95c0-1.078.672-1.951 1.5-1.951s1.5.873 1.5 1.951V97.05zm18.639.072c-.042 1.078-1.113 1.917-2.396 1.878-1.28-.04-2.283-.947-2.242-2.024l2.36-61.095c.042-1.078 1.112-1.919 2.394-1.879 1.28.042 2.285.947 2.244 2.025l-2.36 61.095z"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="166" height="145" viewBox="0 0 166 145"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="noun_1211_cc-+-Message" transform="translate(13 3)"><g id="noun_1211_cc"><path id="Shape" fill="#DBAF88" d="M17 37.196h112.558v42.95c0 .373-.079.862-.279 1.294-.2.433-16.574 35.56-16.574 35.56V62.64l16.854-25.444L148 9H35.44L17 37.196zM17 66V38L2 66"/><g id="Rectangle-5-+-&quot;World!&quot;" transform="translate(15)"><path id="Rectangle-5" fill="#FBF2EC" stroke="#AF6E24" stroke-width="2" d="M18.861 1.809l53.14 56.985L55.14 74.52 1.999 17.533 18.86 1.81z"/><text id="&quot;Hello!&quot;" fill="#AF6E24" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold" transform="rotate(47 40.083 39.762)"><tspan x="10.591" y="46.262">&quot;Hello!&quot;</tspan></text></g><path id="Shape" fill="#DBAF88" d="M0 68v54.73c0 3.42 1.484 5.27 4.387 5.27h100.086c3.122 0 5.527-2.548 5.527-3.476V68H0z"/></g><text id="message" fill="#FFF" font-family="OpenSans-Bold, Open Sans" font-size="18" font-weight="bold"><tspan x="17" y="105">message</tspan></text></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -46,15 +46,13 @@ Besides regular numbers, there are so-called "special numeric values" which also
alert( "not a number" / 2 ); // NaN, such division is erroneous
```
`NaN` is sticky. Any further mathematical operation on `NaN` returns `NaN`:
`NaN` is sticky. Any further operation on `NaN` returns `NaN`:
```js run
alert( NaN + 1 ); // NaN
alert( 3 * NaN ); // NaN
alert( "not a number" / 2 - 1 ); // NaN
alert( "not a number" / 2 + 5 ); // NaN
```
So, if there's a `NaN` somewhere in a mathematical expression, it propagates to the whole result (there's only one exception to that: `NaN ** 0` is `1`).
So, if there's a `NaN` somewhere in a mathematical expression, it propagates to the whole result.
```smart header="Mathematical operations are safe"
Doing maths is "safe" in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc.
@ -66,22 +64,11 @@ Special numeric values formally belong to the "number" type. Of course they are
We'll see more about working with numbers in the chapter <info:number>.
## BigInt [#bigint-type]
## BigInt
In JavaScript, the "number" type cannot safely represent integer values larger than <code>(2<sup>53</sup>-1)</code> (that's `9007199254740991`), or less than <code>-(2<sup>53</sup>-1)</code> for negatives.
In JavaScript, the "number" type cannot represent integer values larger than <code>(2<sup>53</sup>-1)</code> (that's `9007199254740991`), or less than <code>-(2<sup>53</sup>-1)</code> for negatives. It's a technical limitation caused by their internal representation.
To be really precise, the "number" type can store larger integers (up to <code>1.7976931348623157 * 10<sup>308</sup></code>), but outside of the safe integer range <code>±(2<sup>53</sup>-1)</code> there'll be a precision error, because not all digits fit into the fixed 64-bit storage. So an "approximate" value may be stored.
For example, these two numbers (right above the safe range) are the same:
```js
console.log(9007199254740991 + 1); // 9007199254740992
console.log(9007199254740991 + 2); // 9007199254740992
```
So to say, all odd integers greater than <code>(2<sup>53</sup>-1)</code> can't be stored at all in the "number" type.
For most purposes <code>±(2<sup>53</sup>-1)</code> range is quite enough, but sometimes we need the entire range of really big integers, e.g. for cryptography or microsecond-precision timestamps.
For most purposes that's quite enough, but sometimes we need really big numbers, e.g. for cryptography or microsecond-precision timestamps.
`BigInt` type was recently added to the language to represent integers of arbitrary length.
@ -226,7 +213,14 @@ The `symbol` type is used to create unique identifiers for objects. We have to m
The `typeof` operator returns the type of the argument. It's useful when we want to process values of different types differently or just want to do a quick check.
A call to `typeof x` returns a string with the type name:
It supports two forms of syntax:
1. As an operator: `typeof x`.
2. As a function: `typeof(x)`.
In other words, it works with parentheses or without them. The result is the same.
The call to `typeof x` returns a string with the type name:
```js
typeof undefined // "undefined"
@ -257,37 +251,25 @@ typeof alert // "function" (3)
The last three lines may need additional explanation:
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` is `"object"`. That's an officially recognized error in `typeof`, coming from very early days of JavaScript and kept for compatibility. Definitely, `null` is not an object. It is a special value with a separate type of its own. The behavior of `typeof` is wrong here.
2. The result of `typeof null` is `"object"`. That's an officially recognized error in `typeof` behavior, coming from the early days of JavaScript and kept for compatibility. Definitely, `null` is not an object. It is a special value with a separate type of its own.
3. The result of `typeof alert` is `"function"`, because `alert` is a function. We'll study functions in the next chapters where we'll also see that there's no special "function" type in JavaScript. Functions belong to the object type. But `typeof` treats them differently, returning `"function"`. That also comes from the early days of JavaScript. Technically, such behavior isn't correct, but can be convenient in practice.
```smart header="The `typeof(x)` syntax"
You may also come across another syntax: `typeof(x)`. It's the same as `typeof x`.
To put it clear: `typeof` is an operator, not a function. The parentheses here aren't a part of `typeof`. It's the kind of parentheses used for mathematical grouping.
Usually, such parentheses contain a mathematical expression, such as `(2 + 2)`, but here they contain only one argument `(x)`. Syntactically, they allow to avoid a space between the `typeof` operator and its argument, and some people like it.
Some people prefer `typeof(x)`, although the `typeof x` syntax is much more common.
```
## Summary
There are 8 basic data types in JavaScript.
- Seven primitive data types:
- `number` for numbers of any kind: integer or floating-point, integers are limited by <code>±(2<sup>53</sup>-1)</code>.
- `bigint` for integer numbers of arbitrary length.
- `string` for strings. A string may have zero or 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`.
- `symbol` for unique identifiers.
- And one non-primitive data type:
- `object` for more complex data structures.
- `number` for numbers of any kind: integer or floating-point, integers are limited by <code>±(2<sup>53</sup>-1)</code>.
- `bigint` is for integer numbers of arbitrary length.
- `string` for strings. A string may have zero or 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.
The `typeof` operator allows us to see which type is stored in a variable.
- Usually used as `typeof x`, but `typeof(x)` is also possible.
- Two forms: `typeof x` or `typeof(x)`.
- Returns a string with the name of the type, like `"string"`.
- For `null` returns `"object"` -- this is an error in the language, it's not actually an object.

View file

@ -7,7 +7,7 @@ For example, `alert` automatically converts any value to a string to show it. Ma
There are also cases when we need to explicitly convert a value to the expected type.
```smart header="Not talking about objects yet"
In this chapter, we won't cover objects. For now, we'll just be talking about primitives.
In this chapter, we won't cover objects. For now we'll just be talking about primitives.
Later, after we learn about objects, in the chapter <info:object-toprimitive> we'll see how objects fit in.
```
@ -70,7 +70,7 @@ Numeric conversion rules:
|`undefined`|`NaN`|
|`null`|`0`|
|<code>true&nbsp;and&nbsp;false</code> | `1` and `0` |
| `string` | Whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. |
| `string` | Whitespaces from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. |
Examples:
@ -130,7 +130,7 @@ The conversion follows the rules:
|`undefined`|`NaN`|
|`null`|`0`|
|<code>true&nbsp;/&nbsp;false</code> | `1 / 0` |
| `string` | The string is read "as is", whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. |
| `string` | The string is read "as is", whitespaces from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. |
**`Boolean Conversion`** -- Occurs in logical operations. Can be performed with `Boolean(value)`.

View file

@ -9,6 +9,7 @@ true + false = 1
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
7 / 0 = Infinity
" -9 " + 5 = " -9 5" // (3)
" -9 " - 5 = -14 // (4)
null + 1 = 1 // (5)
@ -22,4 +23,4 @@ undefined + 1 = NaN // (6)
4. The subtraction always converts to numbers, so it makes `" -9 "` a number `-9` (ignoring spaces around it).
5. `null` becomes `0` after the numeric conversion.
6. `undefined` becomes `NaN` after the numeric conversion.
7. Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`.
7. Space characters, are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`.

View file

@ -16,6 +16,7 @@ true + false
"$" + 4 + 5
"4" - 2
"4px" - 2
7 / 0
" -9 " + 5
" -9 " - 5
null + 1

View file

@ -56,21 +56,17 @@ alert( 8 % 3 ); // 2, a remainder of 8 divided by 3
### Exponentiation **
The exponentiation operator `a ** b` raises `a` to the power of `b`.
In school maths, we write that as a<sup>b</sup>.
The exponentiation operator `a ** b` multiplies `a` by itself `b` times.
For instance:
```js run
alert( 2 ** 2 ); // 2² = 4
alert( 2 ** 3 ); // 2³ = 8
alert( 2 ** 4 ); // 2⁴ = 16
alert( 2 ** 2 ); // 4 (2 multiplied by itself 2 times)
alert( 2 ** 3 ); // 8 (2 * 2 * 2, 3 times)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2, 4 times)
```
Just like in maths, the exponentiation operator is defined for non-integer numbers as well.
For example, a square root is an exponentiation by ½:
Mathematically, the exponentiation is defined for non-integer numbers as well. For example, a square root is an exponentiation by `1/2`:
```js run
alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root)
@ -108,12 +104,7 @@ Here's a more complex example:
alert(2 + 2 + '1' ); // "41" and not "221"
```
Here, operators work one after another. The first `+` sums two numbers, so it returns `4`, then the next `+` adds the string `1` to it, so it's like `4 + '1' = '41'`.
```js run
alert('1' + 2 + 2); // "122" and not "14"
```
Here, the first operand is a string, the compiler treats the other two operands as strings too. The `2` gets concatenated to `'1'`, so it's like `'1' + 2 = "12"` and `"12" + 2 = "122"`.
Here, operators work one after another. The first `+` sums two numbers, so it returns `4`, then the next `+` adds the string `1` to it, so it's like `4 + '1' = 41`.
The binary `+` is the only operator that supports strings in such a way. Other arithmetic operators work only with numbers and always convert their operands to numbers.
@ -194,22 +185,22 @@ Here's an extract from the [precedence table](https://developer.mozilla.org/en-U
| Precedence | Name | Sign |
|------------|------|------|
| ... | ... | ... |
| 14 | unary plus | `+` |
| 14 | unary negation | `-` |
| 13 | exponentiation | `**` |
| 12 | multiplication | `*` |
| 12 | division | `/` |
| 11 | addition | `+` |
| 11 | subtraction | `-` |
| 17 | unary plus | `+` |
| 17 | unary negation | `-` |
| 16 | exponentiation | `**` |
| 15 | multiplication | `*` |
| 15 | division | `/` |
| 13 | addition | `+` |
| 13 | subtraction | `-` |
| ... | ... | ... |
| 2 | assignment | `=` |
| 3 | assignment | `=` |
| ... | ... | ... |
As we can see, the "unary plus" has a priority of `14` which is higher than the `11` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition.
As we can see, the "unary plus" has a priority of `17` which is higher than the `13` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition.
## Assignment
Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `2`.
Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `3`.
That's why, when we assign a variable, like `x = 2 * 2 + 1`, the calculations are done first and then the `=` is evaluated, storing the result in `x`.
@ -223,7 +214,7 @@ alert( x ); // 5
The fact of `=` being an operator, not a "magical" language construct has an interesting implication.
All operators in JavaScript return a value. That's obvious for `+` and `-`, but also true for `=`.
Most operators in JavaScript return a value. That's obvious for `+` and `-`, but also true for `=`.
The call `x = value` writes the `value` into `x` *and then returns it*.
@ -303,9 +294,9 @@ Such operators have the same precedence as a normal assignment, so they run afte
```js run
let n = 2;
n *= 3 + 5; // right part evaluated first, same as n *= 8
n *= 3 + 5;
alert( n ); // 16
alert( n ); // 16 (right part evaluated first, same as n *= 8)
```
## Increment/decrement
@ -437,7 +428,7 @@ The list of operators:
- RIGHT SHIFT ( `>>` )
- ZERO-FILL RIGHT SHIFT ( `>>>` )
These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) chapter on MDN when a need arises.
These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise) chapter on MDN when a need arises.
## Comma

View file

@ -7,7 +7,7 @@ In JavaScript they are written like this:
- Greater/less than: <code>a &gt; b</code>, <code>a &lt; b</code>.
- Greater/less than or equals: <code>a &gt;= b</code>, <code>a &lt;= b</code>.
- Equals: `a == b`, please note the double equality sign `==` means the equality test, while a single one `a = b` means an assignment.
- Not equals: In maths the notation is <code>&ne;</code>, but in JavaScript it's written as <code>a != b</code>.
- Not equals. In maths the notation is <code>&ne;</code>, but in JavaScript it's written as <code>a != b</code>.
In this article we'll learn more about different types of comparisons, how JavaScript makes them, including important peculiarities.

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="264" viewBox="0 0 500 264"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="ifelse_task2.svg"><path id="Path-1218-Copy" fill="#C06334" fill-rule="nonzero" d="M425.5 133.5v54h8l-9.5 19-9.5-19h8v-51h-82v-3h85z"/><g id="Rectangle-1-+-Корень" transform="translate(213 4)"><rect id="Rectangle-1" width="78" height="28" x="1" y="1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" rx="14"/><text id="Begin" fill="#AF6E24" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="21" y="19">Begin</tspan></text></g><g id="Rectangle-1-+-Корень-Copy-2" transform="translate(8 206)"><rect id="Rectangle-1" width="131" height="49" x="1" y="1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" rx="24.5"/><text id="You-don't-know?-“ECM" fill="#AF6E24" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="12.937" y="20">You don&apos;t know?</tspan> <tspan x="22.107" y="39">“ECMAScript”!</tspan></text></g><g id="Rectangle-1-+-Корень-Copy-3" transform="translate(354 206)"><rect id="Rectangle-1" width="131" height="49" x="1" y="1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" rx="24.5"/><text id="Right!" fill="#AF6E24" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="47.93" y="28">Right!</tspan></text></g><path id="Line" fill="#C06334" fill-rule="nonzero" d="M255 34v23.049l8 .001-9.5 19-9.5-19 8-.001V34h3z"/><path id="Path-1218" fill="#C06334" fill-rule="nonzero" d="M139.5 133.5v3h-59v51h8l-9.5 19-9.5-19h8v-54h62z"/><path id="Rectangle-356" fill="#FFF" d="M47 152h60v20H47z"/><g id="Rectangle-354-+-Каково-“официальное”" transform="translate(137 76)"><path id="Rectangle-354" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M116.5 1.123L230.801 59.5 116.5 117.877 2.199 59.5 116.5 1.123z"/><text id="What's-the-“official" fill="#AF6E24" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="80.958" y="43">What&apos;s the</tspan> <tspan x="60.214" y="62">“official” name of</tspan> <tspan x="80.77" y="81">JavaScript?</tspan></text></g><text id="Other" fill="#AF6E24" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="57" y="166">Other</tspan></text><path id="Rectangle-356-Copy" fill="#FFF" d="M387 152h60v20h-60z"/><text id="ECMAScript" fill="#AF6E24" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="383" y="165">ECMAScript</tspan></text></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="264" viewBox="0 0 500 264"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="ifelse_task2.svg"><path id="Path-1218-Copy" fill="#EE6B47" fill-rule="nonzero" d="M425.5 133.5v54h8l-9.5 19-9.5-19h8v-51h-82v-3h85z"/><g id="Rectangle-1-+-Корень" transform="translate(213 4)"><rect id="Rectangle-1" width="78" height="28" x="1" y="1" fill="#FFF9EB" stroke="#E8C48E" stroke-width="2" rx="14"/><text id="Begin" fill="#8A704D" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="21" y="19">Begin</tspan></text></g><g id="Rectangle-1-+-Корень-Copy-2" transform="translate(8 206)"><rect id="Rectangle-1" width="131" height="49" x="1" y="1" fill="#FFF9EB" stroke="#E8C48E" stroke-width="2" rx="24.5"/><text id="You-don't-know?-“ECM" fill="#8A704D" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="13.354" y="20">You don&apos;t know?</tspan> <tspan x="21.967" y="39">“ECMAScript”!</tspan></text></g><g id="Rectangle-1-+-Корень-Copy-3" transform="translate(354 206)"><rect id="Rectangle-1" width="131" height="49" x="1" y="1" fill="#FFF9EB" stroke="#E8C48E" stroke-width="2" rx="24.5"/><text id="Right!" fill="#8A704D" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="47.93" y="28">Right!</tspan></text></g><path id="Line" fill="#EE6B47" fill-rule="nonzero" d="M255 34v23.049l8 .001-9.5 19-9.5-19 8-.001V34h3z"/><path id="Path-1218" fill="#EE6B47" fill-rule="nonzero" d="M139.5 133.5v3h-59v51h8l-9.5 19-9.5-19h8v-54h62z"/><path id="Rectangle-356" fill="#FFF" d="M47 152h60v20H47z"/><g id="Rectangle-354-+-Каково-“официальное”" transform="translate(137 76)"><path id="Rectangle-354" fill="#FFF9EB" stroke="#E8C48E" stroke-width="2" d="M2.199 59.5L116.5 117.877 230.801 59.5 116.5 1.123 2.199 59.5z"/><text id="What's-the-“official" fill="#8A704D" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="81.026" y="43">What&apos;s the</tspan> <tspan x="60.635" y="62">“official” name of</tspan> <tspan x="80.77" y="81">JavaScript?</tspan></text></g><text id="Other" fill="#8A704D" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="57" y="166">Other</tspan></text><path id="Rectangle-356-Copy" fill="#FFF" d="M387 152h60v20h-60z"/><text id="ECMAScript" fill="#8A704D" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="383" y="165">ECMAScript</tspan></text></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

View file

@ -6,7 +6,7 @@ importance: 2
Using the `if..else` construct, write the code which asks: 'What is the "official" name of JavaScript?'
If the visitor enters "ECMAScript", then output "Right!", otherwise -- output: "You don't know? ECMAScript!"
If the visitor enters "ECMAScript", then output "Right!", otherwise -- output: "Didn't know? ECMAScript!"
![](ifelse_task2.svg)

View file

@ -68,7 +68,7 @@ if (cond) {
## The "else" clause
The `if` statement may contain an optional "else" block. It executes when the condition is falsy.
The `if` statement may contain an optional "else" block. It executes when the condition is false.
For example:
```js run

View file

@ -1,6 +1,6 @@
The answer: `null`, because it's the first falsy value from the list.
```js run
alert(1 && null && 2);
alert( 1 && null && 2 );
```

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Before After
Before After

View file

@ -1,6 +1,6 @@
# Logical operators
There are four logical operators in JavaScript: `||` (OR), `&&` (AND), `!` (NOT), `??` (Nullish Coalescing). Here we cover the first three, the `??` operator is in the next article.
There are three logical operators in JavaScript: `||` (OR), `&&` (AND), `!` (NOT).
Although they are called "logical", they can be applied to values of any type, not only boolean. Their result can also be of any type.
@ -64,7 +64,7 @@ if (hour < 10 || hour > 18 || isWeekend) {
}
```
## OR "||" finds the first truthy value [#or-finds-the-first-truthy-value]
## OR "||" finds the first truthy value
The logic described above is somewhat classical. Now, let's bring in the "extra" features of JavaScript.
@ -123,7 +123,7 @@ This leads to some interesting usage compared to a "pure, classical, boolean-onl
It means that `||` processes its arguments until the first truthy value is reached, and then the value is returned immediately, without even touching the other argument.
The importance of this feature becomes obvious if an operand isn't just a value, but an expression with a side effect, such as a variable assignment or a function call.
That importance of this feature becomes obvious if an operand isn't just a value, but an expression with a side effect, such as a variable assignment or a function call.
In the example below, only the second message is printed:

View file

@ -2,14 +2,15 @@
[recent browser="new"]
The nullish coalescing operator is written as two question marks `??`.
Here, in this article, we'll say that an expression is "defined" when it's neither `null` nor `undefined`.
As it treats `null` and `undefined` similarly, we'll use a special term here, in this article. For brevity, we'll say that a value is "defined" when it's neither `null` nor `undefined`.
The nullish coalescing operator is written as two question marks `??`.
The result of `a ?? b` is:
- if `a` is defined, then `a`,
- if `a` isn't defined, then `b`.
In other words, `??` returns the first argument if it's not `null/undefined`. Otherwise, the second one.
The nullish coalescing operator isn't anything completely new. It's just a nice syntax to get the first "defined" value of the two.
@ -20,31 +21,29 @@ We can rewrite `result = a ?? b` using the operators that we already know, like
result = (a !== null && a !== undefined) ? a : b;
```
Now it should be absolutely clear what `??` does. Let's see where it helps.
The common use case for `??` is to provide a default value for a potentially undefined variable.
The common use case for `??` is to provide a default value.
For example, here we show `user` if its value isn't `null/undefined`, otherwise `Anonymous`:
For example, here we show `Anonymous` if `user` isn't defined:
```js run
let user;
alert(user ?? "Anonymous"); // Anonymous (user not defined)
alert(user ?? "Anonymous"); // Anonymous
```
Here's the example with `user` assigned to a name:
Of course, if `user` had any value except `null/undefined`, then we would see it instead:
```js run
let user = "John";
alert(user ?? "Anonymous"); // John (user defined)
alert(user ?? "Anonymous"); // John
```
We can also use a sequence of `??` to select the first value from a list that isn't `null/undefined`.
Let's say we have a user's data in variables `firstName`, `lastName` or `nickName`. All of them may be not defined, if the user decided not to fill in the corresponding values.
Let's say we have a user's data in variables `firstName`, `lastName` or `nickName`. All of them may be undefined, if the user decided not to enter a value.
We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are `null/undefined`.
We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are undefined.
Let's use the `??` operator for that:
@ -76,7 +75,7 @@ alert(firstName || lastName || nickName || "Anonymous"); // Supercoder
*/!*
```
Historically, the OR `||` operator was there first. It exists since the beginning of JavaScript, so developers were using it for such purposes for a long time.
The OR `||` operator exists since the beginning of JavaScript, so developers were using it for such purposes for a long time.
On the other hand, the nullish coalescing operator `??` was added to JavaScript only recently, and the reason for that was that people weren't quite happy with `||`.
@ -97,20 +96,18 @@ alert(height || 100); // 100
alert(height ?? 100); // 0
```
- The `height || 100` checks `height` for being a falsy value, and it's `0`, falsy indeed.
- so the result of `||` is the second argument, `100`.
- The `height || 100` checks `height` for being a falsy value, and it really is.
- so the result is the second argument, `100`.
- The `height ?? 100` checks `height` for being `null/undefined`, and it's not,
- so the result is `height` "as is", that is `0`.
In practice, the zero height is often a valid value, that shouldn't be replaced with the default. So `??` does just the right thing.
If the zero height is a valid value, that shouldn't be replaced with the default, then `??` does just the right thing.
## Precedence
The precedence of the `??` operator is the same as `||`. They both equal `3` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table).
The precedence of the `??` operator is rather low: `5` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). So `??` is evaluated before `=` and `?`, but after most other operations, such as `+`, `*`.
That means that, just like `||`, the nullish coalescing operator `??` is evaluated before `=` and `?`, but after most other operations, such as `+`, `*`.
So we may need to add parentheses in expressions like this:
So if we'd like to choose a value with `??` in an expression with other operators, consider adding parentheses:
```js run
let height = null;
@ -128,7 +125,7 @@ Otherwise, if we omit parentheses, then as `*` has the higher precedence than `?
// without parentheses
let area = height ?? 100 * width ?? 50;
// ...works this way (not what we want):
// ...works the same as this (probably not what we want):
let area = height ?? (100 * width) ?? 50;
```
@ -142,7 +139,7 @@ The code below triggers a syntax error:
let x = 1 && 2 ?? 3; // Syntax error
```
The limitation is surely debatable, it was added to the language specification with the purpose to avoid programming mistakes, when people start to switch from `||` to `??`.
The limitation is surely debatable, but it was added to the language specification with the purpose to avoid programming mistakes, when people start to switch to `??` from `||`.
Use explicit parentheses to work around it:

View file

@ -6,19 +6,6 @@ For example, outputting goods from a list one after another or just running the
*Loops* are a way to repeat the same code multiple times.
```smart header="The for..of and for..in loops"
A small announcement for advanced readers.
This article covers only basic loops: `while`, `do..while` and `for(..;..;..)`.
If you came to this article searching for other types of loops, here are the pointers:
- See [for..in](info:object#forin) to loop over object properties.
- See [for..of](info:array#loops) and [iterables](info:iterable) for looping over arrays and iterable objects.
Otherwise, please read on.
```
## The "while" loop
The `while` loop has the following syntax:
@ -119,7 +106,7 @@ Let's examine the `for` statement part-by-part:
| part | | |
|-------|----------|----------------------------------------------------------------------------|
| begin | `let i = 0` | Executes once upon entering the loop. |
| begin | `i = 0` | Executes once upon entering the loop. |
| condition | `i < 3`| Checked before every loop iteration. If false, the loop stops. |
| body | `alert(i)`| Runs again and again while the condition is truthy. |
| step| `i++` | Executes after the body on each iteration. |
@ -175,8 +162,10 @@ for (i = 0; i < 3; i++) { // use an existing variable
alert(i); // 3, visible, because declared outside of the loop
```
````
### Skipping parts
Any part of `for` can be skipped.
@ -279,7 +268,7 @@ for (let i = 0; i < 10; i++) {
From a technical point of view, this is identical to the example above. Surely, we can just wrap the code in an `if` block instead of using `continue`.
But as a side effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of `if` is longer than a few lines, that may decrease the overall readability.
But as a side-effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of `if` is longer than a few lines, that may decrease the overall readability.
````
````warn header="No `break/continue` to the right side of '?'"
@ -297,6 +286,7 @@ if (i > 5) {
...and rewrite it using a question mark:
```js no-beautify
(i > 5) ? alert(i) : *!*continue*/!*; // continue isn't allowed here
```
@ -328,10 +318,9 @@ alert('Done!');
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!
The ordinary `break` after `input` would only break the inner loop. That's not sufficient--labels, come to the rescue!
A *label* is an identifier with a colon before a loop:
```js
labelName: for (...) {
...
@ -353,7 +342,6 @@ The `break <labelName>` statement in the loop below breaks out to the label:
// do something with the value...
}
}
alert('Done!');
```
@ -374,26 +362,13 @@ The `continue` directive can also be used with a label. In this case, code execu
Labels do not allow us to jump into an arbitrary place in the code.
For example, it is impossible to do this:
```js
break label; // jump to the label below (doesn't work)
break label; // doesn't jumps to the label below
label: for (...)
```
A `break` directive must be inside a code block. Technically, any labelled code block will do, e.g.:
```js
label: {
// ...
break label; // works
// ...
}
```
...Although, 99.9% of the time `break` is used inside loops, as we've seen in the examples above.
A `continue` is only possible from inside a loop.
A call to `break/continue` is only possible from inside a loop and the label must be somewhere above the directive.
````
## Summary

View file

@ -47,7 +47,7 @@ switch (a) {
break;
*/!*
case 5:
alert( 'Too big' );
alert( 'Too large' );
break;
default:
alert( "I don't know such values" );
@ -139,7 +139,7 @@ switch (a) {
Now both `3` and `5` show the same message.
The ability to "group" cases is 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 ability to "group" cases is 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`.
## Type matters

View file

@ -1,3 +1 @@
No difference!
In both cases, `return confirm('Did parents allow you?')` executes exactly when the `if` condition is falsy.
No difference.

View file

@ -14,4 +14,4 @@ function checkAge(age) {
}
```
Note that the parentheses around `age > 18` are not required here. They exist for better readability.
Note that the parentheses around `age > 18` are not required here. They exist for better readabilty.

View file

@ -20,11 +20,11 @@ function showMessage() {
}
```
The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above, we'll see examples later) and finally the code of the function, also named "the function body", between curly braces.
The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above) and finally the code of the function, also named "the function body", between curly braces.
```js
function name(parameter1, parameter2, ... parameterN) {
// body
function name(parameters) {
...body...
}
```
@ -137,23 +137,26 @@ It's a good practice to minimize the use of global variables. Modern code has fe
## Parameters
We can pass arbitrary data to functions using parameters.
We can pass arbitrary data to functions using parameters (also called *function arguments*) .
In the example below, the function has two parameters: `from` and `text`.
```js run
function showMessage(*!*from, text*/!*) { // parameters: from, text
function showMessage(*!*from, text*/!*) { // arguments: from, text
alert(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 in lines `(*)` and `(**)`, the given values are copied to local variables `from` and `text`. Then the function uses them.
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
function showMessage(from, text) {
@ -172,21 +175,9 @@ showMessage(from, "Hello"); // *Ann*: Hello
alert( from ); // Ann
```
When a value is passed as a function parameter, it's also called an *argument*.
In other words, to put these terms straight:
- A parameter is the variable listed inside the parentheses in the function declaration (it's a declaration time term).
- An argument is the value that is passed to the function when it is called (it's a call time term).
We declare functions listing their parameters, then call them passing arguments.
In the example above, one might say: "the function `showMessage` is declared with two parameters, then called with two arguments: `from` and `"Hello"`".
## Default values
If a function is called, but an argument is not provided, then the corresponding value becomes `undefined`.
If a parameter is not provided, then its value becomes `undefined`.
For instance, the aforementioned function `showMessage(from, text)` can be called with a single argument:
@ -194,9 +185,9 @@ For instance, the aforementioned function `showMessage(from, text)` can be calle
showMessage("Ann");
```
That's not an error. Such a call would output `"*Ann*: undefined"`. As the value for `text` isn't passed, it becomes `undefined`.
That's not an error. Such a call would output `"*Ann*: undefined"`. There's no `text`, so it's assumed that `text === undefined`.
We can specify the so-called "default" (to use if omitted) value for a parameter in the function declaration, using `=`:
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"*/!*) {
@ -206,13 +197,7 @@ function showMessage(from, *!*text = "no text given"*/!*) {
showMessage("Ann"); // Ann: no text given
```
Now if the `text` parameter is not passed, it will get the value `"no text given"`.
The default value also jumps in if the parameter exists, but strictly equals `undefined`, like this:
```js
showMessage("Ann", undefined); // Ann: no text given
```
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:
@ -226,55 +211,19 @@ function showMessage(from, text = anotherFunction()) {
```smart header="Evaluation of default parameters"
In JavaScript, a default parameter is evaluated every time the function is called without the respective parameter.
In the example above, `anotherFunction()` isn't called at all, if the `text` parameter is provided.
On the other hand, it's independently called every time when `text` is missing.
In the example above, `anotherFunction()` is called every time `showMessage()` is called without the `text` parameter.
```
````smart header="Default parameters in old JavaScript code"
Several years ago, JavaScript didn't support the syntax for default parameters. So people used other ways to specify them.
Nowadays, we can come across them in old scripts.
For example, an explicit check for `undefined`:
```js
function showMessage(from, text) {
*!*
if (text === undefined) {
text = 'no text given';
}
*/!*
alert( from + ": " + text );
}
```
...Or using the `||` operator:
```js
function showMessage(from, text) {
// If the value of text is falsy, assign the default value
// this assumes that text == "" is the same as no text at all
text = text || 'no text given';
...
}
```
````
### Alternative default parameters
Sometimes it makes sense to assign default values for parameters at a later stage after the function declaration.
Sometimes it makes sense to set default values for parameters not in the function declaration, but at a later stage, during its execution.
We can check if the parameter is passed during the function execution, by comparing it with `undefined`:
To check for an omitted parameter, we can compare it with `undefined`:
```js run
function showMessage(text) {
// ...
*!*
if (text === undefined) { // if the parameter is missing
if (text === undefined) {
text = 'empty message';
}
*/!*
@ -288,18 +237,18 @@ showMessage(); // empty message
...Or we could use the `||` operator:
```js
// if text parameter is omitted or "" is passed, set it to 'empty'
function showMessage(text) {
// if text is undefined or otherwise falsy, set it to 'empty'
text = text || 'empty';
...
}
```
Modern JavaScript engines support the [nullish coalescing operator](info:nullish-coalescing-operator) `??`, it's better when most falsy values, such as `0`, should be considered "normal":
Modern JavaScript engines support the [nullish coalescing operator](info:nullish-coalescing-operator) `??`, it's better when falsy values, such as `0`, are considered regular:
```js run
// if there's no "count" parameter, show "unknown"
function showCount(count) {
// if count is undefined or null, show "unknown"
alert(count ?? "unknown");
}
@ -462,7 +411,7 @@ Functions that are used *very often* sometimes have ultrashort names.
For example, the [jQuery](http://jquery.com) framework defines a function with `$`. The [Lodash](http://lodash.com/) library has its core function named `_`.
These are exceptions. Generally function names should be concise and descriptive.
These are exceptions. Generally functions names should be concise and descriptive.
```
## Functions == Comments
@ -528,7 +477,7 @@ function name(parameters, delimited, by, comma) {
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.
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.
Function naming:

View file

@ -12,9 +12,7 @@ function sayHi() {
There is another syntax for creating a function that is called a *Function Expression*.
It allows us to create a new function in the middle of any expression.
For example:
It looks like this:
```js
let sayHi = function() {
@ -22,19 +20,9 @@ let sayHi = function() {
};
```
Here we can see a variable `sayHi` getting a value, the new function, created as `function() { alert("Hello"); }`.
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`.
As the function creation happens in the context of the assignment expression (to the right side of `=`), this is a *Function Expression*.
Please note, there's no name after the `function` keyword. Omitting a name is allowed for Function Expressions.
Here we immediately assign it to the variable, so the meaning of these code samples is the same: "create a function and put it into the variable `sayHi`".
In more advanced situations, that we'll come across later, a function may be created and immediately called or scheduled for a later execution, not stored anywhere, thus remaining anonymous.
## Function is a value
Let's reiterate: no matter how the function is created, a function is a value. Both examples above store a function in the `sayHi` variable.
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`:
@ -75,10 +63,10 @@ Here's what happens above in detail:
2. Line `(2)` copies it into the variable `func`. Please note again: there are no parentheses after `sayHi`. If there were, then `func = sayHi()` would write *the result of the call* `sayHi()` into `func`, not *the function* `sayHi` itself.
3. Now the function can be called as both `sayHi()` and `func()`.
We could also have used a Function Expression to declare `sayHi`, in the first line:
Note that we could also have used a Function Expression to declare `sayHi`, in the first line:
```js
let sayHi = function() { // (1) create
let sayHi = function() {
alert( "Hello" );
};
@ -90,7 +78,7 @@ Everything would work the same.
````smart header="Why is there a semicolon at the end?"
You might wonder, why do Function Expressions have a semicolon `;` at the end, but Function Declarations do not:
You might wonder, why does Function Expression have a semicolon `;` at the end, but Function Declaration does not:
```js
function sayHi() {
@ -102,9 +90,9 @@ let sayHi = function() {
}*!*;*/!*
```
The answer is simple: a Function Expression is created here as `function(…) {…}` inside the assignment statement: `let sayHi = …;`. The semicolon `;` is recommended at the end of the statement, it's not a part of the function syntax.
The semicolon would be there for a simpler assignment, such as `let sayHi = 5;`, and it's also there for a function assignment.
The answer is simple:
- There's no need for `;` at the end of code blocks and syntax structures that use them like `if { ... }`, `for { }`, `function f { }` etc.
- A Function Expression is used inside the statement: `let sayHi = ...;`, as a value. It's not a code block, but rather an assignment. The semicolon `;` is recommended at the end of statements, no matter what the value is. So the semicolon here is not related to the Function Expression itself, it just terminates the statement.
````
## Callback functions
@ -144,13 +132,13 @@ function showCancel() {
ask("Do you agree?", showOk, showCancel);
```
In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such functions usually draw a nice-looking question window. But that's another story.
In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such function usually draws a nice-looking question window. But that's another story.
**The arguments `showOk` and `showCancel` of `ask` are called *callback functions* or just *callbacks*.**
The idea is that we pass a function and expect it to be "called back" later if necessary. In our case, `showOk` becomes the callback for "yes" answer, and `showCancel` for "no" answer.
We can use Function Expressions to write an equivalent, shorter function:
We can use Function Expressions to write the same function much shorter:
```js run no-beautify
function ask(question, yes, no) {
@ -186,7 +174,7 @@ Let's formulate the key differences between Function Declarations and Expression
First, the syntax: how to differentiate between them in the code.
- *Function Declaration:* a function, declared as a separate statement, in the main code flow:
- *Function Declaration:* a function, declared as a separate statement, in the main code flow.
```js
// Function Declaration
@ -194,7 +182,7 @@ First, the syntax: how to differentiate between them in the code.
return a + b;
}
```
- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created on the right side of the "assignment expression" `=`:
- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created at the right side of the "assignment expression" `=`:
```js
// Function Expression
@ -291,7 +279,7 @@ if (age < 18) {
welcome(); // \ (runs)
*/!*
// |
function welcome() { // |
function welcome() { // |
alert("Hello!"); // | Function Declaration is available
} // | everywhere in the block where it's declared
// |
@ -301,7 +289,7 @@ if (age < 18) {
} else {
function welcome() {
function welcome() {
alert("Greetings!");
}
}
@ -360,7 +348,7 @@ welcome(); // ok now
```smart header="When to choose Function Declaration versus Function Expression?"
As a rule of thumb, when we need to declare a function, the first thing to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
As a rule of thumb, when we need to declare a function, the first to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
That's also better for readability, as it's easier to look up `function f(…) {…}` in the code than `let f = function(…) {…};`. Function Declarations are more "eye-catching".

View file

@ -1,7 +1,7 @@
```js run
function ask(question, yes, no) {
if (confirm(question)) yes();
if (confirm(question)) yes()
else no();
}

View file

@ -5,7 +5,7 @@ Replace Function Expressions with arrow functions in the code below:
```js run
function ask(question, yes, no) {
if (confirm(question)) yes();
if (confirm(question)) yes()
else no();
}

View file

@ -5,15 +5,15 @@ There's another very simple and concise syntax for creating functions, that's of
It's called "arrow functions", because it looks like this:
```js
let func = (arg1, arg2, ..., argN) => expression;
let func = (arg1, arg2, ...argN) => expression
```
This creates a function `func` that accepts arguments `arg1..argN`, then evaluates the `expression` on the right side with their use and returns its result.
...This creates a function `func` that accepts arguments `arg1..argN`, then evaluates the `expression` on the right side with their use and returns its result.
In other words, it's the shorter version of:
```js
let func = function(arg1, arg2, ..., argN) {
let func = function(arg1, arg2, ...argN) {
return expression;
};
```
@ -33,7 +33,7 @@ let sum = function(a, b) {
alert( sum(1, 2) ); // 3
```
As you can see, `(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result.
As you can, see `(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result.
- If we have only one argument, then parentheses around parameters can be omitted, making that even shorter.
@ -48,7 +48,7 @@ As you can see, `(a, b) => a + b` means a function that accepts two arguments na
alert( double(3) ); // 6
```
- If there are no arguments, parentheses are empty, but they must be present:
- If there are no arguments, parentheses will be empty (but they should be present):
```js run
let sayHi = () => alert("Hello!");
@ -64,7 +64,7 @@ For instance, to dynamically create a function:
let age = prompt("What is your age?", 18);
let welcome = (age < 18) ?
() => alert('Hello!') :
() => alert('Hello') :
() => alert("Greetings!");
welcome();
@ -76,9 +76,9 @@ They are very convenient for simple one-line actions, when we're just too lazy t
## Multiline arrow functions
The arrow functions that we've seen so far were very simple. They took arguments from the left of `=>`, evaluated and returned the right-side expression with them.
The examples above took arguments from the left of `=>` and evaluated the right-side expression with them.
Sometimes we need a more complex function, with multiple expressions and statements. In that case, we can enclose them in curly braces. The major difference is that curly braces require a `return` within them to return a value (just like a regular function does).
Sometimes we need something a little bit more complex, like multiple expressions or statements. It is also possible, but we should enclose them in curly braces. Then use a normal `return` within them.
Like this:
@ -86,7 +86,7 @@ Like this:
let sum = (a, b) => { // the curly brace opens a multiline function
let result = a + b;
*!*
return result; // if we use curly braces, then we need an explicit "return"
return result; // if we use curly braces, then we need an explicit "return"
*/!*
};
@ -105,7 +105,7 @@ For now, we can already use arrow functions for one-line actions and callbacks.
## Summary
Arrow functions are handy for simple actions, especially for one-liners. They come in two flavors:
Arrow functions are handy for one-liners. They come in two flavors:
1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result. Parentheses can be omitted, if there's only a single argument, e.g. `n => n*2`.
1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result.
2. With curly braces: `(...args) => { body }` -- brackets allow us to write multiple statements inside the function, but we need an explicit `return` to return something.

View file

@ -55,7 +55,7 @@ To fully enable all features of modern JavaScript, we should start scripts with
The directive must be at the top of a script or at the beginning of a function body.
Without `"use strict"`, everything still works, but some features behave in the old-fashioned, "compatible" way. We'd generally prefer the modern behavior.
Without `"use strict"`, everything still works, but some features behave in the old-fashion, "compatible" way. We'd generally prefer the modern behavior.
Some modern features of the language (like classes that we'll study in the future) enable strict mode implicitly.
@ -144,7 +144,7 @@ Assignments
: There is a simple assignment: `a = b` and combined ones like `a *= 2`.
Bitwise
: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](mdn:/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) when they are needed.
: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](mdn:/JavaScript/Reference/Operators/Bitwise_Operators) when they are needed.
Conditional
: The only operator with three parameters: `cond ? resultA : resultB`. If `cond` is truthy, returns `resultA`, otherwise `resultB`.
@ -256,7 +256,7 @@ We covered three ways to create a function in JavaScript:
3. Arrow functions:
```js
// expression on the right side
// expression at the right side
let sum = (a, b) => a + b;
// or multi-line syntax with { ... }, need return here:
@ -273,7 +273,7 @@ We covered three ways to create a function in JavaScript:
```
- Functions may have local variables: those declared inside its body or its parameter list. Such variables are only visible inside the function.
- Functions may have local variables: those declared inside its body. Such variables are only visible inside the function.
- Parameters can have default values: `function sum(a = 1, b = 2) {...}`.
- Functions always return something. If there's no `return` statement, then the result is `undefined`.

View file

@ -1,4 +1,4 @@
# Debugging in the browser
# Debugging in Chrome
Before writing more complex code, let's talk about debugging.
@ -38,7 +38,7 @@ If we press `key:Esc`, then a console opens below. We can type commands there an
After a statement is executed, its result is shown below.
For example, here `1+2` results in `3`, while the function call `hello("debugger")` returns nothing, so the result is `undefined`:
For example, here `1+2` results in `3`, and `hello("debugger")` returns nothing, so the result is `undefined`:
![](chrome-sources-console.svg)
@ -63,12 +63,12 @@ We can always find a list of breakpoints in the right panel. That's useful when
- ...And so on.
```smart header="Conditional breakpoints"
*Right click* on the line number allows to create a *conditional* breakpoint. It only triggers when the given expression, that you should provide when you create it, is truthy.
*Right click* on the line number allows to create a *conditional* breakpoint. It only triggers when the given expression is truthy.
That's handy when we need to stop only for a certain variable value or for certain function parameters.
```
## The command "debugger"
## Debugger command
We can also pause the code by using the `debugger` command in it, like this:
@ -84,7 +84,8 @@ function hello(name) {
}
```
Such command works only when the development tools are open, otherwise the browser ignores it.
That's very convenient when we are in a code editor and don't want to switch to the browser and look up the script in developer tools to set the breakpoint.
## Pause and look around
@ -98,7 +99,7 @@ Please open the informational dropdowns to the right (labeled with arrows). They
1. **`Watch` -- shows current values for any expressions.**
You can click the plus `+` and input an expression. The debugger will show its value, automatically recalculating it in the process of execution.
You can click the plus `+` and input an expression. The debugger will show its value at any moment, automatically recalculating it in the process of execution.
2. **`Call Stack` -- shows the nested calls chain.**
@ -134,11 +135,11 @@ There are buttons for it at the top of the right panel. Let's engage them.
Clicking this again and again will step through all script statements one by one.
<span class="devtools" style="background-position:-62px -192px"></span> -- "Step over": run the next command, but *don't go into a function*, hotkey `key:F10`.
: Similar to the previous "Step" command, but behaves differently if the next statement is a function call (not a built-in, like `alert`, but a function of our own).
: Similar to the previous the "Step" command, but behaves differently if the next statement is a function call. That is: not a built-in, like `alert`, but a function of our own.
If we compare them, the "Step" command goes into a nested function call and pauses the execution at its first line, while "Step over" executes the nested function call invisibly to us, skipping the function internals.
The "Step" command goes into it and pauses the execution at its first line, while "Step over" executes the nested function call invisibly, skipping the function internals.
The execution is then paused immediately after that function call.
The execution is then paused immediately after that function.
That's good if we're not interested to see what happens inside the function call.
@ -154,7 +155,7 @@ There are buttons for it at the top of the right panel. Let's engage them.
: That button does not move the execution. Just a mass on/off for breakpoints.
<span class="devtools" style="background-position:-90px -146px"></span> -- enable/disable automatic pause in case of an error.
: When enabled, if the developer tools is open, an error during the script execution automatically pauses it. Then we can analyze variables in the debugger to see what went wrong. So if our script dies with an error, we can open debugger, enable this option and reload the page to see where it dies and what's the context at that moment.
: When enabled, and the developer tools is open, a script error automatically pauses the execution. Then we can analyze variables to see what went wrong. So if our script dies with an error, we can open debugger, enable this option and reload the page to see where it dies and what's the context at that moment.
```smart header="Continue to here"
Right click on a line of code opens the context menu with a great option called "Continue to here".
@ -186,7 +187,7 @@ As we can see, there are three main ways to pause a script:
2. The `debugger` statements.
3. An error (if dev tools are open and the button <span class="devtools" style="background-position:-90px -146px"></span> is "on").
When paused, we can debug: examine variables and trace the code to see where the execution goes wrong.
When paused, we can debug - examine variables and trace the code to see where the execution goes wrong.
There are many more options in developer tools than covered here. The full manual is at <https://developers.google.com/web/tools/chrome-devtools>.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 172 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Before After
Before After

View file

@ -116,7 +116,7 @@ There are two types of indents:
One advantage of spaces over tabs is that spaces allow more flexible configurations of indents than the tab symbol.
For instance, we can align the parameters with the opening bracket, like this:
For instance, we can align the arguments with the opening bracket, like this:
```js no-beautify
show(parameters,
@ -301,11 +301,11 @@ The great thing about them is that style-checking can also find some bugs, like
Here are some well-known linting tools:
- [JSLint](https://www.jslint.com/) -- one of the first linters.
- [JSHint](https://jshint.com/) -- more settings than JSLint.
- [ESLint](https://eslint.org/) -- probably the newest one.
- [JSLint](http://www.jslint.com/) -- one of the first linters.
- [JSHint](http://www.jshint.com/) -- more settings than JSLint.
- [ESLint](http://eslint.org/) -- probably the newest one.
All of them can do the job. The author uses [ESLint](https://eslint.org/).
All of them can do the job. The author uses [ESLint](http://eslint.org/).
Most linters are integrated with many popular editors: just enable the plugin in the editor and configure the style.
@ -328,14 +328,14 @@ Here's an example of an `.eslintrc` file:
},
"rules": {
"no-console": 0,
"indent": 2
"indent": ["warning", 2]
}
}
```
Here the directive `"extends"` denotes that the configuration is based on the "eslint:recommended" set of settings. After that, we specify our own.
It is also possible to download style rule sets from the web and extend them instead. See <https://eslint.org/docs/user-guide/getting-started> for more details about installation.
It is also possible to download style rule sets from the web and extend them instead. See <http://eslint.org/docs/user-guide/getting-started> for more details about installation.
Also certain IDEs have built-in linting, which is convenient but not as customizable as ESLint.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Before After
Before After

View file

@ -143,7 +143,7 @@ Such comments allow us to understand the purpose of the function and use it the
By the way, many editors like [WebStorm](https://www.jetbrains.com/webstorm/) can understand them as well and use them to provide autocomplete and some automatic code-checking.
Also, there are tools like [JSDoc 3](https://github.com/jsdoc/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at <https://jsdoc.app>.
Also, there are tools like [JSDoc 3](https://github.com/jsdoc3/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at <http://usejsdoc.org/>.
Why is the task solved this way?
: What's written is important. But what's *not* written may be even more important to understand what's going on. Why is the task solved exactly this way? The code gives no answer.

View file

@ -2,7 +2,7 @@
Automated testing will be used in further tasks, and it's also widely used in real projects.
## Why do we need tests?
## Why we need tests?
When we write a function, we can usually imagine what it should do: which parameters give which results.
@ -51,7 +51,7 @@ describe("pow", function() {
A spec has three main building blocks that you can see above:
`describe("title", function() { ... })`
: What functionality we're describing? In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks.
: What functionality we're describing. In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks.
`it("use case description", function() { ... })`
: In the title of `it` we *in a human-readable way* describe the particular use case, and the second argument is a function that tests it.
@ -79,7 +79,7 @@ So, the development is *iterative*. We write the spec, implement it, make sure t
Let's see this development flow in our practical case.
The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use a few JavaScript libraries to run the tests, just to see that they are working (they will all fail).
The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use few JavaScript libraries to run the tests, just to see that they are working (they will all fail).
## The spec in action

View file

@ -1,92 +1,54 @@
# Polyfills and transpilers
# Polyfills
The JavaScript language steadily evolves. New proposals to the language appear regularly, they are analyzed and, if considered worthy, are appended to the list at <https://tc39.github.io/ecma262/> and then progress to the [specification](http://www.ecma-international.org/publications/standards/Ecma-262.htm).
Teams behind JavaScript engines have their own ideas about what to implement first. They may decide to implement proposals that are in draft and postpone things that are already in the spec, because they are less interesting or just harder to do.
So it's quite common for an engine to implement only part of the standard.
So it's quite common for an engine to implement only the part of the standard.
A good page to see the current state of support for language features is <https://kangax.github.io/compat-table/es6/> (it's big, we have a lot to study yet).
As programmers, we'd like to use most recent features. The more good stuff - the better!
## Babel
On the other hand, how to make our modern code work on older engines that don't understand recent features yet?
When we use modern features of the language, some engines may fail to support such code. Just as said, not all features are implemented everywhere.
There are two tools for that:
Here Babel comes to the rescue.
1. Transpilers.
2. Polyfills.
[Babel](https://babeljs.io) is a [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler). It rewrites modern JavaScript code into the previous standard.
Here, in this chapter, our purpose is to get the gist of how they work, and their place in web development.
Actually, there are two parts in Babel:
## Transpilers
1. First, the transpiler program, which rewrites the code. The developer runs it on their own computer. It rewrites the code into the older standard. And then the code is delivered to the website for users. Modern project build systems like [webpack](http://webpack.github.io/) provide means to run transpiler automatically on every code change, so that it's very easy to integrate into development process.
A [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler) is a special piece of software that translates source code to another source code. It can parse ("read and understand") modern code and rewrite it using older syntax constructs, so that it'll also work in outdated engines.
2. Second, the polyfill.
E.g. JavaScript before year 2020 didn't have the "nullish coalescing operator" `??`. So, if a visitor uses an outdated browser, it may fail to understand the code like `height = height ?? 100`.
New language features may include new built-in functions and syntax constructs.
The transpiler rewrites the code, transforming syntax constructs into older ones. But as for new built-in functions, we need to implement them. JavaScript is a highly dynamic language, scripts may add/modify any functions, so that they behave according to the modern standard.
A transpiler would analyze our code and rewrite `height ?? 100` into `(height !== undefined && height !== null) ? height : 100`.
A script that updates/adds new functions is called "polyfill". It "fills in" the gap and adds missing implementations.
```js
// before running the transpiler
height = height ?? 100;
Two interesting polyfills are:
- [core js](https://github.com/zloirock/core-js) that supports a lot, allows to include only needed features.
- [polyfill.io](http://polyfill.io) service that provides a script with polyfills, depending on the features and user's browser.
// after running the transpiler
height = (height !== undefined && height !== null) ? height : 100;
So, if we're going to use modern language features, a transpiler and a polyfill are necessary.
## Examples in the tutorial
````online
Most examples are runnable at-place, like this:
```js run
alert('Press the "Play" button in the upper-right corner to run');
```
Now the rewritten code is suitable for older JavaScript engines.
Examples that use modern JS will work only if your browser supports it.
````
Usually, a developer runs the transpiler on their own computer, and then deploys the transpiled code to the server.
Speaking of names, [Babel](https://babeljs.io) is one of the most prominent transpilers out there.
Modern project build systems, such as [webpack](https://webpack.js.org/), provide a means to run a transpiler automatically on every code change, so it's very easy to integrate into the development process.
## Polyfills
New language features may include not only syntax constructs and operators, but also built-in functions.
For example, `Math.trunc(n)` is a function that "cuts off" the decimal part of a number, e.g `Math.trunc(1.23)` returns `1`.
In some (very outdated) JavaScript engines, there's no `Math.trunc`, so such code will fail.
As we're talking about new functions, not syntax changes, there's no need to transpile anything here. We just need to declare the missing function.
A script that updates/adds new functions is called "polyfill". It "fills in" the gap and adds missing implementations.
For this particular case, the polyfill for `Math.trunc` is a script that implements it, like this:
```js
if (!Math.trunc) { // if no such function
// implement it
Math.trunc = function(number) {
// Math.ceil and Math.floor exist even in ancient JavaScript engines
// they are covered later in the tutorial
return number < 0 ? Math.ceil(number) : Math.floor(number);
};
}
```offline
As you're reading the offline version, in PDF examples are not runnable. In EPUB some of them can run.
```
JavaScript is a highly dynamic language. Scripts may add/modify any function, even built-in ones.
Two interesting polyfill libraries are:
- [core js](https://github.com/zloirock/core-js) that supports a lot, allows to include only needed features.
- [polyfill.io](http://polyfill.io) service that provides a script with polyfills, depending on the features and user's browser.
## Summary
In this chapter we'd like to motivate you to study modern and even "bleeding-edge" language features, even if they aren't yet well-supported by JavaScript engines.
Just don't forget to use a transpiler (if using modern syntax or operators) and polyfills (to add functions that may be missing). They'll ensure that the code works.
For example, later when you're familiar with JavaScript, you can setup a code build system based on [webpack](https://webpack.js.org/) with the [babel-loader](https://github.com/babel/babel-loader) plugin.
Good resources that show the current state of support for various features:
- <https://kangax.github.io/compat-table/es6/> - for pure JavaScript.
- <https://caniuse.com/> - for browser-related functions.
P.S. Google Chrome is usually the most up-to-date with language features, try it if a tutorial demo fails. Most tutorial demos work with any modern browser though.
Google Chrome is usually the most up-to-date with language features, good to run bleeding-edge demos without any transpilers, but other modern browsers also work fine.

View file

@ -2,9 +2,9 @@ importance: 3
---
# Multiply numeric property values by 2
# Multiply numeric properties by 2
Create a function `multiplyNumeric(obj)` that multiplies all numeric property values of `obj` by `2`.
Create a function `multiplyNumeric(obj)` that multiplies all numeric properties of `obj` by `2`.
For instance:

View file

@ -44,7 +44,7 @@ The resulting `user` object can be imagined as a cabinet with two signed files l
![user object](object-user.svg)
We can add, remove and read files from it at any time.
We can add, remove and read files from it any time.
Property values are accessible using the dot notation:
@ -62,7 +62,7 @@ user.isAdmin = true;
![user object 2](object-user-isadmin.svg)
To remove a property, we can use the `delete` operator:
To remove a property, we can use `delete` operator:
```js
delete user.age;
@ -92,6 +92,30 @@ let user = {
```
That is called a "trailing" or "hanging" comma. Makes it easier to add/remove/move around properties, because all lines become alike.
````smart header="Object with const can be changed"
Please note: an object declared as `const` *can* be modified.
For instance:
```js run
const user = {
name: "John"
};
*!*
user.name = "Pete"; // (*)
*/!*
alert(user.name); // Pete
```
It might seem that the line `(*)` would cause an error, but no. The `const` fixes the value of `user`, but not its contents.
The `const` would give an error only if we try to set `user=...` as a whole.
There's another way to make constant object properties, we'll cover it later in the chapter <info:property-descriptors>.
````
## Square brackets
For multiword properties, the dot access doesn't work:
@ -201,13 +225,13 @@ let bag = {
};
```
Square brackets are much more powerful than dot notation. They allow any property names and variables. But they are also more cumbersome to write.
Square brackets are much more powerful than the dot notation. They allow any property names and variables. But they are also more cumbersome to write.
So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets.
## Property value shorthand
In real code, we often use existing variables as values for property names.
In real code we often use existing variables as values for property names.
For instance:
@ -252,7 +276,7 @@ let user = {
## Property names limitations
As we already know, a variable cannot have a name equal to one of the language-reserved words like "for", "let", "return" etc.
As we already know, a variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.
But for an object property, there's no such restriction:
@ -325,7 +349,7 @@ alert( "blabla" in user ); // false, user.blabla doesn't exist
Please note that on the left side of `in` there must be a *property name*. That's usually a quoted string.
If we omit quotes, that means a variable should contain the actual name to be tested. For instance:
If we omit quotes, that means a variable, it should contain the actual name to be tested. For instance:
```js run
let user = { age: 30 };
@ -355,7 +379,7 @@ In the code above, the property `obj.test` technically exists. So the `in` opera
Situations like this happen very rarely, because `undefined` should not be explicitly assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code.
## The "for..in" loop [#forin]
## The "for..in" loop
To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we studied before.
@ -412,7 +436,7 @@ for (let code in codes) {
*/!*
```
The object may be used to suggest a list of options to the user. If we're making a site mainly for a German audience then we probably want `49` to be the first.
The object may be used to suggest a list of options to the user. If we're making a site mainly for German audience then we probably want `49` to be the first.
But if we run the code, we see a totally different picture:
@ -424,10 +448,9 @@ The phone codes go in the ascending sorted order, because they are integers. So
````smart header="Integer properties? What's that?"
The "integer property" term here means a string that can be converted to-and-from an integer without a change.
So, `"49"` is an integer property name, because when it's transformed to an integer number and back, it's still the same. But `"+49"` and `"1.2"` are not:
So, "49" is an integer property name, because when it's transformed to an integer number and back, it's still the same. But "+49" and "1.2" are not:
```js run
// Number(...) explicitly converts to a number
// Math.trunc is a built-in function that removes the decimal part
alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property
alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property
@ -482,7 +505,7 @@ They store properties (key-value pairs), where:
To access a property, we can use:
- The dot notation: `obj.property`.
- Square brackets notation `obj["property"]`. Square brackets allow taking the key from a variable, like `obj[varWithKey]`.
- Square brackets notation `obj["property"]`. Square brackets allow to take the key from a variable, like `obj[varWithKey]`.
Additional operators:
- To delete a property: `delete obj.prop`.

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="173" viewBox="0 0 248 173"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user-delete.svg"><path fill="#FFF" d="M0 0h248v173H0z"/><path id="Rectangle-4-Copy" fill="#DBAF88" stroke="#DBAF88" stroke-width="4" d="M225.063 101l16.667 20H111.27l16.667-20h97.126z" opacity=".5"/><g id="Group-2" transform="translate(141 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="name" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 15.5 42.859)"><tspan x="-1.3" y="47.359">name</tspan></text></g><g id="Group-2-Copy-2" transform="translate(179 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="isAdmin" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 14.5 41.653)"><tspan x="-14.9" y="46.153">isAdmin</tspan></text></g><path id="Rectangle-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="4" d="M109 115h135v50H109z"/><path id="Rectangle-8" stroke="#DBAF88" stroke-width="3" d="M164.5 135.5h25v10h-25z"/><text id="user" fill="#C06334" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="9" y="145">user</tspan></text><path id="Line-8" fill="#C06334" fill-rule="nonzero" d="M75.5 131l19 9.5-19 9.5v-8H49v-3h26.5v-8z"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="173" viewBox="0 0 248 173"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user-delete.svg"><path fill="#FFF" d="M0 0h248v173H0z"/><path id="Rectangle-4-Copy" fill="#D1C4B1" stroke="#D1C4B1" stroke-width="4" d="M127.937 101l-16.667 20h130.46l-16.667-20h-97.126z" opacity=".5"/><g id="Group-2" transform="translate(141 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="name" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 15.5 42.859)"><tspan x="-1.3" y="47.359">name</tspan></text></g><g id="Group-2-Copy-2" transform="translate(179 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="isAdmin" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 14.5 41.653)"><tspan x="-14.9" y="46.153">isAdmin</tspan></text></g><path id="Rectangle-4" fill="#FFF9EB" stroke="#BCA68E" stroke-width="4" d="M109 115h135v50H109z"/><path id="Rectangle-8" stroke="#BCA68E" stroke-width="3" d="M164.5 135.5h25v10h-25z"/><text id="user" fill="#EE6B47" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="9" y="145">user</tspan></text><path id="Line-8" fill="#EE6B47" fill-rule="nonzero" d="M75.5 131l19 9.5-19 9.5v-8H49v-3h26.5v-8z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before After
Before After

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="92" viewBox="0 0 248 92"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user-empty.svg"><path fill="#FFF" d="M0 0h248v92H0z"/><path id="Rectangle-4-Copy" fill="#DBAF88" stroke="#DBAF88" stroke-width="4" d="M221.063 12l16.667 20H107.27l16.667-20h97.126z" opacity=".5"/><path id="Rectangle-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="4" d="M105 26h135v50H105z"/><path id="Rectangle-8" stroke="#DBAF88" stroke-width="3" d="M160.5 46.5h25v10h-25z"/><text id="empty" fill="#7E7C7B" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="151" y="22">empty</tspan></text><text id="user" fill="#C06334" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="4" y="56">user</tspan></text><path id="Line-8" fill="#C06334" fill-rule="nonzero" d="M70.5 42l19 9.5-19 9.5v-8H44v-3h26.5v-8z"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="92" viewBox="0 0 248 92"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user-empty.svg"><path fill="#FFF" d="M0 0h248v92H0z"/><path id="Rectangle-4-Copy" fill="#D1C4B1" stroke="#D1C4B1" stroke-width="4" d="M123.937 12L107.27 32h130.46l-16.667-20h-97.126z" opacity=".5"/><path id="Rectangle-4" fill="#FFF9EB" stroke="#BCA68E" stroke-width="4" d="M105 26h135v50H105z"/><path id="Rectangle-8" stroke="#BCA68E" stroke-width="3" d="M160.5 46.5h25v10h-25z"/><text id="empty" fill="#9B9B9B" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal"><tspan x="151" y="22">empty</tspan></text><text id="user" fill="#EE6B47" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="4" y="56">user</tspan></text><path id="Line-8" fill="#EE6B47" fill-rule="nonzero" d="M70.5 42l19 9.5-19 9.5v-8H44v-3h26.5v-8z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="173" viewBox="0 0 248 173"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user-isadmin.svg"><path fill="#FFF" d="M0 0h248v173H0z"/><path id="Rectangle-4-Copy" fill="#DBAF88" stroke="#DBAF88" stroke-width="4" d="M225.063 101l16.667 20H111.27l16.667-20h97.126z" opacity=".5"/><g id="Group-2" transform="translate(125 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="name" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 15.5 42.859)"><tspan x="-1.3" y="47.359">name</tspan></text></g><g id="Group-2-Copy" transform="translate(162 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="age" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 14.5 41.653)"><tspan x="1.9" y="46.153">age</tspan></text></g><g id="Group-2-Copy-2" transform="translate(199 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="isAdmin" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 14.5 41.653)"><tspan x="-14.9" y="46.153">isAdmin</tspan></text></g><path id="Rectangle-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="4" d="M109 115h135v50H109z"/><path id="Rectangle-8" stroke="#DBAF88" stroke-width="3" d="M164.5 135.5h25v10h-25z"/><text id="user" fill="#C06334" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="12" y="145">user</tspan></text><path id="Line-8" fill="#C06334" fill-rule="nonzero" d="M78.5 131l19 9.5-19 9.5v-8H52v-3h26.5v-8z"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="173" viewBox="0 0 248 173"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user-isadmin.svg"><path fill="#FFF" d="M0 0h248v173H0z"/><path id="Rectangle-4-Copy" fill="#D1C4B1" stroke="#D1C4B1" stroke-width="4" d="M127.937 101l-16.667 20h130.46l-16.667-20h-97.126z" opacity=".5"/><g id="Group-2" transform="translate(125 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="name" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 15.5 42.859)"><tspan x="-1.3" y="47.359">name</tspan></text></g><g id="Group-2-Copy" transform="translate(162 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="age" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 14.5 41.653)"><tspan x="1.9" y="46.153">age</tspan></text></g><g id="Group-2-Copy-2" transform="translate(199 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="isAdmin" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 14.5 41.653)"><tspan x="-14.9" y="46.153">isAdmin</tspan></text></g><path id="Rectangle-4" fill="#FFF9EB" stroke="#BCA68E" stroke-width="4" d="M109 115h135v50H109z"/><path id="Rectangle-8" stroke="#BCA68E" stroke-width="3" d="M164.5 135.5h25v10h-25z"/><text id="user" fill="#EE6B47" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="12" y="145">user</tspan></text><path id="Line-8" fill="#EE6B47" fill-rule="nonzero" d="M78.5 131l19 9.5-19 9.5v-8H52v-3h26.5v-8z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before After
Before After

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="215" viewBox="0 0 248 215"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user-props.svg"><path fill="#FFF" d="M0 0h248v215H0z"/><path id="Rectangle-4-Copy" fill="#DBAF88" stroke="#DBAF88" stroke-width="4" d="M225.063 143l16.667 20H111.27l16.667-20h97.126z" opacity=".5"/><g id="Group-2" transform="translate(124 3)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v157H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v157H0V0h32zM16.5 126.613c-4.142 0-7.5 4.251-7.5 9.496 0 5.244 3.358 9.496 7.5 9.496 4.142 0 7.5-4.252 7.5-9.496 0-5.245-3.358-9.496-7.5-9.496zM28 6.33H4v110.153h24V6.33z"/></g><text id="name" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 13.105 60.141)"><tspan x="-6.095" y="65.141">name</tspan></text></g><g id="Group-2-Copy" transform="translate(161 3)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v157H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v157H0V0h32zM16.5 126.613c-4.142 0-7.5 4.251-7.5 9.496 0 5.244 3.358 9.496 7.5 9.496 4.142 0 7.5-4.252 7.5-9.496 0-5.245-3.358-9.496-7.5-9.496zM28 6.33H4v110.153h24V6.33z"/></g><text id="age" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 13.105 60.141)"><tspan x="-1.295" y="65.141">age</tspan></text></g><g id="Group-2-Copy-2" transform="translate(198 3)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v157H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v157H0V0h32zM16.5 126.613c-4.142 0-7.5 4.251-7.5 9.496 0 5.244 3.358 9.496 7.5 9.496 4.142 0 7.5-4.252 7.5-9.496 0-5.245-3.358-9.496-7.5-9.496zM28 6.33H4v110.153h24V6.33z"/></g><text id="likes-birds" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 15.504 60.774)"><tspan x="-30.696" y="65.274">likes birds</tspan></text></g><path id="Rectangle-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="4" d="M109 157h135v50H109z"/><path id="Rectangle-8" stroke="#DBAF88" stroke-width="3" d="M164.5 177.5h25v10h-25z"/><text id="user" fill="#C06334" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="5" y="187">user</tspan></text><path id="Line-8" fill="#C06334" fill-rule="nonzero" d="M71.5 173l19 9.5-19 9.5v-8H45v-3h26.5v-8z"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="215" viewBox="0 0 248 215"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user-props.svg"><path fill="#FFF" d="M0 0h248v215H0z"/><path id="Rectangle-4-Copy" fill="#D1C4B1" stroke="#D1C4B1" stroke-width="4" d="M127.937 143l-16.667 20h130.46l-16.667-20h-97.126z" opacity=".5"/><g id="Group-2" transform="translate(124 3)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v157H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v157H0V0h32zM16.5 126.613c-4.142 0-7.5 4.251-7.5 9.496 0 5.244 3.358 9.496 7.5 9.496 4.142 0 7.5-4.252 7.5-9.496 0-5.245-3.358-9.496-7.5-9.496zM28 6.33H4v110.153h24V6.33z"/></g><text id="name" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 15.5 60.141)"><tspan x="-3.7" y="62.746">name</tspan></text></g><g id="Group-2-Copy" transform="translate(161 3)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v157H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v157H0V0h32zM16.5 126.613c-4.142 0-7.5 4.251-7.5 9.496 0 5.244 3.358 9.496 7.5 9.496 4.142 0 7.5-4.252 7.5-9.496 0-5.245-3.358-9.496-7.5-9.496zM28 6.33H4v110.153h24V6.33z"/></g><text id="age" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 15.5 60.141)"><tspan x="1.1" y="62.746">age</tspan></text></g><g id="Group-2-Copy-2" transform="translate(198 3)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v157H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v157H0V0h32zM16.5 126.613c-4.142 0-7.5 4.251-7.5 9.496 0 5.244 3.358 9.496 7.5 9.496 4.142 0 7.5-4.252 7.5-9.496 0-5.245-3.358-9.496-7.5-9.496zM28 6.33H4v110.153h24V6.33z"/></g><text id="likes-birds" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 17.5 60.774)"><tspan x="-28.7" y="63.278">likes birds</tspan></text></g><path id="Rectangle-4" fill="#FFF9EB" stroke="#BCA68E" stroke-width="4" d="M109 157h135v50H109z"/><path id="Rectangle-8" stroke="#BCA68E" stroke-width="3" d="M164.5 177.5h25v10h-25z"/><text id="user" fill="#EE6B47" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="5" y="187">user</tspan></text><path id="Line-8" fill="#EE6B47" fill-rule="nonzero" d="M71.5 173l19 9.5-19 9.5v-8H45v-3h26.5v-8z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="173" viewBox="0 0 248 173"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user.svg"><path fill="#FFF" d="M0 0h248v173H0z"/><path id="Rectangle-4-Copy" fill="#DBAF88" stroke="#DBAF88" stroke-width="4" d="M225.063 101l16.667 20H111.27l16.667-20h97.126z" opacity=".5"/><g id="Group-2" transform="translate(142 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="name" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 15.5 42.859)"><tspan x="-1.3" y="47.359">name</tspan></text></g><g id="Group-2-Copy" transform="translate(179 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="age" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 14.5 41.653)"><tspan x="1.9" y="46.153">age</tspan></text></g><path id="Rectangle-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="4" d="M109 115h135v50H109z"/><path id="Rectangle-8" stroke="#DBAF88" stroke-width="3" d="M164.5 135.5h25v10h-25z"/><text id="user" fill="#C06334" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="11" y="145">user</tspan></text><path id="Line-8" fill="#C06334" fill-rule="nonzero" d="M77.5 131l19 9.5-19 9.5v-8H51v-3h26.5v-8z"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="248" height="173" viewBox="0 0 248 173"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object-user.svg"><path fill="#FFF" d="M0 0h248v173H0z"/><path id="Rectangle-4-Copy" fill="#D1C4B1" stroke="#D1C4B1" stroke-width="4" d="M127.937 101l-16.667 20h130.46l-16.667-20h-97.126z" opacity=".5"/><g id="Group-2" transform="translate(142 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="name" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 15.5 42.859)"><tspan x="-1.3" y="47.359">name</tspan></text></g><g id="Group-2-Copy" transform="translate(179 8)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v110H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v110H0V0h32zM16.5 88.71c-4.142 0-7.5 2.978-7.5 6.653 0 3.674 3.358 6.653 7.5 6.653 4.142 0 7.5-2.979 7.5-6.653 0-3.675-3.358-6.653-7.5-6.653zM28 4.435H4v77.178h24V4.435z"/></g><text id="age" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="14" font-weight="bold" transform="rotate(-90 14.5 41.653)"><tspan x="1.9" y="46.153">age</tspan></text></g><path id="Rectangle-4" fill="#FFF9EB" stroke="#BCA68E" stroke-width="4" d="M109 115h135v50H109z"/><path id="Rectangle-8" stroke="#BCA68E" stroke-width="3" d="M164.5 135.5h25v10h-25z"/><text id="user" fill="#EE6B47" font-family="OpenSans-Bold, Open Sans" font-size="14" font-weight="bold"><tspan x="11" y="145">user</tspan></text><path id="Line-8" fill="#EE6B47" fill-rule="nonzero" d="M77.5 131l19 9.5-19 9.5v-8H51v-3h26.5v-8z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before After
Before After

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="176" height="183" viewBox="0 0 176 183"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object.svg"><path fill="#FFF" d="M0 0h176v183H0z"/><path id="Rectangle-4-Copy" fill="#DBAF88" stroke="#DBAF88" stroke-width="4" d="M134.063 113l16.667 20H20.27l16.667-20h97.126z" opacity=".5"/><g id="Group-2" transform="translate(33 6)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v124H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v124H0V0h32zM16.5 100a7.5 7.5 0 100 15 7.5 7.5 0 000-15zM28 5H4v87h24V5z"/></g><text id="key1" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 15.5 47.5)"><tspan x="-3.7" y="52.5">key1</tspan></text></g><g id="Group-2-Copy" transform="translate(70 6)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v124H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v124H0V0h32zM16.5 100a7.5 7.5 0 100 15 7.5 7.5 0 000-15zM28 5H4v87h24V5z"/></g><text id="key2" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 15.5 47.5)"><tspan x="-3.7" y="52.5">key2</tspan></text></g><g id="Group-2-Copy-2" transform="translate(107 6)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v124H0z"/><path id="Combined-Shape" fill="#DBAF88" d="M32 0v124H0V0h32zM16.5 100a7.5 7.5 0 100 15 7.5 7.5 0 000-15zM28 5H4v87h24V5z"/></g><text id="key3" fill="#C06334" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 15.5 47.5)"><tspan x="-3.7" y="52.5">key3</tspan></text></g><path id="Rectangle-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="4" d="M18 127h135v50H18z"/><path id="Rectangle-8" stroke="#DBAF88" stroke-width="3" d="M73.5 147.5h25v10h-25z"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="176" height="183" viewBox="0 0 176 183"><defs><style>@import url(https://fonts.googleapis.com/css?family=Open+Sans:bold,italic,bolditalic%7CPT+Mono);@font-face{font-family:&apos;PT Mono&apos;;font-weight:700;font-style:normal;src:local(&apos;PT MonoBold&apos;),url(/font/PTMonoBold.woff2) format(&apos;woff2&apos;),url(/font/PTMonoBold.woff) format(&apos;woff&apos;),url(/font/PTMonoBold.ttf) format(&apos;truetype&apos;)}</style></defs><g id="combined" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="object.svg"><path fill="#FFF" d="M0 0h176v183H0z"/><path id="Rectangle-4-Copy" fill="#D1C4B1" stroke="#D1C4B1" stroke-width="4" d="M36.937 113L20.27 133h130.46l-16.667-20H36.937z" opacity=".5"/><g id="Group-2" transform="translate(33 6)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v124H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v124H0V0h32zM16.5 100a7.5 7.5 0 100 15 7.5 7.5 0 000-15zM28 5H4v87h24V5z"/></g><text id="key1" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 15.5 47.5)"><tspan x="-3.7" y="52.5">key1</tspan></text></g><g id="Group-2-Copy" transform="translate(70 6)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v124H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v124H0V0h32zM16.5 100a7.5 7.5 0 100 15 7.5 7.5 0 000-15zM28 5H4v87h24V5z"/></g><text id="key2" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 15.5 47.5)"><tspan x="-3.7" y="52.5">key2</tspan></text></g><g id="Group-2-Copy-2" transform="translate(107 6)"><g id="Group"><path id="Rectangle-7" fill="#FFF" d="M0 0h32v124H0z"/><path id="Combined-Shape" fill="#E8C48F" d="M32 0v124H0V0h32zM16.5 100a7.5 7.5 0 100 15 7.5 7.5 0 000-15zM28 5H4v87h24V5z"/></g><text id="key3" fill="#EE6B47" font-family="PTMono-Bold, PT Mono" font-size="16" font-weight="bold" transform="rotate(-90 15.5 47.5)"><tspan x="-3.7" y="52.5">key3</tspan></text></g><path id="Rectangle-4" fill="#FFF9EB" stroke="#BCA68E" stroke-width="4" d="M18 127h135v50H18z"/><path id="Rectangle-8" stroke="#BCA68E" stroke-width="3" d="M73.5 147.5h25v10h-25z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more