Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dagolinuxoid 2018-11-26 16:58:26 +03:00
commit 1ba2ebbb44
214 changed files with 1166 additions and 4587 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto eol=lf

View file

@ -1,16 +1,16 @@
# An Introduction to JavaScript
Let's see what's so special about JavaScript, what we can achieve with it and which other technologies play well with it.
Let's see what's so special about JavaScript, what we can achieve with it, and which other technologies play well with it.
## What is JavaScript?
*JavaScript* was initially created to *"make webpages alive"*.
*JavaScript* was initially created to *"make web pages alive"*.
The programs in this language are called *scripts*. They can be written right in the HTML and execute automatically as the page loads.
The programs in this language are called *scripts*. They can be written right in the HTML and executed automatically as the page loads.
Scripts are provided and executed as a plain text. They don't need a special preparation or a compilation to run.
In this aspect, JavaScript is very different from another language called [Java](http://en.wikipedia.org/wiki/Java).
In this aspect, JavaScript is very different from another language called [Java](https://en.wikipedia.org/wiki/Java_(programming_language)).
```smart header="Why <u>Java</u>Script?"
When JavaScript was created, it initially had another name: "LiveScript". But Java language was very popular at that time, so it was decided that positioning a new language as a "younger brother" of Java would help.
@ -18,15 +18,15 @@ When JavaScript was created, it initially had another name: "LiveScript". But Ja
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.
```
At present, JavaScript can execute not only in the browser, but also on the server, or actually on any device where there exists a special program called [the JavaScript engine](https://en.wikipedia.org/wiki/JavaScript_engine).
At present, JavaScript can not only execute 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 it's also called a "JavaScript virtual machine".
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 and Opera.
- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- in Firefox.
- ...There are other codenames like "Trident", "Chakra" for different versions of IE, "ChakraCore" for Microsoft Edge, "Nitro" and "SquirrelFish" for Safari etc.
- ...There are other codenames like "Trident" and "Chakra" for different versions of IE, "ChakraCore" for Microsoft Edge, "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 and Opera.
@ -45,9 +45,9 @@ The engine applies optimizations on every stage of the process. It even watches
The modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or CPU, because it was initially created for browsers which do not require it.
The capabilities greatly depend on the environment that runs JavaScript. For instance, [Node.JS](https://wikipedia.org/wiki/Node.js) supports functions that allow JavaScript to read/write arbitrary files, perform network requests etc.
The capabilities greatly depend on the environment that runs JavaScript. 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.
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:
@ -85,7 +85,7 @@ There are at least *three* great things about JavaScript:
```compare
+ Full integration with HTML/CSS.
+ Simple things done simply.
+ Simple things are done simply.
+ Supported by all major browsers and enabled by default.
```
@ -104,15 +104,15 @@ That's to be expected, because projects and requirements are different for every
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 autoconverting it "under the hood".
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](http://coffeescript.org/) is a "syntactic sugar" for JavaScript, it introduces shorter syntax, allowing to write more precise and clear code. Usually Ruby devs like it.
- [TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing", to simplify development and support of complex systems. It is developed by Microsoft.
- [TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing", to simplify the development and support of complex systems. It is developed by Microsoft.
- [Dart](https://www.dartlang.org/) is a standalone language that has its own engine that runs in non-browser environments (like mobile apps). It was initially offered by Google as a replacement for JavaScript, but as of now, browsers require it to be transpiled to JavaScript just like the ones above.
There are more. Of course even if we use one of those languages, we should also know JavaScript, to really understand what we're doing.
There are more. Of course, even if we use one of those languages, we should also know JavaScript, to really understand what we're doing.
## Summary

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Before After
Before After

View file

@ -6,25 +6,27 @@ There are two archetypes: IDE and lightweight editors. Many people feel comforta
## IDE
The term [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) (Integrated Development Environment) means a powerful editor with many features that usually operates on a "whole project". As the name suggests, that's not just an editor, but a full-scale "development environment".
The term [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) (Integrated Development Environment) means a powerful editor with many features that usually operates on a "whole project." As the name suggests, that's not just an editor, but a full-scale "development environment."
An IDE loads the project (can be many files), allows navigation between files, provides autocompletion based on the whole project (not just the open file), integrates with a version management system (like [git](https://git-scm.com/)), a testing environment and other "project-level" stuff.
If you haven't considered selecting an IDE yet, look at the following variants:
- [WebStorm](http://www.jetbrains.com/webstorm/) for frontend development and other editors of the same company if you need additional languages.
- Visual Studio is fine if you're a .NET developer, and a free version is available ([Visual Studio Community](https://www.visualstudio.com/vs/community/))
- [Netbeans](http://netbeans.org/).
- [WebStorm](http://www.jetbrains.com/webstorm/) for frontend development and other editors of the same company if you need additional languages (paid).
- [Visual Studio Code](https://code.visualstudio.com/) (free).
- [Netbeans](http://netbeans.org/) (paid).
All of the IDEs except Visual Studio are available on Windows, MacOs and Linux. Visual Studio doesn't work on Linux.
All of the IDEs are cross-platform.
Most 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.
For Windows, there's also a "Visual Studio" editor, don't confuse it with "Visual Studio Code." "Visual Studio" is a paid and mighty Windows-only editor, well-suited for the .NET platform. A free version of it is called ([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 instantly open and edit a file.
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.
@ -36,7 +38,7 @@ The following options deserve your attention:
- [Atom](https://atom.io/) (cross-platform, free).
- [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.
- [Vim](http://www.vim.org/) and [Emacs](https://www.gnu.org/software/emacs/) are also cool if you know how to use them.
## My favorites
@ -44,12 +46,12 @@ The personal preference of the author is to have both an IDE for projects and a
I'm using:
- [WebStorm](http://www.jetbrains.com/webstorm/) for JS, and if there is one more language in the project, then I switch to one of the other Jetbrains offerings listed above.
- [WebStorm](http://www.jetbrains.com/webstorm/) for JS, and if there is one more language in the project, then I switch to one of the other JetBrains offerings listed above.
- As a lightweight editor -- [Sublime Text](http://www.sublimetext.com) or [Atom](https://atom.io/).
## Let's not argue
The editors in the lists above are those that either I or my friends who I consider good developers have been using for a long time and are happy with.
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.

View file

@ -4,11 +4,11 @@ Code is prone to errors. You are quite likely to make errors... Oh, what am I ta
But in the browser, a user doesn't see the 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, browsers have embedded "developer tools".
To see errors and get a lot of other useful information about scripts, "developer tools" have been embedded in browsers.
Most often 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 people have a "favorite" browser and switch to others if a problem is browser-specific.
Most often 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 people have a "favorite" browser and switch to others if a problem is browser-specific.
Developer tools are really powerful, there are many features. To start, we'll learn how to open them, look at errors and run JavaScript commands.
Developer tools are potent; there are many features. To start, we'll learn how to open them, look at errors and run JavaScript commands.
## Google Chrome
@ -24,21 +24,21 @@ 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.
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.
- 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 and press `key:Enter` to run them (`key:Shift+Enter` to input multi-line commands).
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 (`key:Shift+Enter` to input multi-line commands).
Now we can see errors and that's enough for the start. We'll be back to developer tools later and cover debugging more in-depth in the chapter <info:debugging-chrome>.
Now we can see errors, and that's enough for a start. We'll be back to developer tools later and cover debugging more in-depth in the chapter <info:debugging-chrome>.
## Firefox, Edge and others
## 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 them (you can start with Chrome), you can easily switch to another.
The look & feel of them is quite similar. Once you know how to use one of those tools (you can start with Chrome), you can easily switch to another.
## Safari
@ -48,11 +48,11 @@ Open Preferences and go to "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.
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 under 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.
Now we have the environment ready. In the next section, we'll get down to JavaScript.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Before After
Before After

View file

@ -2,7 +2,7 @@
The tutorial that you're reading is about core JavaScript, which is platform-independent. Further on, you will learn Node.JS and other platforms that use it.
But, we need a working environment to run our scripts, and, just because 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. On the other hand, browser details are explained in detail in the [next part](/ui) of the tutorial.
But, we need a working environment to run our scripts, and, just because 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. On the other hand, browser details are explained in detail in the [next part](/ui) of the tutorial.
So first, let's see how to attach a script to a webpage. For server-side environments, you can just execute it with a command like `"node my.js"` for Node.JS.
@ -47,10 +47,10 @@ The `<script>` tag has a few attributes that are rarely used nowadays, but we ca
The `type` attribute: <code>&lt;script <u>type</u>=...&gt;</code>
: The old standard HTML4 required a script to have a type. Usually it was `type="text/javascript"`. It's not required any more. Also, the modern standard totally changed the meaning of this attribute. Now it can be used for Javascript modules. But that's an advanced topic, but we'll talk about modules later in another part of the tutorial.
: The old standard HTML4 required a script to have a type. Usually it was `type="text/javascript"`. It's not required anymore. Also, the modern 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 later 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. As of now, this attribute makes no sense, the language is JavaScript by default. No need to use it.
: This attribute was meant to show the language of the script. This attribute no longer makes sense, because JavaScript is the default language. No need to use it.
Comments before and after scripts.
: In really ancient books and guides, one may find comments inside `<script>`, like this:
@ -61,7 +61,7 @@ Comments before and after scripts.
//--></script>
```
This trick isn't used in modern JavaScript. These comments were used to hide the JavaScript code from old browsers that didn't know about a `<script>` tag. Since browsers born in the last 15 years don't have this issue, this kind of comment can help you identify really old code.
This trick isn't used in modern JavaScript. These comments were used to hide the JavaScript code from old browsers that didn't know about a `<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
@ -78,7 +78,7 @@ Here `/path/to/script.js` is an absolute path to the file with the script (from
It is also possible to provide a path relative to the current page. For instance, `src="script.js"` would mean a file `"script.js"` in the current folder.
We can give a full URL as well, for instance:
We can give a full URL as well. For instance:
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
@ -95,7 +95,7 @@ To attach several scripts, use multiple tags:
```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 then store in its [cache](https://en.wikipedia.org/wiki/Web_cache).
The benefit of a separate file is that the browser will download it and then store it in its [cache](https://en.wikipedia.org/wiki/Web_cache).
After this, other pages that want the same script will take it from the cache instead of downloading it. So the file is actually downloaded only once.

View file

@ -6,7 +6,7 @@ The first thing to study is the building blocks of the code.
Statements are syntax constructs and commands that perform actions.
We've already seen a statement `alert('Hello, world!')`, which shows the message.
We've already seen a statement `alert('Hello, world!')`, which shows the message "Hello world!".
We can have as many statements in the code as we want. Another statement can be separated with a semicolon.
@ -46,7 +46,7 @@ alert(3 +
+ 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", no semicolon required. And in this case that works as intended.
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 the semicolon is not required. And in this case that works as intended.
**But there are situations where JavaScript "fails" to assume a semicolon where it is really needed.**
@ -98,7 +98,7 @@ It's recommended to put semicolons between statements even if they are separated
As time goes on, the program becomes more and more complex. It becomes necessary to add *comments* which describe what happens and why.
Comments can be put into any place of the script. They don't affect the execution, because the engine simply ignores them.
Comments can be put into any place of the script. They don't affect the execution because the engine simply ignores them.
**One-line comments start with two forward slash characters `//`.**
@ -156,4 +156,4 @@ 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 the code before publishing to the production server. They remove comments, so they don't appear in the working scripts. Therefore comments do not have any negative effects on production at all.
Further in the tutorial, there will be a chapter <info:coding-style> that also explains how to write better comments.
Further in the tutorial there will be a chapter <info:coding-style> that also explains how to write better comments.

View file

@ -51,7 +51,7 @@ Once we enter the strict mode, there's no return.
The differences of `"use strict"` versus the "default" mode are still to be covered.
In the next chapters, as we learn language features, we'll make notes about the differences of the strict mode. Luckily, there are not so many. And they actually make our life better.
In the next chapters, as we learn language features, we'll make notes about the differences of the strict and default mode. Luckily, there are not so many. And they actually make our life better.
At this point in time it's enough to know about it in general:

View file

@ -18,4 +18,4 @@ Again, we could shorten that to `userName` if we know for sure that the user is
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](/editors).
And if your editor does not have proper autocompletion, get [a new one](/code-editors).

View file

@ -1,7 +1,7 @@
# Variables
Most of the time, a JavaScript application needs to work with information. Here are 2 examples:
1. An online-shop -- the information might include goods being sold and a shopping cart.
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.
@ -183,7 +183,7 @@ let my-name; // a hyphen '-' is not allowed in the name
Variables named `apple` and `AppLE` -- are two different variables.
```
````smart header="Non-english letters are allowed, but not recommended"
````smart header="Non-English letters are allowed, but not recommended"
It is possible to use any language, including cyrillic letters or even hieroglyphs, like this:
```js
@ -195,7 +195,7 @@ Technically, there is no error here, such names are allowed, but there is an int
````
````warn header="Reserved names"
There is a list of reserved words, which cannot be used as variable names, because they are used by the language itself.
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, words `let`, `class`, `return`, `function` are reserved.
@ -221,14 +221,13 @@ alert(num); // 5
That's a bad practice, it gives an error in the strict mode:
```js run untrusted
```js run refresh untrusted
"use strict";
*!*
num = 5; // error: num is not defined
*/!*
```
````
## Constants

View file

@ -91,7 +91,7 @@ alert( 1 + '2' ); // '12' (string to the right)
alert( '1' + 2 ); // '12' (string to the left)
```
That only happens when one of the arguments is a string. Otherwise, values are converted to numbers.
That only happens when at least one of the arguments is a string. Otherwise, values are converted to numbers.
````
## ToBoolean

View file

@ -4,7 +4,7 @@ importance: 5
# What's the result of OR?
What the code below is going to output?
What is the code below going to output?
```js
alert( null || 2 || undefined );

View file

@ -4,7 +4,7 @@ importance: 3
# What's the result of OR'ed alerts?
What the code below will output?
What will the code below output?
```js
alert( alert(1) || 2 || alert(3) );

View file

@ -4,7 +4,7 @@ importance: 5
# What is the result of AND?
What this code is going to show?
What is this code going to show?
```js
alert( 1 && null && 2 );

View file

@ -12,5 +12,5 @@ The result of `2 && 3 = 3`, so the expression becomes:
null || 3 || 4
```
Now the result if the first truthy value: `3`.
Now the result is the first truthy value: `3`.

View file

@ -4,7 +4,7 @@ importance: 5
# The result of OR AND OR
What will be the result?
What will the result be?
```js
alert( null || 2 && 3 || 4 );

View file

@ -6,7 +6,7 @@ importance: 5
Which of these `alert`s are going to execute?
What will be the results of the expressions inside `if(...)`?
What will the results of the expressions be inside `if(...)`?
```js
if (-1 || 0) alert( 'first' );

View file

@ -300,4 +300,4 @@ alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false
```
The precedence of NOT `!` is the highest of all bitwise operators, so it always executes first, before any `&&`, `||`.
The precedence of NOT `!` is the highest of all logical operators, so it always executes first, before any `&&`, `||`.

View file

@ -7,11 +7,11 @@ The task demonstrates how postfix/prefix forms can lead to different results whe
while (++i < 5) alert( i );
```
The first value is `i=1`, because `++i` first increments `i` and then returns the new value. So the first comparison is `1 < 5` and the `alert` shows `1`.
The first value is `i = 1`, because `++i` first increments `i` and then returns the new value. So the first comparison is `1 < 5` and the `alert` shows `1`.
Then follow `2,3,4…` -- the values show up one after another. The comparison always uses the incremented value, because `++` is before the variable.
Then follow `2, 3, 4…` -- the values show up one after another. The comparison always uses the incremented value, because `++` is before the variable.
Finally, `i=4` is incremented to `5`, the comparison `while(5 < 5)` fails, and the loop stops. So `5` is not shown.
Finally, `i = 4` is incremented to `5`, the comparison `while(5 < 5)` fails, and the loop stops. So `5` is not shown.
2. **From 1 to 5**
```js run
@ -19,12 +19,12 @@ The task demonstrates how postfix/prefix forms can lead to different results whe
while (i++ < 5) alert( i );
```
The first value is again `i=1`. The postfix form of `i++` increments `i` and then returns the *old* value, so the comparison `i++ < 5` will use `i=0` (contrary to `++i < 5`).
The first value is again `i = 1`. The postfix form of `i++` increments `i` and then returns the *old* value, so the comparison `i++ < 5` will use `i = 0` (contrary to `++i < 5`).
But the `alert` call is separate. It's another statement which executes after the increment and the comparison. So it gets the current `i=1`.
But the `alert` call is separate. It's another statement which executes after the increment and the comparison. So it gets the current `i = 1`.
Then follow `2,3,4…`
Then follow `2, 3, 4…`
Let's stop on `i=4`. The prefix form `++i` would increment it and use `5` in the comparison. But here we have the postfix form `i++`. So it increments `i` to `5`, but returns the old value. Hence the comparison is actually `while(4 < 5)` -- true, and the control goes on to `alert`.
Let's stop on `i = 4`. The prefix form `++i` would increment it and use `5` in the comparison. But here we have the postfix form `i++`. So it increments `i` to `5`, but returns the old value. Hence the comparison is actually `while(4 < 5)` -- true, and the control goes on to `alert`.
The value `i=5` is the last one, because on the next step `while(5 < 5)` is false.
The value `i = 5` is the last one, because on the next step `while(5 < 5)` is false.

View file

@ -2,11 +2,11 @@ importance: 4
---
# Which values shows the while?
# Which values does the while loop show?
For every loop, write down which values it shows, in your opinion. And then compare with the answer.
For every loop iteration, write down which value it outputs and then compare it with the solution.
Both loops `alert` same values or not?
Both loops `alert` the same values, or not?
1. The prefix form `++i`:

View file

@ -204,6 +204,10 @@ 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, `anotherFunctions()` is called everytime `someMessage()` is called without the `text` parameter. This is in contrast to some other languages like Python, where any default parameters are evaluated only once during the initial interpretation.
```
````smart header="Default parameters old-style"
Old editions of JavaScript did not support default parameters. So there are alternative ways to support them, that you can find mostly in the old scripts.
@ -263,7 +267,7 @@ function checkAge(age) {
*/!*
} else {
*!*
return confirm('Got a permission from the parents?');
return confirm('Do you have permission from your parents?');
*/!*
}
}
@ -334,7 +338,7 @@ So, it effectively becomes an empty return. We should put the value on the same
## Naming a function [#function-naming]
Functions are actions. So their name is usually a verb. It should briefly, but as accurately as possible describe what the function does. So that a person who reads the code gets the right clue.
Functions are actions. So their name is usually a verb. It should be brief, as accurate as possible and describe what the function does, so that someone reading the code gets an indication of what the function does.
It is a widespread practice to start a function with a verbal prefix which vaguely describes the action. There must be an agreement within the team on the meaning of the prefixes.
@ -376,9 +380,9 @@ These examples assume common meanings of prefixes. What they mean for you is det
```smart header="Ultrashort function names"
Functions that are used *very often* sometimes have ultrashort names.
For example, the [jQuery](http://jquery.com) framework defines a function `$`. The [LoDash](http://lodash.com/) library has its core function named `_`.
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 functions names should be concise, but descriptive.
These are exceptions. Generally functions names should be concise and descriptive.
```
## Functions == Comments

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before After
Before After

View file

@ -78,8 +78,8 @@ let func = sayHi;
Everything would work the same. Even more obvious what's going on, right?
````smart header="Why there's a semicolon at the end?"
There might be a question, why does Function Expression have a semicolon `;` at the end, and Function Declaration does not:
````smart header="Why is there a semicolon at the end?"
You might wonder, why does Function Expression have a semicolon `;` at the end, but Function Declaration does not:
```js
function sayHi() {
@ -198,7 +198,7 @@ The more subtle difference is *when* a function is created by the JavaScript eng
**A Function Expression is created when the execution reaches it and is usable from then on.**
Once the execution flow passes to the right side of the assignment `let sum = function…` -- here we go, the function is created and can be used (assigned, called etc) from now on.
Once the execution flow passes to the right side of the assignment `let sum = function…` -- here we go, the function is created and can be used (assigned, called, etc. ) from now on.
Function Declarations are different.
@ -350,7 +350,7 @@ welcome(); // ok now
```
```smart header="When to choose Function Declaration versus Function Expression?"
```smart header="When should you choose Function Declaration versus Function Expression?"
As a rule of thumb, when we need to declare a function, the first to consider is Function Declaration syntax, the one we used before. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
It's also a little bit easier to look up `function f(…) {…}` in the code than `let f = function(…) {…}`. Function Declarations are more "eye-catching".
@ -375,7 +375,7 @@ In other words, it's roughly the same as:
```js
let func = function(arg1, arg2, ...argN) {
return expression;
}
};
```
...But much more concise.

View file

@ -1,14 +1,12 @@
# Coding style
# Coding Style
Our code must be as clean and easy to read as possible.
That is actually an art of programming -- to take a complex task and code it in a way that is both correct and human-readable.
One thing to help is the good code style.
That is actually the art of programming -- to take a complex task and code it in a way that is both correct and human-readable.
## Syntax
A cheatsheet with the rules (more details below):
Here is a cheatsheet with some suggested rules (see below for more details):
![](code-style.png)
<!--
@ -38,13 +36,13 @@ if (n < 0) {
Now let's discuss the rules and reasons for them in detail.
Nothing is "carved in stone" here. Everything is optional and can be changed: these are coding rules, not religious dogmas.
```warn header="Irony Detected"
Nothing is set in stone here. These are style preferences, not religious dogmas.
```
### Curly braces
### Curly Braces
In most JavaScript projects curly braces are written on the same line as the corresponding keyword, not on the new line, a so-called "Egyptian" style. There's also a space before an opening bracket.
Like this:
In most JavaScript projects curly braces are written in "Egyptian" style with the opening brace on the same line as the corresponding keyword -- not on a new line. There should also be a space before the opening bracket, like this:
```js
if (condition) {
@ -56,7 +54,7 @@ if (condition) {
A single-line construct is an important edge case. Should we use brackets at all? If yes, then where?
Here are the annotated variants, so you can judge about their readability on your own:
Here are the annotated variants so you can judge their readability for yourself:
<!--
```js no-beautify
@ -74,21 +72,21 @@ if (n < 0) {
-->
![](figure-bracket-style.png)
As a summary:
- For a really short code, one line is acceptable: like `if (cond) return null`.
- But a separate line for each statement in brackets is usually better.
In summary:
- For very short code, one line is acceptable. For example: `if (cond) return null`.
- But a separate line for each statement in brackets is usually easier to read.
### Line length
### Line Length
The maximal line length should be limited. No one likes to eye-follow a long horizontal line. It's better to split it.
No one likes to read a long horizontal line of code. It's best practice to split them up and limit the length of your lines.
The maximal line length is agreed on the team-level. It's usually 80 or 120 characters.
The maximum line length should be agreed upon at the team-level. It's usually 80 or 120 characters.
### Indents
There are two types of indents:
- **A horizontal indent: 2(4) spaces.**
- **Horizontal indents: 2 or 4 spaces.**
A horizontal indentation is made using either 2 or 4 spaces or the "Tab" symbol. Which one to choose is an old holy war. Spaces are more common nowadays.
@ -107,9 +105,9 @@ There are two types of indents:
}
```
- **A vertical indent: empty lines for splitting code into logical blocks.**
- **Vertical indents: empty lines for splitting code into logical blocks.**
Even a single function can often be divided in logical blocks. In the example below, the initialization of variables, the main loop and returning the result are split vertically:
Even a single function can often be divided into logical blocks. In the example below, the initialization of variables, the main loop and returning the result are split vertically:
```js
function pow(x, n) {
@ -125,21 +123,21 @@ There are two types of indents:
Insert an extra newline where it helps to make the code more readable. There should not be more than nine lines of code without a vertical indentation.
### A semicolon
### Semicolons
A semicolon should be present after each statement. Even if it could possibly be skipped.
A semicolon should be present after each statement, even if it could possibly be skipped.
There are languages where a semicolon is truly optional. It's rarely used there. But in JavaScript there are few cases when a line break is sometimes not interpreted as a semicolon. That leaves a place for programming errors.
There are languages where a semicolon is truly optional and it is rarely used. In JavaScript, though, there are cases where a line break is not interpreted as a semicolon, leaving the code vulnerable to errors.
As you become more mature as a programmer, you may choose a no-semicolon style, like [StandardJS](https://standardjs.com/), but that's only when you know JavaScript well and understand possible pitfalls.
As you become more mature as a programmer, you may choose a no-semicolon style like [StandardJS](https://standardjs.com/). Until then, it's best to use semicolons to avoid possible pitfalls.
### Nesting levels
### Nesting Levels
There should not be too many nesting levels.
Try to avoid nesting code too many levels deep.
Sometimes it's a good idea to use the ["continue"](info:while-for#continue) directive in the loop to evade extra nesting in `if(..) { ... }`:
Sometimes it's a good idea to use the ["continue"](info:while-for#continue) directive in a loop to avoid extra nesting.
Instead of:
For example, instead of adding a nested `if` conditional like this:
```js
for (let i = 0; i < 10; i++) {
@ -162,7 +160,7 @@ A similar thing can be done with `if/else` and `return`.
For example, two constructs below are identical.
The first one:
Option 1:
```js
function pow(x, n) {
@ -180,7 +178,7 @@ function pow(x, n) {
}
```
And this:
Option 2:
```js
function pow(x, n) {
@ -199,13 +197,13 @@ function pow(x, n) {
}
```
...But the second one is more readable, because the "edge case" of `n < 0` is handled early on, and then we have the "main" code flow, without an additional nesting.
The second one is more readable because the "edge case" of `n < 0` is handled early on. Once the check is done we can move on to the "main" code flow without the need for additional nesting.
## Functions below the code
## Function Placement
If you are writing several "helper" functions and the code to use them, then there are three ways to place them.
If you are writing several "helper" functions and the code that uses them, there are three ways to organize the functions.
1. Functions above the code that uses them:
1. Functions declared above the code that uses them:
```js
// *!*function declarations*/!*
@ -235,7 +233,6 @@ If you are writing several "helper" functions and the code to use them, then the
walkAround();
// --- *!*helper functions*/!* ---
function createElement() {
...
}
@ -248,39 +245,37 @@ If you are writing several "helper" functions and the code to use them, then the
...
}
```
3. Mixed: a function is described where it's first used.
3. Mixed: a function is declared where it's first used.
Most of time, the second variant is preferred.
That's because when reading a code, we first want to know "what it does". If the code goes first, then it provides that information. And then maybe we won't need to read functions at all, especially if their names are adequate to what they're doing.
That's because when reading code, we first want to know *what it does*. If the code goes first, then it provides that information. Then, maybe we won't need to read the functions at all, especially if their names are descriptive of what they actually do.
## Style guides
## Style Guides
A style guide contains general rules about "how to write": which quotes to use, how many spaces to indent, where to put line breaks, etc. A lot of minor things.
A style guide contains general rules about "how to write" code, e.g. which quotes to use, how many spaces to indent, where to put line breaks, etc. A lot of minor things.
In total, when all members of a team use the same style guide, the code looks uniform. No matter who of the team wrote it, it's still the same style.
When all members of a team use the same style guide the code tends looks uniform, regardless of which team member wrote it.
Surely, a team may think out a style guide themselves. But as of now, there's no need to. There are many tried, worked-out style guides, which are easy to adopt.
Of course, a team can always write their own style guide. Most of the time though, there's no need to. There are many existing tried and true options to choose from, so adopting one of these is usually your best bet.
For instance:
Some popular choices:
- [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml)
- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)
- [Idiomatic.JS](https://github.com/rwaldron/idiomatic.js)
- [StandardJS](https://standardjs.com/)
- (there are more)
- (plus many more)
If you're a novice developer, then you could start with the cheatsheet above in the chapter, and later browse the style guides to pick up the common principles and maybe choose one.
If you're a novice developer, start with the cheatsheet at the beginning of this chapter. Once you've mastered that you can browse other style guides to pick up common principles and decide which one you like best.
## Automated linters
## Automated Linters
There are tools that can check the code style automatically. They are called "linters".
Linters are tools that can automatically check the style of your code and make suggestions for refactoring.
The great thing about them is that style-checking also finds some bugs, like a typo in a variable or function name.
The great thing about them is that style-checking can also find some bugs, like typos in variable or function names. Because of this feature, installing a linter is recommended even if you don't want to stick to one particular "code style".
So it's recommended to install one, even if you don't want to stick to a "code style". They help to find typos -- and that's already good enough.
Most well-known tools are:
Here are the most well-known linting tools:
- [JSLint](http://www.jslint.com/) -- one of the first linters.
- [JSHint](http://www.jshint.com/) -- more settings than JSLint.
@ -288,15 +283,16 @@ Most well-known tools are:
All of them can do the job. The author uses [ESLint](http://eslint.org/).
Most linters are integrated with editors: just enable the plugin in the editor and configure the style.
Most linters are integrated with many popular editors: just enable the plugin in the editor and configure the style.
For instance, for ESLint you should do the following:
1. Install [Node.JS](https://nodejs.org/).
2. Install ESLint with the command `npm install -g eslint` (npm is a JavaScript package installer).
3. Create a config file named `.eslintrc` in the root of your JavaScript project (in the folder that contains all your files).
4. Install/enable the plugin for your editor that integrates with ESLint. The majority of editors have one.
Here's an example of `.eslintrc`:
Here's an example of an `.eslintrc` file:
```js
{
@ -313,22 +309,16 @@ Here's an example of `.eslintrc`:
}
```
Here the directive `"extends"` denotes that we base on the "eslint:recommended" set of settings, and then we specify our own.
Here the directive `"extends"` denotes that the configuration is based on the "eslint:recommended" set of settings. After that, we specify our own.
Then install/enable the plugin for your editor that integrates with ESLint. The majority of editors have it.
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.
It is 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.
Using a linter has a great side-effect: linters catch typos. For instance, when an undefined variable is accessed, a linter detects it and (if integrated with an editor) highlights it. In most cases that's a mistype. So we can fix it right ahead.
For that reason even if you're not concerned about styles, using a linter is highly recommended.
Also certain IDEs support built-in linting, that also may be good, but not so tunable as ESLint.
Also certain IDEs have built-in linting, which is convenient but not as customizable as ESLint.
## Summary
All syntax rules from this chapter and the style guides aim to increase readability, so all of them are debatable.
All syntax rules described in this chapter (and in the style guides referenced) aim to increase the readability of your code, but all of them are debatable.
When we think about "how to write better?", the sole criterion is "what makes the code more readable and easier to understand? what helps to avoid errors?" That's the main thing to keep in mind when choosing the style or discussing which one is better.
When we think about writing "better" code, the questions we should ask are, "What makes the code more readable and easier to understand?" and "What can help us avoid errors?" These are the main things to keep in mind when choosing and debating code styles.
Read style guides to see the latest ideas about that and follow those that you find the best.
Reading popular style guides will allow you to keep up to date with the latest ideas about code style trends and best practices.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 227 KiB

Before After
Before After

View file

@ -5,7 +5,7 @@
Learning without thought is labor lost; thought without learning is perilous.
```
Programmer ninjas of the past used these tricks to make sharpen the mind of code maintainers.
Programmer ninjas of the past used these tricks to sharpen the mind of code maintainers.
Code review gurus look for them in test tasks.
@ -32,7 +32,7 @@ For instance, take a look at this ternary operator `'?'`:
i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
```
Cool, right? If you write like that, the developer who comes across this line and tries to understand what is the value of `i` is going to have a merry time. Then come to you, seeking for an answer.
Cool, right? If you write like that, a developer who comes across this line and tries to understand what is the value of `i` is going to have a merry time. Then come to you, seeking for an answer.
Tell them that shorter is always better. Initiate them into the paths of ninja.
@ -155,7 +155,7 @@ function ninjaFunction(elem) {
A fellow programmer who wants to work with `elem` in the second half of the function will be surprised... Only during the debugging, after examining the code they will find out that he's working with a clone!
Deadly effective even against an experienced ninja. Seen in code regularly.
Seen in code regularly. Deadly effective even against an experienced ninja.
## Underscores for fun
@ -171,6 +171,8 @@ Let everyone see how magnificent your entities are! Names like `superElement`, `
Indeed, from one hand, something is written: `super..`, `mega..`, `nice..` But from the other hand -- that brings no details. A reader may decide to look for a hidden meaning and meditate for an hour or two.
## Overlap outer variables
```quote author="Guan Yin Zi"
@ -204,7 +206,7 @@ There are functions that look like they don't change anything. Like `isReady()`,
**A really beautiful trick is to add a "useful" action to them, besides the main task.**
The expression of dazed surprise on the face of your colleague when they see a function named `is..`, `check..` or `find...` changing something -- will definitely broaden your boundaries of reason.
An expression of dazed surprise on the face of your colleague when they see a function named `is..`, `check..` or `find...` changing something -- will definitely broaden your boundaries of reason.
**Another way to surprise is to return a non-standard result.**

View file

@ -96,7 +96,7 @@ The full HTML page with these frameworks and `pow` spec:
```html src="index.html"
```
The page can be divided into four parts:
The page can be divided into five parts:
1. The `<head>` -- add third-party libraries and styles for tests.
2. The `<script>` with the function to test, in our case -- with the code for `pow`.

View file

@ -4,7 +4,7 @@ importance: 5
# Constant objects?
Is it possible to change an object declared with `const`, how do you think?
Is it possible to change an object declared with `const`? What do you think?
```js
const user = {

View file

@ -1,7 +1,7 @@
# Objects
As we know from the chapter <info:types>, there are seven language types in JavaScript. Six of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever).
As we know from the chapter <info:types>, there are seven data types in JavaScript. Six of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever).
In contrast, objects are used to store keyed collections of various data and more complex entities. In JavaScript, objects penetrate almost every aspect of the language. So we must understand them first before going in-depth anywhere else.
@ -205,7 +205,7 @@ let obj = {
for: 1,
let: 2,
return: 3
}
};
alert( obj.for + obj.let + obj.return ); // 6
```
@ -220,7 +220,7 @@ alert(obj.__proto__); // [object Object], didn't work as intended
As we see from the code, the assignment to a primitive `5` is ignored.
That can become a source of bugs and even vulnerabilies if we intent to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys.
That can become a source of bugs and even vulnerabilies if we intend to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys.
In that case the visitor may choose "__proto__" as the key, and the assignment logic will be ruined (as shown above).
@ -301,7 +301,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 would mean a variable containing the actual name to be tested. For instance:
If we omit quotes, that would mean a variable containing the actual name will be tested. For instance:
```js run
let user = { age: 30 };
@ -605,7 +605,7 @@ for (let key in user) {
}
*/!*
// now clone is a fully independant clone
// now clone is a fully independent clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

Before After
Before After

View file

@ -75,7 +75,7 @@ user[id] = "ID Value";
alert( user[id] ); // we can access the data using the symbol as the key
```
What's the benefit over using `Symbol("id")` over a string `"id"`?
What's the benefit of using `Symbol("id")` over a string `"id"`?
Let's make the example a bit deeper to see that.

View file

@ -276,7 +276,7 @@ Looking closely, we may notice two operations in `obj.method()` statement:
1. First, the dot `'.'` retrieves the property `obj.method`.
2. Then parentheses `()` execute it.
So, how does the information about `this` gets passed from the first part to the second one?
So, how does the information about `this` get passed from the first part to the second one?
If we put these operations on separate lines, then `this` will be lost for sure:
@ -316,7 +316,7 @@ When parentheses `()` are called on the Reference Type, they receive the full in
Any other operation like assignment `hi = user.hi` discards the reference type as a whole, takes the value of `user.hi` (a function) and passes it on. So any further operation "loses" `this`.
So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj[method]()` syntax (they do the same here). Later in this tutorial, we will learn various ways to solve this problem such as [func.bind()](/bind#solution-2-bind).
So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj['method']()` syntax (they do the same here). Later in this tutorial, we will learn various ways to solve this problem such as [func.bind()](/bind#solution-2-bind).
## Arrow functions have no "this"

View file

@ -2,7 +2,7 @@ Yes, it's possible.
If a function returns an object then `new` returns it instead of `this`.
So thay can, for instance, return the same externally defined object `obj`:
So they can, for instance, return the same externally defined object `obj`:
```js run no-beautify
let obj = {};

View file

@ -1,18 +1,22 @@
# Methods of primitives
JavaScript allows us to work with primitives (strings, numbers etc) as if they were objects.
JavaScript allows us to work with primitives (strings, numbers, etc.) as if they were objects.
They also provide methods to call as such. We will study those soon, but first we'll see how it works, because, of course, primitives are not objects (and here we will make it even more clear).
They also provide methods to call as such. We will study those soon, but first we'll see how it works because, of course, primitives are not objects (and here we will make it even clearer).
Let's look at the key distinction between primitives and objects.
Let's look at the key distinctions between primitives and objects.
A primitive
An object
: Is capable of storing multiple values as properties.
Can be created with `{}`, for instance: `{name: "John", age: 30}`. There are other kinds of objects in JavaScript, e.g. functions are objects.
- Is a value of a primitive type.
- There are 6 primitive types: `string`, `number`, `boolean`, `symbol`, `null` and `undefined`.
One of the best things about objects is that we can store a function as one of its properties:
An object
- Is capable of storing multiple values as properties.
- Can be created with `{}`, for instance: `{name: "John", age: 30}`. There are other kinds of objects in JavaScript; functions, for example, are objects.
One of the best things about objects is that we can store a function as one of its properties.
```js run
let john = {
@ -27,7 +31,7 @@ john.sayHi(); // Hi buddy!
So here we've made an object `john` with the method `sayHi`.
Many built-in objects already exist, such as those that work with dates, errors, HTML elements etc. They have different properties and methods.
Many built-in objects already exist, such as those that work with dates, errors, HTML elements, etc. They have different properties and methods.
But, these features come with a cost!

View file

@ -283,7 +283,7 @@ In most cases the distinction is unnoticeable, because operators are suited to t
Remember these two special numeric values?
- `Infinite` (and `-Infinite`) is a special numeric value that is greater (less) than anything.
- `Infinity` (and `-Infinity`) is a special numeric value that is greater (less) than anything.
- `NaN` represents an error.
They belong to the type `number`, but are not "normal" numbers, so there are special functions to check for them:
@ -349,7 +349,7 @@ But in real life we often have values in units, like `"100px"` or `"12pt"` in CS
That's what `parseInt` and `parseFloat` are for.
They "read" a number from a string until they can. In case of an error, the gathered number is returned. The function `parseInt` returns an integer, whilst `parseFloat` will return a floating-point number:
They "read" a number from a string until they can't. In case of an error, the gathered number is returned. The function `parseInt` returns an integer, whilst `parseFloat` will return a floating-point number:
```js run
alert( parseInt('100px') ); // 100

View file

@ -132,7 +132,7 @@ Note that `\n` is a single "special" character, so the length is indeed `3`.
```warn header="`length` is a property"
People with a background in some other languages sometimes mistype by calling `str.length()` instead of just `str.length`. That doesn't work.
Please note that `str.length` is a numeric property, not a function. There is no need to add brackets after it.
Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it.
```
## Accessing characters
@ -275,8 +275,8 @@ while ((pos = str.indexOf(target, pos + 1)) != -1) {
*/!*
```
```smart header="`str.lastIndexOf(pos)`"
There is also a similar method [str.lastIndexOf(pos)](mdn:js/String/lastIndexOf) that searches from the end of a string to its beginning.
```smart header="`str.lastIndexOf(substr, position)`"
There is also a similar method [str.lastIndexOf(substr, position)](mdn:js/String/lastIndexOf) that searches from the end of a string to its beginning.
It would list the occurrences in the reverse order.
```

View file

@ -8,7 +8,7 @@ The input is an array of numbers, e.g. `arr = [1, -2, 3, 4, -9, 6]`.
The task is: find the contiguous subarray of `arr` with the maximal sum of items.
Write the function `getMaxSubSum(arr)` that will find return that sum.
Write the function `getMaxSubSum(arr)` that will return that sum.
For instance:
@ -27,4 +27,4 @@ If all items are negative, it means that we take none (the subarray is empty), s
getMaxSubSum([-1, -2, -3]) = 0
```
Please try to think of a fast solution: [O(n<sup>2</sup>)](https://en.wikipedia.org/wiki/Big_O_notation) or even O(n) if you can.
Please try to think of a fast solution: [O(n<sup>2</sup>)](https://en.wikipedia.org/wiki/Big_O_notation) or even O(n) if you can.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Before After
Before After

View file

@ -1,6 +1,6 @@
# Arrays
Objects allow to store keyed collections of values. That's fine.
Objects allow you to store keyed collections of values. That's fine.
But quite often we find that we need an *ordered collection*, where we have a 1st, a 2nd, a 3rd element and so on. For example, we need that to store a list of something: users, goods, HTML elements etc.
@ -121,7 +121,7 @@ A stack is usually illustrated as a pack of cards: new cards are added to the to
For stacks, the latest pushed item is received first, that's also called LIFO (Last-In-First-Out) principle. For queues, we have FIFO (First-In-First-Out).
Arrays in JavaScript can work both as a queue and as a stack. They allow to add/remove elements both to/from the beginning or the end.
Arrays in JavaScript can work both as a queue and as a stack. They allow you to add/remove elements both to/from the beginning or the end.
In computer science the data structure that allows it is called [deque](https://en.wikipedia.org/wiki/Double-ended_queue).
@ -431,7 +431,7 @@ alert( "1,2" + 1 ); // "1,21"
## Summary
Array is a special kind of objects, suited to store and manage ordered data items.
Array is a special kind of object, suited to storing and managing ordered data items.
- The declaration:

View file

@ -3,9 +3,10 @@
*Iterable* objects is a generalization of arrays. That's a concept that allows to make any object useable in a `for..of` loop.
Arrays by themselves are iterable. But not only arrays. Strings are iterable too, and many other built-in objects as well.
Of course, Arrays are iterable. But there are many other built-in objects, that are iterable as well. For instance, Strings are iterable also. As we'll see, many built-in operators and methods rely on them.
If an object represents a collection (list, set) of something, then `for..of` is a great syntax to loop over it, so let's see how to make it work.
Iterables are widely used by the core JavaScript. As we'll see many built-in operators and methods rely on them.
## Symbol.iterator
@ -27,10 +28,10 @@ let range = {
To make the `range` iterable (and thus let `for..of` work) we need to add a method to the object named `Symbol.iterator` (a special built-in symbol just for that).
- When `for..of` starts, it calls that method (or errors if not found).
- The method must return an *iterator* -- an object with the method `next`.
- When `for..of` wants the next value, it calls `next()` on that object.
- The result of `next()` must have the form `{done: Boolean, value: any}`, where `done=true` means that the iteration is finished, otherwise `value` must be the new value.
1. When `for..of` starts, it calls that method once (or errors if not found). The method must return an *iterator* -- an object with the method `next`.
2. Onward, `for..of` works *only with that returned object*.
3. When `for..of` wants the next value, it calls `next()` on that object.
4. The result of `next()` must have the form `{done: Boolean, value: any}`, where `done=true` means that the iteration is finished, otherwise `value` must be the new value.
Here's the full implementation for `range`:
@ -43,7 +44,8 @@ let range = {
// 1. call to for..of initially calls this
range[Symbol.iterator] = function() {
// 2. ...it returns the iterator:
// ...it returns the iterator object:
// 2. Onward, for..of works only with this iterator, asking it for next values
return {
current: this.from,
last: this.to,
@ -66,10 +68,10 @@ for (let num of range) {
}
```
There is an important separation of concerns in this code:
Please note the core feature of iterables: an important separation of concerns:
- The `range` itself does not have the `next()` method.
- Instead, another object, a so-called "iterator" is created by the call to `range[Symbol.iterator]()`, and it handles the iteration.
- Instead, another object, a so-called "iterator" is created by the call to `range[Symbol.iterator]()`, and it handles the whole iteration.
So, the iterator object is separate from the object it iterates over.
@ -101,10 +103,12 @@ for (let num of range) {
}
```
Now `range[Symbol.iterator]()` returns the `range` object itself: it has the necessary `next()` method and remembers the current iteration progress in `this.current`. Sometimes that's fine too. The downside is that now it's impossible to have two `for..of` loops running over the object simultaneously: they'll share the iteration state, because there's only one iterator -- the object itself.
Now `range[Symbol.iterator]()` returns the `range` object itself: it has the necessary `next()` method and remembers the current iteration progress in `this.current`. Shorter? Yes. And sometimes that's fine too.
The downside is that now it's impossible to have two `for..of` loops running over the object simultaneously: they'll share the iteration state, because there's only one iterator -- the object itself. But two parallel for-ofs is a rare thing, doable with some async scenarios.
```smart header="Infinite iterators"
Infinite iterators are also doable. For instance, the `range` becomes infinite for `range.to = Infinity`. Or we can make an iterable object that generates an infinite sequence of pseudorandom numbers. Also can be useful.
Infinite iterators are also possible. For instance, the `range` becomes infinite for `range.to = Infinity`. Or we can make an iterable object that generates an infinite sequence of pseudorandom numbers. Also can be useful.
There are no limitations on `next`, it can return more and more values, that's normal.
@ -120,11 +124,12 @@ For a string, `for..of` loops over its characters:
```js run
for (let char of "test") {
// triggers 4 times: once for each character
alert( char ); // t, then e, then s, then t
}
```
And it works right with surrogate pairs!
And it works correctly with surrogate pairs!
```js run
let str = '𝒳😂';

View file

@ -324,7 +324,7 @@ Now where do we need such thing?
The idea of `WeakMap` is that we can store something for an object that exists only while the object exists. But we do not force the object to live by the mere fact that we store something for it.
```js
weakMap.put(john, "secret documents");
weakMap.set(john, "secret documents");
// if john dies, secret documents will be destroyed
```
@ -378,7 +378,7 @@ With a regular `Map`, cleaning up after a user has left becomes a tedious task:
`WeakSet` behaves similarly:
- It is analogous to `Set`, but we may only add objects to `WeakSet` (not primitives).
- An object exists in the set while it has reachable from somewhere else.
- An object exists in the set while it is reachable from somewhere else.
- Like `Set`, it supports `add`, `has` and `delete`, but not `size`, `keys()` and no iterations.
For instance, we can use it to keep track of whether an item is checked:
@ -429,4 +429,4 @@ The most notable limitation of `WeakMap` and `WeakSet` is the absence of iterati
- Also does not support `size/clear()` and iterations.
`WeakMap` and `WeakSet` are used as "secondary" data structures in addition to the "main" object storage. Once the object is removed from the main storage, so it only stays in `WeakMap/WeakSet`, they clean up automatically.
`WeakMap` and `WeakSet` are used as "secondary" data structures in addition to the "main" object storage. Once the object is removed from the main storage, if it is only found in the `WeakMap/WeakSet`, it will be cleaned up automatically.

View file

@ -31,8 +31,8 @@ It looks great when combined with `split` or other array-returning methods:
let [firstName, surname] = "Ilya Kantor".split(' ');
```
````smart header="\"Destructuring\" does not mean \"destructive\""
It's called "destructuring assignment", because it "destructurizes" by copying items into variables. But the array itself is not modified.
````smart header="\"Destructuring\" does not mean \"destructive\"."
It's called "destructuring assignment," because it "destructurizes" by copying items into variables. But the array itself is not modified.
It's just a shorter way to write:
```js
@ -407,7 +407,7 @@ function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
}
```
In real-life the problem is how to remember the order of arguments. Usually IDEs try to help us, especially if the code is well-documented, but still... Another problem is how to call a function when most parameters are ok by default.
In real-life, the problem is how to remember the order of arguments. Usually IDEs try to help us, especially if the code is well-documented, but still... Another problem is how to call a function when most parameters are ok by default.
Like this?
@ -502,7 +502,7 @@ In the code above, the whole arguments object is `{}` by default, so there's alw
let {prop : varName = default, ...} = object
```
This means that property `prop` should go into the variable `varName` and, if no such property exists, then `default` value should be used.
This means that property `prop` should go into the variable `varName` and, if no such property exists, then the `default` value should be used.
- The array syntax:
@ -510,6 +510,6 @@ In the code above, the whole arguments object is `{}` by default, so there's alw
let [item1 = default, item2, ...rest] = array
```
The first item goes to `item1`, the second goes into `item2`, all the rest makes the array `rest`.
The first item goes to `item1`; the second goes into `item2`, all the rest makes the array `rest`.
- For more complex cases, the left side must have the same structure as the right one.

View file

@ -66,10 +66,10 @@ alert(json);
The method `JSON.stringify(student)` takes the object and converts it into a string.
The resulting `json` string is a called *JSON-encoded* or *serialized* or *stringified* or *marshalled* object. We are ready to send it over the wire or put into plain data store.
The resulting `json` string is a called *JSON-encoded* or *serialized* or *stringified* or *marshalled* object. We are ready to send it over the wire or put into a plain data store.
Please note that JSON-encoded object has several important differences from the object literal:
Please note that a JSON-encoded object has several important differences from the object literal:
- Strings use double quotes. No single quotes or backticks in JSON. So `'John'` becomes `"John"`.
- Object property names are double-quoted also. That's obligatory. So `age:30` becomes `"age":30`.
@ -190,7 +190,7 @@ replacer
space
: Amount of space to use for formatting
Most of time, `JSON.stringify` is used with first argument only. But if we need to fine-tune the replacement process, like to filter out circular references, we can use the second argument of `JSON.stringify`.
Most of the time, `JSON.stringify` is used with the first argument only. But if we need to fine-tune the replacement process, like to filter out circular references, we can use the second argument of `JSON.stringify`.
If we pass an array of properties to it, only these properties will be encoded.
@ -244,7 +244,7 @@ Now everything except `occupiedBy` is serialized. But the list of properties is
Fortunately, we can use a function instead of an array as the `replacer`.
The function will be called for every `(key,value)` pair and should return the "replaced" value, which will be used instead of the original one.
The function will be called for every `(key, value)` pair and should return the "replaced" value, which will be used instead of the original one.
In our case, we can return `value` "as is" for everything except `occupiedBy`. To ignore `occupiedBy`, the code below returns `undefined`:
@ -281,7 +281,7 @@ number: 23
Please note that `replacer` function gets every key/value pair including nested objects and array items. It is applied recursively. The value of `this` inside `replacer` is the object that contains the current property.
The first call is special. It is made using a special "wrapper object": `{"": meetup}`. In other words, the first `(key,value)` pair has an empty key, and the value is the target object as a whole. That's why the first line is `":[object Object]"` in the example above.
The first call is special. It is made using a special "wrapper object": `{"": meetup}`. In other words, the first `(key, value)` pair has an empty key, and the value is the target object as a whole. That's why the first line is `":[object Object]"` in the example above.
The idea is to provide as much power for `replacer` as possible: it has a chance to analyze and replace/skip the whole object if necessary.
@ -332,7 +332,7 @@ The `spaces` parameter is used solely for logging and nice-output purposes.
## Custom "toJSON"
Like `toString` for a string conversion, an object may provide method `toJSON` for to-JSON conversion. `JSON.stringify` automatically calls it if available.
Like `toString` for string conversion, an object may provide method `toJSON` for to-JSON conversion. `JSON.stringify` automatically calls it if available.
For instance:
@ -409,7 +409,7 @@ str
: JSON-string to parse.
reviver
: Optional function(key,value) that will be called for each `(key,value)` pair and can transform the value.
: Optional function(key,value) that will be called for each `(key, value)` pair and can transform the value.
For instance:
@ -521,7 +521,7 @@ alert( schedule.meetups[1].date.getDate() ); // works!
## Summary
- JSON is a data format that has its own independent standard and libraries for most programming languages.
- JSON supports plain objects, arrays, strings, numbers, booleans and `null`.
- JSON supports plain objects, arrays, strings, numbers, booleans, and `null`.
- JavaScript provides methods [JSON.stringify](mdn:js/JSON/stringify) to serialize into JSON and [JSON.parse](mdn:js/JSON/parse) to read from JSON.
- Both methods support transformer functions for smart reading/writing.
- If an object has `toJSON`, then it is called by `JSON.stringify`.

View file

@ -7,7 +7,7 @@
.function-execution-context {
border: 1px solid black;
font-family: "Consolas", monospace;
font-family: 'DejaVu Sans Mono', 'Lucida Console', 'Menlo', 'Monaco', monospace;
padding: 4px 6px;
margin: 0 4px;
}
@ -23,4 +23,4 @@
.function-execution-context-list li:first-child {
font-weight: bold;
}
</style>
</style>

View file

@ -119,6 +119,8 @@ function f() {
f(1); // 1
```
````
As we remember, arrow functions don't have their own `this`. Now we know they don't have the special `arguments` object either.
## Spread operator [#spread-operator]

View file

@ -118,11 +118,11 @@ First, when a function runs, a new function Lexical Environment is created autom
<!--
```js
let phrase = "Hello";
function say(name) {
alert( `${phrase}, ${name}` );
}
say("John"); // Hello, John
```-->
@ -319,7 +319,7 @@ Here's what's going on in the `makeCounter` example step-by-step, follow it to m
In other words, a function is "imprinted" with a reference to the Lexical Environment where it was born. And `[[Environment]]` is the hidden function property that has that reference.
2. The code runs on, and the call to `makeCounter()` is performed. Here's a snapshot of the moment when the execution is on the first line inside `makeCounter()`:
2. The code runs on, the new global variable `counter` is declared and for its value `makeCounter()` is called. Here's a snapshot of the moment when the execution is on the first line inside `makeCounter()`:
![](lexenv-nested-makecounter-2.png)
@ -339,7 +339,7 @@ Here's what's going on in the `makeCounter` example step-by-step, follow it to m
![](lexenv-nested-makecounter-3.png)
Please note that on this step the inner function was created, but not yet called. The code inside `function() { return count++; }` is not running, we're going to return it.
Please note that on this step the inner function was created, but not yet called. The code inside `function() { return count++; }` is not running; we're going to return it soon.
4. As the execution goes on, the call to `makeCounter()` finishes, and the result (the tiny nested function) is assigned to the global variable `counter`:
@ -380,7 +380,7 @@ But if there were no `let name` in `makeWorker()`, then the search would go outs
```smart header="Closures"
There is a general programming term "closure", that developers generally should know.
A [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)) is a function that remembers its outer variables and can access them. In some languages, that's not possible, or a function should be written in a special way to make it happen. But as explained above, in JavaScript all functions are naturally closures (there is only one exclusion, to be covered in <info:new-function>).
A [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)) is a function that remembers its outer variables and can access them. In some languages, that's not possible, or a function should be written in a special way to make it happen. But as explained above, in JavaScript, all functions are naturally closures (there is only one exclusion, to be covered in <info:new-function>).
That is: they automatically remember where they were created using a hidden `[[Environment]]` property, and all of them can access outer variables.
@ -400,7 +400,7 @@ In the example below, when the execution goes into `if` block, the new "if-only"
<!--
```js run
let phrase = "Hello";
if (true) {
let user = "John";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Before After
Before After

View file

@ -65,7 +65,7 @@ alert(user.sayHi.name); // sayHi
alert(user.sayBye.name); // sayBye
```
There's no magic though. There are cases when there's no way to figure out the right name. In that case, the name property empty, like here:
There's no magic though. There are cases when there's no way to figure out the right name. In that case, the name property is empty, like here:
```js
// function created inside array

View file

@ -43,7 +43,7 @@ The task is quite typical -- we want to pass an object method somewhere else (he
## Solution 1: a wrapper
The simplest solution is to use an wrapping function:
The simplest solution is to use a wrapping function:
```js run
let user = {

View file

@ -191,7 +191,7 @@ The non-configurable flag (`configurable:false`) is sometimes preset for built-i
A non-configurable property can not be deleted or altered with `defineProperty`.
For instance, `Math.PI` is both read-only, non-enumerable and non-configurable:
For instance, `Math.PI` is read-only, non-enumerable and non-configurable:
```js run
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Before After
Before After

View file

@ -9,7 +9,7 @@ Clock.prototype._render = function() {
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
if (mins < 10) min = '0' + mins;
if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;

View file

@ -9,7 +9,7 @@ function Clock({ template }) {
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
if (mins < 10) min = '0' + mins;
if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;

View file

@ -10,7 +10,7 @@ class Clock {
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
if (mins < 10) min = '0' + mins;
if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;

View file

@ -11,7 +11,7 @@ Clock.prototype._render = function() {
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
if (mins < 10) min = '0' + mins;
if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;

View file

@ -10,7 +10,7 @@ class Clock {
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
if (mins < 10) min = '0' + mins;
if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;

View file

@ -10,7 +10,7 @@ class Clock {
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
if (mins < 10) min = '0' + mins;
if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;

View file

@ -255,7 +255,7 @@ The syntax is:
throw <error object>
```
Technically, we can use anything as an error object. That may be even a primitive, like a number or a string, but it's better to use objects, preferrably with `name` and `message` properties (to stay somewhat compatible with built-in errors).
Technically, we can use anything as an error object. That may be even a primitive, like a number or a string, but it's better to use objects, preferably with `name` and `message` properties (to stay somewhat compatible with built-in errors).
JavaScript has many built-in constructors for standard errors: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` and others. We can use them to create error objects as well.

View file

@ -209,7 +209,7 @@ You can see the DOM, click on elements, see their details and so on.
Please note that the DOM structure in developer tools is simplified. Text nodes are shown just as text. And there are no "blank" (space only) text nodes at all. That's fine, because most of the time we are interested in element nodes.
Clicking the <span class="devtools" style="background-position:-328px -124px"></span> button in the left-upper corner allows to choose a node from the webpage using a mouse (or other pointer devices) and "inspect" it (scroll to it in the Elements tab). This works great when we have a huge HTML page (and corresponding huge DOM) and would like to see the place of a particual element in it.
Clicking the <span class="devtools" style="background-position:-328px -124px"></span> button in the left-upper corner allows to choose a node from the webpage using a mouse (or other pointer devices) and "inspect" it (scroll to it in the Elements tab). This works great when we have a huge HTML page (and corresponding huge DOM) and would like to see the place of a particular element in it.
Another way to do it would be just right-clicking on a webpage and selecting "Inspect" in the context menu.

View file

@ -91,7 +91,7 @@ interface HTMLInputElement: HTMLElement {
// here go properties and methods of <input> elements
*!*
// "DOMString" means that these properties are strings
// "DOMString" means that the value of these properties are strings
*/!*
attribute DOMString accept;
attribute DOMString alt;
@ -99,12 +99,12 @@ interface HTMLInputElement: HTMLElement {
attribute DOMString value;
*!*
// boolean property (true/false)
// boolean value property (true/false)
attribute boolean autofocus;
*/!*
...
*!*
// now the method: "void" means that that returns no value
// now the method: "void" means that the method returns no value
*/!*
void select();
...

View file

@ -1,6 +1,6 @@
# Attributes and properties
When the browser loads the page, it "reads" (another word: "parses") HTML text and generates DOM objects from it. For element nodes most standard HTML attributes automatically become properties of DOM objects.
When the browser loads the page, it "reads" (another word: "parses") the HTML and generates DOM objects from it. For element nodes, most standard HTML attributes automatically become properties of DOM objects.
For instance, if the tag is `<body id="page">`, then the DOM object has `body.id="page"`.
@ -51,7 +51,7 @@ So, DOM properties and methods behave just like those of regular JavaScript obje
## HTML attributes
In HTML language, tags may have attributes. When the browser reads HTML text and creates DOM objects for tags, it recognizes *standard* attributes and creates DOM properties from them.
In HTML, tags may have attributes. When the browser parses the HTML to create DOM objects for tags, it recognizes *standard* attributes and creates DOM properties from them.
So when an element has `id` or another *standard* attribute, the corresponding property gets created. But that doesn't happen if the attribute is non-standard.
@ -83,9 +83,9 @@ Here we can see it:
</body>
```
So, if an attribute is non-standard, there won't be DOM-property for it. Is there a way to access such attributes?
So, if an attribute is non-standard, there won't be a DOM-property for it. Is there a way to access such attributes?
Sure. All attributes are accessible using following methods:
Sure. All attributes are accessible by using the following methods:
- `elem.hasAttribute(name)` -- checks for existence.
- `elem.getAttribute(name)` -- gets the value.
@ -138,7 +138,7 @@ Please note:
1. `getAttribute('About')` -- the first letter is uppercase here, and in HTML it's all lowercase. But that doesn't matter: attribute names are case-insensitive.
2. We can assign anything to an attribute, but it becomes a string. So here we have `"123"` as the value.
3. All attributes including ones that we set are visible in `outerHTML`.
4. The `attributes` collection is iterable and has all attributes with `name` and `value`.
4. The `attributes` collection is iterable and has all the attributes of the element (standard and non-standard) as objects with `name` and `value` properties.
## Property-attribute synchronization

View file

@ -54,5 +54,11 @@
clockStart();
</script>
<!-- click on this button calls clockStart() -->
<input type="button" onclick="clockStart()" value="Start">
<!-- click on this button calls clockStop() -->
<input type="button" onclick="clockStop()" value="Stop">
</body>
</html>

View file

@ -7,3 +7,5 @@ importance: 4
Create a colored clock like here:
[iframe src="solution" height=60]
Use HTML/CSS for the styling, Javascript only updates time in elements.

View file

@ -61,7 +61,7 @@ div.className = "alert alert-success";
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
```
After that, we have a ready DOM element. Right now it's in the variable, but can not be seen, because it's not been inserted into the page yet.
After that, we have our DOM element ready. Right now it is just in a variable and we cannot see it. That is because it's not yet inserted into the page.
## Insertion methods
@ -236,7 +236,7 @@ But what if we want to insert HTML "as html", with all tags and stuff working, l
There's another, pretty versatile method: `elem.insertAdjacentHTML(where, html)`.
The first parameter is a string, specifying where to insert, must be one of the following:
The first parameter is a string, specifying where to insert. Must be one of the following:
- `"beforebegin"` -- insert `html` before `elem`,
- `"afterbegin"` -- insert `html` into `elem`, at the beginning,
@ -273,10 +273,10 @@ We can easily notice similarities between this and the previous picture. The ins
The method has two brothers:
- `elem.insertAdjacentText(where, text)` -- the same syntax, but a string of `text` in inserted "as text" instead of HTML,
- `elem.insertAdjacentText(where, text)` -- the same syntax, but a string of `text` is inserted "as text" instead of HTML,
- `elem.insertAdjacentElement(where, elem)` -- the same syntax, but inserts an element.
They exist mainly to make the syntax "uniform". In practice, most of the time only `insertAdjacentHTML` is used, because for elements and text we have methods `append/prepend/before/after` -- they are shorter to write and can insert nodes/text pieces.
They exist mainly to make the syntax "uniform". In practice, only `insertAdjacentHTML` is used most of the time. Because for elements and text, we have methods `append/prepend/before/after` -- they are shorter to write and can insert nodes/text pieces.
So here's an alternative variant of showing a message:
@ -409,7 +409,7 @@ The syntax:
The call to `document.write(html)` writes the `html` into page "right here and now". The `html` string can be dynamically generated, so it's kind of flexible. We can use JavaScript to create a full-fledged webpage and write it.
The method comes from times when there were no DOM, no standards... Really old times. It still lives, because there are scripts using it.
The method comes from times when there was no DOM, no standards... Really old times. It still lives, because there are scripts using it.
In modern scripts we can rarely see it, because of the following important limitation:

View file

@ -1,6 +1,6 @@
# Styles and classes
Before we get to JavaScript ways of dealing with styles and classes -- here's an important rule. Hopefully it's obvious enough, but we still have to mention it.
Before we get into JavaScript's ways of dealing with styles and classes -- here's an important rule. Hopefully it's obvious enough, but we still have to mention it.
There are generally two ways to style an element:
@ -125,7 +125,7 @@ document.body.style.display = "none"; // hide
setTimeout(() => document.body.style.display = "", 1000); // back to normal
```
If we set `display` to an empty string, then the browser applies CSS classes and its built-in styles normally, as if there were no such `style` property at all.
If we set `display` to an empty string, then the browser applies CSS classes and its built-in styles normally, as if there were no such `display` property at all.
````smart header="Full rewrite with `style.cssText`"
Normally, we use `style.*` to assign individual style properties. We can't set the full style like `div.style="color: red; width: 100px"`, because `div.style` is an object, and it's read-only.
@ -147,7 +147,7 @@ To set the full style as a string, there's a special property `style.cssText`:
</script>
```
We rarely use it, because such assignment removes all existing styles: it does not add, but replaces them. May occasionally delete something needed. But still can be done for new elements when we know we don't delete something important.
We rarely use it, because such assignment removes all existing styles: it does not add, but replaces them. May occasionally delete something needed. But still can be done for new elements when we know we won't delete something important.
The same can be accomplished by setting an attribute: `div.setAttribute('style', 'color: red...')`.
````

View file

@ -2,5 +2,5 @@ Differences:
1. `clientWidth` is numeric, while `getComputedStyle(elem).width` returns a string with `px` at the end.
2. `getComputedStyle` may return non-numeric width like `"auto"` for an inline element.
3. `clientWidth` is the inner content area of the element plus paddings, while CSS width (with standard `box-sizing`) is the inner conand sometent area *without paddings*.
3. `clientWidth` is the inner content area of the element plus paddings, while CSS width (with standard `box-sizing`) is the inner content area *without paddings*.
4. If there's a scrollbar and the browser reserves the space for it, some browser substract that space from CSS width (cause it's not available for content any more), and some do not. The `clientWidth` property is always the same: scrollbar size is substracted if reserved.

View file

@ -60,13 +60,13 @@ These properties are rarely needed, but still they are the "most outer" geometry
The `offsetParent` is the nearest ancestor that is:
1. CSS-positioned (`position` is `absolute`, `relative` or `fixed`),
1. CSS-positioned (`position` is `absolute`, `relative`, `fixed` or `sticky`),
2. or `<td>`, `<th>`, `<table>`,
2. or `<body>`.
In most practical cases we can use `offsetParent` to get the nearest CSS-positioned ancestor. And `offsetLeft/offsetTop` provide x/y coordinates relative to it's left-upper corner.
In most practical cases we can use `offsetParent` to get the nearest CSS-positioned ancestor. And `offsetLeft/offsetTop` provide x/y coordinates relative to it's upper-left corner.
In the example below the inner `<div>` has `<main>` as `offsetParent` and `offsetLeft/offsetTop` shifts from its left-upper corner (`180`):
In the example below the inner `<div>` has `<main>` as `offsetParent` and `offsetLeft/offsetTop` shifts from its upper-left corner (`180`):
```html run height=10
<main style="position: relative" id="main">
@ -265,11 +265,11 @@ Please note that the described difference is only about reading `getComputedStyl
Elements have the following geometry properties:
- `offsetParent` -- is the nearest positioned ancestor or `td`, `th`, `table`, `body`.
- `offsetLeft/offsetTop` -- coordinates relative to the left-upper edge of `offsetParent`.
- `offsetLeft/offsetTop` -- coordinates relative to the upper-left edge of `offsetParent`.
- `offsetWidth/offsetHeight` -- "outer" width/height of an element including borders.
- `clientLeft/clientTop` -- the distance from the left-upper outer corner to its left-upper inner corner. For left-to-right OS they are always the widths of left/top borders. For right-to-left OS the vertical scrollbar is on the left so `clientLeft` includes its width too.
- `clientLeft/clientTop` -- the distance from the upper-left outer corner to its upper-left inner corner. For left-to-right OS they are always the widths of left/top borders. For right-to-left OS the vertical scrollbar is on the left so `clientLeft` includes its width too.
- `clientWidth/clientHeight` -- the width/height of the content including paddings, but without the scrollbar.
- `scrollWidth/scrollHeight` -- the width/height of the content including the scrolled out parts. Also includes paddings, but not the scrollbar.
- `scrollLeft/scrollTop` -- width/height of the scrolled out part of the element, starting from its left-upper corner.
- `scrollLeft/scrollTop` -- width/height of the scrolled out part of the element, starting from its upper-left corner.
All properties are read-only except `scrollLeft/scrollTop`. They make the browser scroll the element if changed.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Before After
Before After

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