edit
This commit is contained in:
parent
e78e527866
commit
05a93ced80
212 changed files with 3213 additions and 3968 deletions
|
@ -12,47 +12,41 @@ Scripts are provided and executed a plain text. They don't need a special prepar
|
||||||
|
|
||||||
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](http://en.wikipedia.org/wiki/Java).
|
||||||
|
|
||||||
[smart header="Why <u>Java</u>Script?"]
|
```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.
|
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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
```
|
||||||
[/smart]
|
|
||||||
|
|
||||||
At present, JavaScript can execute not only in the browser, but also on the server, or actually on any device where a special program called [an interpreter]("http://en.wikipedia.org/wiki/Interpreter_(computing)") is installed. The execution process is called "an interpretation".
|
At present, JavaScript can execute not only in the browser, but also on the server, or actually on any device where a special program called [an interpreter]("http://en.wikipedia.org/wiki/Interpreter_(computing)") is installed. The execution process is called "an interpretation".
|
||||||
|
|
||||||
The browser has an embedded JavaScript interpreter, sometimes it's also called a "JavaScript engine" or a "JavaScript virtual machine".
|
The browser has an embedded JavaScript interpreter, sometimes it's also called a "JavaScript engine" or a "JavaScript virtual machine".
|
||||||
|
|
||||||
Different engines have different "codenames", for example:
|
Different engines have different "codenames", for example:
|
||||||
<ul>
|
|
||||||
<li>[V8 engine]("https://en.wikipedia.org/wiki/V8_(JavaScript_engine)") -- in Chrome and Opera.</li>
|
- [V8 engine]("https://en.wikipedia.org/wiki/V8_(JavaScript_engine)") -- in Chrome and Opera.
|
||||||
<li>[Gecko]("https://en.wikipedia.org/wiki/Gecko_(software)") -- in Firefox.</li>
|
- [Gecko]("https://en.wikipedia.org/wiki/Gecko_(software)") -- in Firefox.
|
||||||
<li>...There are other codenames like "Trident", "Chakra" for different versions of IE, "Nitro" and "SquirrelFish" for Safari etc.</li>
|
- ...There are other codenames like "Trident", "Chakra" for different versions of IE, "Nitro" and "SquirrelFish" for Safari etc.
|
||||||
</ul>
|
|
||||||
|
|
||||||
The codenames are good to know. They are used when searching for detailed information in the internet. Also, we'll sometimes reference them further in the tutorial. Instead of the words "Chrome supports feature..." we'd rather say "V8 supports feature...", not just because it's more precise, but because that also implies Opera and Node.JS.
|
The codenames are good to know. They are used when searching for detailed information in the internet. Also, we'll sometimes reference them further in the tutorial. Instead of the words "Chrome supports feature..." we'd rather say "V8 supports feature...", not just because it's more precise, but because that also implies Opera and Node.JS.
|
||||||
|
|
||||||
[smart header="Compilation and interpretation"]
|
```smart header="Compilation and interpretation"
|
||||||
There are two general approaches to execute programs: "compilation" and "interpretation".
|
There are two general approaches to execute programs: "compilation" and "interpretation".
|
||||||
|
|
||||||
<ul>
|
- *Compilers* convert the program text (source code) to binary code (or kind-of) without executing it. When a developer wants to publish the program, he runs a compiler with the source code and then distributes the binary files that it produces.
|
||||||
<li>*Compilers* convert the program text (source code) to binary code (or kind-of) without executing it. When a developer wants to publish the program, he runs a compiler with the source code and then distributes the binary files that it produces.</li>
|
- *Interpreters*, and in particular the one embedded in the browser -- get the source code and execute it "as is".
|
||||||
<li>*Interpreters*, and in particular the one embedded in the browser -- get the source code and execute it "as is".</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
As we can see, an interpretation is simpler. No intermediate steps involved. But a compilation is more powerful, because the binary code is more "machine-friendly" and runs faster at the end user.
|
As we can see, an interpretation is simpler. No intermediate steps involved. But a compilation is more powerful, because the binary code is more "machine-friendly" and runs faster at the end user.
|
||||||
|
|
||||||
Modern javascript engines actually combine these approaches into one:
|
Modern javascript engines actually combine these approaches into one:
|
||||||
<ol>
|
|
||||||
<li>The script is written and distributed as a plain text (can be compressed/optimized by so-called "javascript minifiers").</li>
|
|
||||||
<li>The engine (in-browser for the web) reads the script and converts it to the machine language. And then it runs it. That's why JavaScript executes very fast.
|
|
||||||
|
|
||||||
Even more than that, the binary code may be adjusted later, through the process of its execution. The engine learns more about the actual data that it works with and then can optimize it better.</li>
|
1. The script is written and distributed as a plain text (can be compressed/optimized by so-called "javascript minifiers").
|
||||||
</ol>
|
2. The engine (in-browser for the web) reads the script and converts it to the machine language. And then it runs it. That's why JavaScript executes very fast.
|
||||||
|
|
||||||
|
Even more than that, the binary code may be adjusted later, through the process of its execution. The engine learns more about the actual data that it works with and then can optimize it better.
|
||||||
|
|
||||||
So the term "interpretation" is used mostly for historical reasons. We do know what there's actually a two-stage (at least) process behind it.
|
So the term "interpretation" is used mostly for historical reasons. We do know what there's actually a two-stage (at least) process behind it.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
|
|
||||||
## What in-browser JavaScript can do?
|
## What in-browser JavaScript can do?
|
||||||
|
|
||||||
|
@ -64,13 +58,11 @@ In the browser JavaScript can do everything related to webpage manipulation, int
|
||||||
|
|
||||||
For instance, in-browser JavaScript is able to:
|
For instance, in-browser JavaScript is able to:
|
||||||
|
|
||||||
<ul>
|
- Add new HTML to the page, change the existing content, modify styles.
|
||||||
<li>Add new HTML to the page, change the existing content, modify styles.</li>
|
- React on user actions, run on mouse clicks, pointer movements, key presses.
|
||||||
<li>React on user actions, run on mouse clicks, pointer movements, key presses.</li>
|
- Send requests over the network to remote servers, download and upload data without reloading the page (a so-called "AJAX" technology).
|
||||||
<li>Send requests over the network to remote servers, download and upload data without reloading the page (a so-called "AJAX" technology).</li>
|
- Get and set cookies, prompt user for the data, show messages.
|
||||||
<li>Get and set cookies, prompt user for the data, show messages.</li>
|
- Store data in-browser ("localStorage").
|
||||||
<li>Store data in-browser ("localStorage").</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
## What in-browser JavaScript can NOT do?
|
## What in-browser JavaScript can NOT do?
|
||||||
|
|
||||||
|
@ -78,38 +70,31 @@ JavaScript abilities in the browser are limited for the sake of the user's safet
|
||||||
|
|
||||||
The examples of such restrictions are:
|
The examples of such restrictions are:
|
||||||
|
|
||||||
<ul>
|
- JavaScript on the webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS system functions.
|
||||||
<li>JavaScript on the webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS system functions.
|
|
||||||
|
|
||||||
Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like "dropping" a file into a browser window or selecting it via an `<input>` tag.
|
Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like "dropping" a file into a browser window or selecting it via an `<input>` tag.
|
||||||
|
|
||||||
There are ways to interact with camera/microphone and other devices, but they require an explicit user's permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the NSA.
|
There are ways to interact with camera/microphone and other devices, but they require an explicit user's permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the NSA.
|
||||||
</li>
|
- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. Such action is allowed. But even in this case, JavaScript from one page may not access the other if they compe from different sites (from a different domain, protocol or port).
|
||||||
<li>Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. Such action is allowed. But even in this case, JavaScript from one page may not access the other if they compe from different sites (from a different domain, protocol or port).
|
|
||||||
|
|
||||||
That is called a "Same Origin Policy". To workaround that, *both pages* must contain a special JavaScript code that handles data exchange.
|
That is called a "Same Origin Policy". To workaround that, *both pages* must contain a special JavaScript code that handles data exchange.
|
||||||
|
|
||||||
The limitation is again for a user's safety. A page from `http://anysite.com` which a user has opened occasionaly must not be able to open or access another browser tab with the URL `http://gmail.com` and steal information from there.
|
The limitation is again for a user's safety. A page from `http://anysite.com` which a user has opened occasionaly must not be able to open or access another browser tab with the URL `http://gmail.com` and steal information from there.
|
||||||
</li>
|
- JavaScript can easily communicate over the net to the server where the current page came from. But it's ability to receive data from other sites/domains is crippled. Though possible, it requires the explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's safety limitations.
|
||||||
<li>JavaScript can easily communicate over the net to the server where the current page came from. But it's ability to receive data from other sites/domains is crippled. Though possible, it requires the explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's safety limitations.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<img src="limitations.png">
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Such limits do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow installing plugin/extensions which may get extended permissions.
|
Such limits do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow installing plugin/extensions which may get extended permissions.
|
||||||
|
|
||||||
|
|
||||||
## Why JavaScript is unique?
|
## Why JavaScript is unique?
|
||||||
|
|
||||||
There are at least *three* great things about JavaScript:
|
There are at least *three* great things about JavaScript:
|
||||||
|
|
||||||
[compare]
|
```compare
|
||||||
+Full integration with HTML/CSS.
|
+ Full integration with HTML/CSS.
|
||||||
+Simple things done simply.
|
+ Simple things done simply.
|
||||||
+Supported by all major browsers and enabled by default.
|
+ Supported by all major browsers and enabled by default.
|
||||||
[/compare]
|
```
|
||||||
|
|
||||||
Combined, these 3 things only exist in JavaScript and no other browser technology.
|
Combined, these 3 things only exist in JavaScript and no other browser technology.
|
||||||
|
|
||||||
|
@ -123,19 +108,17 @@ While planning to learn a new technology, it's beneficial to check it's perspect
|
||||||
|
|
||||||
Few examples:
|
Few examples:
|
||||||
|
|
||||||
<ul>
|
- Write files on disk (in a "sandbox", not to any folder).
|
||||||
<li>Write files on disk (in a "sandbox", not to any folder).</li>
|
- A database embedded in the browser, to keep data on a user's computer and effeciently operate on it.
|
||||||
<li>A database embedded in the browser, to keep data on a user's computer and effeciently operate on it.</li>
|
- Multitasking with the usage of many CPU cores in one time.
|
||||||
<li>Multitasking with the usage of many CPU cores in one time.</li>
|
- Audio/video playback.
|
||||||
<li>Audio/video playback.</li>
|
- 2d and 3d-drawing with hardware acceleration support, just like in modern games.
|
||||||
<li>2d and 3d-drawing with hardware acceleration support, just like in modern games.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Many new abilities are still in progress, but browsers gradually improve the support for them.
|
Many new abilities are still in progress, but browsers gradually improve the support for them.
|
||||||
|
|
||||||
[summary]
|
```summary
|
||||||
The trend: browser can do more and more, it is becoming more like an all-purpose desktop application.
|
The trend: browser can do more and more, it is becoming more like an all-purpose desktop application.
|
||||||
[/summary]
|
```
|
||||||
|
|
||||||
Still, there is a small gotcha with those "extra-fresh" modern browser abilities. Sometimes browsers try to implement them on very early stages when they are nor fully defined neither agreed upon, but are so interesting that the developers just can't wait.
|
Still, there is a small gotcha with those "extra-fresh" modern browser abilities. Sometimes browsers try to implement them on very early stages when they are nor fully defined neither agreed upon, but are so interesting that the developers just can't wait.
|
||||||
|
|
||||||
|
@ -143,9 +126,9 @@ Still, there is a small gotcha with those "extra-fresh" modern browser abilities
|
||||||
|
|
||||||
But what's great -- eventually all browsers tend to follow the standard. There are much less differences between them now than only a couple years ago.
|
But what's great -- eventually all browsers tend to follow the standard. There are much less differences between them now than only a couple years ago.
|
||||||
|
|
||||||
[summary]
|
```summary
|
||||||
The trend: browsers, though eager for new features, tend to be compatible with the standard.
|
The trend: browsers, though eager for new features, tend to be compatible with the standard.
|
||||||
[/summary]
|
```
|
||||||
|
|
||||||
## New ECMAScript
|
## New ECMAScript
|
||||||
|
|
||||||
|
@ -153,9 +136,9 @@ JavaScript evolves. The upcoming ECMAScript-2016 standard adds more language-lev
|
||||||
|
|
||||||
Modern browsers improve their engines to raise JavaScript execution script, fix bugs and try to follow the standards.
|
Modern browsers improve their engines to raise JavaScript execution script, fix bugs and try to follow the standards.
|
||||||
|
|
||||||
[summary]
|
```summary
|
||||||
The trend: JavaScript is becoming faster, gets new syntax and language features.
|
The trend: JavaScript is becoming faster, gets new syntax and language features.
|
||||||
[/summary]
|
```
|
||||||
|
|
||||||
## Languages "over" JavaScript
|
## Languages "over" JavaScript
|
||||||
|
|
||||||
|
@ -169,18 +152,13 @@ The transpilation happens automatically, modern tools make the process very fast
|
||||||
|
|
||||||
Examples of such languages:
|
Examples of such languages:
|
||||||
|
|
||||||
<ul>
|
- [CoffeeScript](http://coffeescript.org/) is a "syntax sugar" for JavaScript, it introduces shorter syntax, allowing to write more precise and clear code. Usually Ruby guys like it.
|
||||||
<li>[CoffeeScript](http://coffeescript.org/) is a "syntax sugar" for JavaScript, it introduces shorter syntax, allowing to write more precise and clear code. Usually Ruby guys like it.</li>
|
- [TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing", to simplify development and support of complex systems. Developed by Microsoft.
|
||||||
<li>[TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing", to simplify development and support of complex systems. Developed by Microsoft.</li>
|
- [Dart](https://www.dartlang.org/) is a standalone language that has it's 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 browsers require it to be transpiled to JavaScript just like the ones above.
|
||||||
<li>[Dart](https://www.dartlang.org/) is a standalone language that has it's 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 browsers require it to be transpiled to JavaScript just like the ones above.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
- JavaScript was initially created as a browser-only language, but now used in many other environments as well.
|
||||||
<li>JavaScript was initially created as a browser-only language, but now used in many other environments as well.</li>
|
- At this moment, JavaScript as a unique position as a most widely adopted browser language with full integration with HTML/CSS.
|
||||||
<li>At this moment, JavaScript as a unique position as a most widely adopted browser language with full integration with HTML/CSS.</li>
|
- There are over languages that get "transpiled" to JavaScript and provide certain features. It is recommended to take a look at them, at least briefly, after mastering JavaScript.
|
||||||
<li>There are over languages that get "transpiled" to JavaScript and provide certain features. It is recommended to take a look at them, at least briefly, after mastering JavaScript.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
The [latest standard](http://www.ecma-international.org/publications/standards/Ecma-262.htm) was approved in June 2015.
|
The [latest standard](http://www.ecma-international.org/publications/standards/Ecma-262.htm) was approved in June 2015.
|
||||||
|
|
||||||
As it includes a lot of new features, most browsers implement them partially. You can find the current state of the support at [](https://kangax.github.io/compat-table/es6/).
|
As it includes a lot of new features, most browsers implement them partially. You can find the current state of the support at <https://kangax.github.io/compat-table/es6/>.
|
||||||
|
|
||||||
## Single-engine app
|
## Single-engine app
|
||||||
|
|
||||||
|
@ -23,21 +23,18 @@ Here comes Babel.JS.
|
||||||
|
|
||||||
Actually, there are two parts in Babel:
|
Actually, there are two parts in Babel:
|
||||||
|
|
||||||
<ol>
|
1. The transpiler program, which rewrites the code.
|
||||||
<li>The transpiler program, which rewrites the code.
|
|
||||||
|
|
||||||
The transpiler runs on a developer's computer. It rewrites the code, which is then bundled by a project build system (like [webpack](http://webpack.github.io/) or [brunch](http://brunch.io/)). Most build systems can support Babel easily. One just needs to setup the build system itself.</li>
|
The transpiler runs on a developer's computer. It rewrites the code, which is then bundled by a project build system (like [webpack](http://webpack.github.io/) or [brunch](http://brunch.io/)). Most build systems can support Babel easily. One just needs to setup the build system itself.
|
||||||
<li>JavaScript library.
|
2. JavaScript library.
|
||||||
|
|
||||||
An additional JavaScript library with modern JavaScript functions for the browsers that do not have them built-in (yet). The library must be attached to each webpage which relies on these functions.</li>
|
An additional JavaScript library with modern JavaScript functions for the browsers that do not have them built-in (yet). The library must be attached to each webpage which relies on these functions.
|
||||||
</ol>
|
|
||||||
|
|
||||||
There is a special "play" mode of Babel.JS which merges both parts in a single in-browser script.
|
There is a special "play" mode of Babel.JS which merges both parts in a single in-browser script.
|
||||||
|
|
||||||
The usage looks like this:
|
The usage looks like this:
|
||||||
|
|
||||||
```html
|
```html run
|
||||||
<!--+ run -->
|
|
||||||
*!*
|
*!*
|
||||||
<!-- browser.js is on my server please don't hotlink -->
|
<!-- browser.js is on my server please don't hotlink -->
|
||||||
<script src="https://en.js.cx/babel-core/browser.min.js"></script>
|
<script src="https://en.js.cx/babel-core/browser.min.js"></script>
|
||||||
|
@ -57,16 +54,15 @@ Script `browser.min.js` is attached to the top of the page. It automatically tra
|
||||||
The size of `browser.min.js` is above 1 megabyte, because it includes the transpiler. Hence such usage is only for "playing" and not recommended for production.
|
The size of `browser.min.js` is above 1 megabyte, because it includes the transpiler. Hence such usage is only for "playing" and not recommended for production.
|
||||||
|
|
||||||
Also:
|
Also:
|
||||||
<ul>
|
|
||||||
<li>There is a "try it" page on [](https://babeljs.io/repl/) which allows to run snippets of code.</li>
|
- There is a "try it" page on <https://babeljs.io/repl/> which allows to run snippets of code.
|
||||||
<li>[JSBin](http://jsbin.com) allows to use "ES6/Babel" mode for JS, see [this snippet](http://jsbin.com/daxihelolo/edit?js,output) as an example.</li>
|
- [JSBin](http://jsbin.com) allows to use "ES6/Babel" mode for JS, see [this snippet](http://jsbin.com/daxihelolo/edit?js,output) as an example.
|
||||||
</ul>
|
|
||||||
|
|
||||||
# Examples on this site
|
# Examples on this site
|
||||||
|
|
||||||
[warn header="Browser support is required"]
|
```warn header="Browser support is required"
|
||||||
Examples that use ES-2015 will work only if your browser supports it.
|
Examples that use ES-2015 will work only if your browser supports it.
|
||||||
[/warn]
|
```
|
||||||
|
|
||||||
Sometimes it means that when running an example in a non-supporting browser, an error is shown.
|
Sometimes it means that when running an example in a non-supporting browser, an error is shown.
|
||||||
|
|
||||||
|
@ -80,7 +76,7 @@ And even if your browser does not support some code, you can run it through Babe
|
||||||
|
|
||||||
That would be fine, because on production everyone's using Babel anyway.
|
That would be fine, because on production everyone's using Babel anyway.
|
||||||
|
|
||||||
Once again, let's note that the most up-to-date situation with support is reflected on [](https://kangax.github.io/compat-table/es6/).
|
Once again, let's note that the most up-to-date situation with support is reflected on <https://kangax.github.io/compat-table/es6/>.
|
||||||
|
|
||||||
Now we can go coding, but we need a good code editor for that. That is discussed in the next session.
|
Now we can go coding, but we need a good code editor for that. That is discussed in the next session.
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,10 @@ For the comfortable development we need a good code editor.
|
||||||
|
|
||||||
It should support at least:
|
It should support at least:
|
||||||
|
|
||||||
<ol>
|
1. Syntax highlight.
|
||||||
<li>Syntax highlight.</li>
|
2. Autocompletion.
|
||||||
<li>Autocompletion.</li>
|
3. Folding -- collapsing/opening blocks of code.
|
||||||
<li>Folding -- collapsing/opening blocks of code.</li>
|
4. ...the more features -- the better.
|
||||||
<li>...the more features -- the better.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
|
@ -21,13 +19,11 @@ An IDE operates on a "whole project": loads it and then can navigate between fil
|
||||||
|
|
||||||
If you haven't considered selecting an IDE, pleae look at the following variants:
|
If you haven't considered selecting an IDE, pleae look at the following variants:
|
||||||
|
|
||||||
<ul>
|
- IntelliJ editors: [WebStorm](http://www.jetbrains.com/webstorm/) for frontend development and [PHPStorm (PHP)](http://www.jetbrains.com/phpstorm/), [IDEA (Java)](http://www.jetbrains.com/idea/), [RubyMine (Ruby)](http://www.jetbrains.com/ruby/) and other if you need additional languages.
|
||||||
<li>IntelliJ editors: [WebStorm](http://www.jetbrains.com/webstorm/) for frontend development and [PHPStorm (PHP)](http://www.jetbrains.com/phpstorm/), [IDEA (Java)](http://www.jetbrains.com/idea/), [RubyMine (Ruby)](http://www.jetbrains.com/ruby/) and other if you need additional languages.</li>
|
- Visual Studio is fine if you're a .NET developer.
|
||||||
<li>Visual Studio is fine if you're a .NET developer.</li>
|
- Eclipse-based products, like [Aptana](http://www.aptana.com/) and Zend Studio.
|
||||||
<li>Eclipse-based products, like [Aptana](http://www.aptana.com/) and Zend Studio.</li>
|
- [Komodo IDE](http://www.activestate.com/komodo-ide) and it's lightweight free version [Komodo Edit](http://www.activestate.com/komodo-edit).
|
||||||
<li>[Komodo IDE](http://www.activestate.com/komodo-ide) and it's lightweight free version [Komodo Edit](http://www.activestate.com/komodo-edit).</li>
|
- [Netbeans](http://netbeans.org/)
|
||||||
<li>[Netbeans](http://netbeans.org/)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
All of them with the exception of Visual Studio are cross-platform.
|
All of them with the exception of Visual Studio are cross-platform.
|
||||||
|
|
||||||
|
@ -45,22 +41,19 @@ In practice, "lightweight" editors may have a lot of plugins including directory
|
||||||
|
|
||||||
The following options deserve your attention:
|
The following options deserve your attention:
|
||||||
|
|
||||||
<ul>
|
- <a href="http://www.sublimetext.com">Sublime Text</a> (cross-platform, shareware).
|
||||||
<li><a href="http://www.sublimetext.com">Sublime Text</a> (cross-platform, shareware).</li>
|
- <a href="https://atom.io/">Atom</a> (cross-platform, free).
|
||||||
<li><a href="https://atom.io/">Atom</a> (cross-platform, free).</li>
|
- <a href="http://sourceforge.net/projects/notepad-plus/">Notepad++</a> (Windows, free).
|
||||||
<li><a href="http://sourceforge.net/projects/notepad-plus/">Notepad++</a> (Windows, free).</li>
|
- Vim, Emacs are cool. If you know how to use them.
|
||||||
<li>Vim, Emacs are cool. If you know how to use them.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
## My favorites
|
## My favorites
|
||||||
|
|
||||||
I believe one should have both an IDE for projects and a lightweight editor for quick and easy file editing.
|
I believe one should have both an IDE for projects and a lightweight editor for quick and easy file editing.
|
||||||
|
|
||||||
I'm using:
|
I'm using:
|
||||||
<ul>
|
|
||||||
<li>[WebStorm](http://www.jetbrains.com/webstorm/) for JS, and if there is one more language in the project, then I switch to other Jetbrains editors like [PHPStorm](http://www.jetbrains.com/phpstorm/) (PHP), [IDEA](http://www.jetbrains.com/idea/) (Java), [RubyMine](http://www.jetbrains.com/ruby/) (Ruby). There are editors for other languages too, but I didn't use them.</li>
|
- [WebStorm](http://www.jetbrains.com/webstorm/) for JS, and if there is one more language in the project, then I switch to other Jetbrains editors like [PHPStorm](http://www.jetbrains.com/phpstorm/) (PHP), [IDEA](http://www.jetbrains.com/idea/) (Java), [RubyMine](http://www.jetbrains.com/ruby/) (Ruby). There are editors for other languages too, but I didn't use them.
|
||||||
<li>As a lightweight editor -- <a href="http://www.sublimetext.com">Sublime Text</a>.</li>
|
- As a lightweight editor -- <a href="http://www.sublimetext.com">Sublime Text</a>.
|
||||||
</ul>
|
|
||||||
|
|
||||||
If you don't know what to choose -- you can consider these ones.
|
If you don't know what to choose -- you can consider these ones.
|
||||||
|
|
||||||
|
|
|
@ -26,24 +26,22 @@ Open the page [bug.html](bug.html).
|
||||||
|
|
||||||
There's an error in the JavaScript code on it. An ordinary visitor won't see it, so let's open developer tools.
|
There's an error in the JavaScript code on it. An ordinary visitor won't see it, so let's open developer tools.
|
||||||
|
|
||||||
Press the key [key F12] or, if you're on Mac, then [key Cmd+Opt+J].
|
Press the key `key:F12` or, if you're on Mac, then `key:Cmd+Opt+J`.
|
||||||
|
|
||||||
The developer tools will open on the Console tab by default.
|
The developer tools will open on the Console tab by default.
|
||||||
|
|
||||||
It looks somewhat like this:
|
It looks somewhat like this:
|
||||||
|
|
||||||
<img src="chrome.png">
|

|
||||||
|
|
||||||
The exact look depends on your Chrome version. It changes from time to time, but should be similar.
|
The exact look depends on your Chrome version. It changes from time to time, but should be similar.
|
||||||
|
|
||||||
<ul>
|
- Here we can see the red-colored error message. In this case the script contains a "lalala" command, which was put there just because it is unknown.
|
||||||
<li>Here we can see the red-colored error message. In this case the script contains a "lalala" command, which was put there just because it is unknown.</li>
|
- On the right, there is a clickable link to the source `bug.html:12` with the line number where the error has occured.
|
||||||
<li>On the right, there is a clickable link to the source `bug.html:12` with the line number where the error has occured.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Below the error message there is a blue `>` symbol. It marks a "command line" where we can type JavaScript commands and press enter to run them ([key Shift+Enter] to input multiline commands).
|
Below the error message there is a blue `>` symbol. It marks a "command line" where we can type JavaScript commands and press enter to run them (`key:Shift+Enter` to input multiline 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 [](/debugging-chrome).
|
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>.
|
||||||
|
|
||||||
## Safari
|
## Safari
|
||||||
|
|
||||||
|
@ -51,22 +49,19 @@ For Safari, we need to enable the "Develop menu" first.
|
||||||
|
|
||||||
There's a checkbox for that at the bottom of the "Advanced" pane of the preferences:
|
There's a checkbox for that at the bottom of the "Advanced" pane of the preferences:
|
||||||
|
|
||||||
<img src="safari.png">
|

|
||||||
|
|
||||||
Now [key Cmd+Opt+C] can toggle the console. Also note that the new top menu item has appeared with many useful options.
|
Now `key:Cmd+Opt+C` can toggle the console. Also note that the new top menu item has appeared with many useful options.
|
||||||
|
|
||||||
## Other browsers
|
## Other browsers
|
||||||
|
|
||||||
Most other browsers use [key F12] to open developer tools.
|
Most other browsers use `key:F12` to open developer tools.
|
||||||
|
|
||||||
The look & feel of them is quite similar, once we know how to use one of them (can start with Chrome), can easily switch to another.
|
The look & feel of them is quite similar, once we know how to use one of them (can start with Chrome), can easily switch to another.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
- Developer tools allow us to see errors, run commands, examine variables and much more.
|
||||||
<li>Developer tools allow us to see errors, run commands, examine variables and much more.</li>
|
- 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).
|
||||||
<li>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).
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Now we have the environment ready. In the next section we get down to JavaScript.
|
Now we have the environment ready. In the next section we get down to JavaScript.
|
|
@ -1,9 +1,12 @@
|
||||||
# Show an alert
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Show an alert
|
||||||
|
|
||||||
Create a page that shows a message "I'm JavaScript!".
|
Create a page that shows a message "I'm JavaScript!".
|
||||||
|
|
||||||
Do it in a sandbox, or on your hard drive, doesn't matter, just ensure that it works.
|
Do it in a sandbox, or on your hard drive, doesn't matter, just ensure that it works.
|
||||||
|
|
||||||
[demo src="solution"]
|
[demo src="solution"]
|
||||||
|
|
||||||
|
|
|
@ -3,20 +3,20 @@
|
||||||
In this chapter we'll create a simple script and see it working.
|
In this chapter we'll create a simple script and see it working.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## The "script" tag
|
## The "script" tag
|
||||||
|
|
||||||
[smart header="What if I want to move faster?"]
|
```smart header="What if I want to move faster?"
|
||||||
In the case if the reader of these lines has developed with JavaScript already or has a lot of experience in another language, he can skip detailed explanatins and jump to [](/javascript-specials). There he can find an essense of important features.
|
In the case if the reader of these lines has developed with JavaScript already or has a lot of experience in another language, he can skip detailed explanatins and jump to <info:javascript-specials>. There he can find an essense of important features.
|
||||||
|
|
||||||
If you have enough time and want to learn things in details then read on :)
|
If you have enough time and want to learn things in details then read on :)
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
JavaScript programs can be inserted in any place of HTML with the help of the `<script>` tag.
|
JavaScript programs can be inserted in any place of HTML with the help of the `<script>` tag.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```html
|
```html run height=100
|
||||||
<!--+ run height=100 -->
|
|
||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
|
@ -37,57 +37,48 @@ For instance:
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
[online]
|
```online
|
||||||
You can run the example clicking on a "Play" button in it's right-top corner.
|
You can run the example clicking on a "Play" button in it's right-top corner.
|
||||||
[/online]
|
```
|
||||||
|
|
||||||
The `<script>` tag contains JavaScript code which is automatically executed when the browser meets the tag.
|
The `<script>` tag contains JavaScript code which is automatically executed when the browser meets the tag.
|
||||||
|
|
||||||
Please note the execution sequence:
|
Please note the execution sequence:
|
||||||
|
|
||||||
<ol>
|
1. Browser starts to parse the document and display the page.
|
||||||
<li>Browser starts to parse the document and display the page.</li>
|
2. When the browser meets `<script>`, it switches to the JavaScript execution mode. In this mode it executes the script.
|
||||||
<li>When the browser meets `<script>`, it switches to the JavaScript execution mode. In this mode it executes the script.</li>
|
3. The `alert` command shows a message and pauses the execution.
|
||||||
<li>The `alert` command shows a message and pauses the execution.</li>
|
4. *Note that a part of the page before the script is shown already at this moment.*
|
||||||
<li>*Note that a part of the page before the script is shown already at this moment.*</li>
|
5. When the script is finished, it gets back to the HTML-mode, and *only then* it shows the rest of the document.
|
||||||
<li>When the script is finished, it gets back to the HTML-mode, and *only then* it shows the rest of the document.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
A visitor won't see the content after the script until it is executed. In other words, a `<script>` tag blocks rendering.
|
A visitor won't see the content after the script until it is executed. In other words, a `<script>` tag blocks rendering.
|
||||||
|
|
||||||
|
|
||||||
## The modern markup
|
## The modern markup
|
||||||
|
|
||||||
In the past, `<script>` had a few necessary attributes.
|
In the past, `<script>` had a few necessary attributes.
|
||||||
|
|
||||||
We can find the following in the old code:
|
We can find the following in the old code:
|
||||||
|
|
||||||
<dl>
|
The `type` attribute: <code><script <u>type</u>=...></code>
|
||||||
<dt>The `type` attribute: <code><script <u>type</u>=...></code></dt>
|
|
||||||
|
|
||||||
<dd>The old standard HTML4 required a script to have the type. Usually it was `type="text/javascript"`. The modern HTML standard assumes this `type` by default, no attribute is required.
|
: The old standard HTML4 required a script to have the type. Usually it was `type="text/javascript"`. The modern HTML standard assumes this `type` by default, no attribute is required.
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>The `language` attribute: <code><script <u>language</u>=...></code></dt>
|
The `language` attribute: <code><script <u>language</u>=...></code>
|
||||||
<dd>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.</dd>
|
: 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.
|
||||||
<dt>Comments before and after scripts.</dt>
|
|
||||||
<dd>In really ancient books and guides, one may find comments inside `<script>`, like this:
|
|
||||||
|
|
||||||
```html
|
Comments before and after scripts.
|
||||||
<!--+ no-beautify -->
|
: In really ancient books and guides, one may find comments inside `<script>`, like this:
|
||||||
<script type="text/javascript"><!--
|
|
||||||
|
```html no-beautify
|
||||||
|
<script type="text/javascript"><!--
|
||||||
...
|
...
|
||||||
//--></script>
|
//--></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
These comments were supposed to hide the code from an old browser that did't understand a `<script>` tag. But all browsers born in the past 15 years know about `<script>`, so that's not an issue. So if you see such code somewhere you know the guide is really old and probably not worth looking into.
|
These comments were supposed to hide the code from an old browser that did't understand a `<script>` tag. But all browsers born in the past 15 years know about `<script>`, so that's not an issue. So if you see such code somewhere you know the guide is really old and probably not worth looking into.
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
- We can use a `<script>` tag without attributes to add JavaScript code to the page.
|
||||||
<li>We can use a `<script>` tag without attributes to add JavaScript code to the page.</li>
|
- A `<script>` tag blocks page rendering. Can be bad. Later we'll see how to evade that.
|
||||||
<li>A `<script>` tag blocks page rendering. Can be bad. Later we'll see how to evade that.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
JavaScript-code:
|
JavaScript-code:
|
||||||
|
|
||||||
```js
|
```js demo run
|
||||||
//+ demo run
|
|
||||||
let name = prompt("What is your name?", "");
|
let name = prompt("What is your name?", "");
|
||||||
alert( name );
|
alert( name );
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
# A simple page
|
importance: 4
|
||||||
|
|
||||||
[importance 4]
|
---
|
||||||
|
|
||||||
|
# A simple page
|
||||||
|
|
||||||
Create a web-page which asks for a name and outputs it.
|
Create a web-page which asks for a name and outputs it.
|
||||||
|
|
||||||
[demo /]
|
[demo]
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
This chapter covers basic UI operations: `alert`, `prompt` and `confirm`. They allow to ask a visitor for the input and show the results.
|
This chapter covers basic UI operations: `alert`, `prompt` and `confirm`. They allow to ask a visitor for the input and show the results.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## alert
|
## alert
|
||||||
|
|
||||||
Syntax:
|
Syntax:
|
||||||
|
@ -15,8 +16,7 @@ This shows a message and pauses the script execution until the user presses "OK"
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( "Hello" );
|
alert( "Hello" );
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -26,50 +26,45 @@ The small window with the message is called a *modal window*. The word "modal" m
|
||||||
|
|
||||||
Function `prompt` accepts two arguments:
|
Function `prompt` accepts two arguments:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
result = prompt(title, default);
|
result = prompt(title, default);
|
||||||
```
|
```
|
||||||
|
|
||||||
It shows a modal window with the given `title`, a field for text, initially filled with the `default` string and buttons OK/CANCEL.
|
It shows a modal window with the given `title`, a field for text, initially filled with the `default` string and buttons OK/CANCEL.
|
||||||
|
|
||||||
The visitor may type something in the field and press OK. Or he can cancel the input by pressing a CANCEL button or the [key Esc] key.
|
The visitor may type something in the field and press OK. Or he can cancel the input by pressing a CANCEL button or the `key:Esc` key.
|
||||||
|
|
||||||
The call to `prompt` returns the text from the field or `null` if te input is canceled.
|
The call to `prompt` returns the text from the field or `null` if te input is canceled.
|
||||||
|
|
||||||
[warn header="Safari 5.1+ does not return `null`"]
|
```warn header="Safari does not return `null`"
|
||||||
Safari is the only browser which does not return `null` when the input was canceled. It returns an empty string instead.
|
Safari returns an empty string instead of `null` on cancellation. So we can't be sure whether the user actually entered an empty line or he cancelled the input.
|
||||||
|
|
||||||
To make the code compatible with that browser, we should consider both an empty line and `null` as a cancellation.
|
A compatible practice is to treat both an empty line and `null` the same, as a cancellation.
|
||||||
[/warn]
|
```
|
||||||
|
|
||||||
As with `alert`, the `prompt` window is modal.
|
As with `alert`, the `prompt` window is modal.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let age = prompt('How old are you?', 100);
|
let age = prompt('How old are you?', 100);
|
||||||
|
|
||||||
alert(`You are ${age} years old!`); // You are 100 years old! (for default prompt value)
|
alert(`You are ${age} years old!`); // You are 100 years old!
|
||||||
```
|
```
|
||||||
|
|
||||||
[warn header="Always supply a `default`"]
|
````warn header="IE: always supply a `default`"
|
||||||
The second parameter is optional. But if we don't supply it, Internet Explorer would insert the text `"undefined"` into the prompt.
|
The second parameter is optional. But if we don't supply it, Internet Explorer would insert the text `"undefined"` into the prompt.
|
||||||
|
|
||||||
Run this code in Internet Explorer to see that:
|
Run this code in Internet Explorer to see that:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let test = prompt("Test");
|
let test = prompt("Test");
|
||||||
```
|
```
|
||||||
|
|
||||||
So, to look good in IE, it's recommended to always provide the second argument:
|
So, to look good in IE, it's recommended to always provide the second argument:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let test = prompt("Test", ''); // <-- for IE
|
let test = prompt("Test", ''); // <-- for IE
|
||||||
```
|
```
|
||||||
[/warn]
|
````
|
||||||
|
|
||||||
|
|
||||||
## confirm
|
## confirm
|
||||||
|
|
||||||
|
@ -85,8 +80,7 @@ The result is `true` if OK is pressed and `false` otherwise.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let isBoss = confirm("Are you the boss?");
|
let isBoss = confirm("Are you the boss?");
|
||||||
|
|
||||||
alert( isBoss ); // true is OK is pressed
|
alert( isBoss ); // true is OK is pressed
|
||||||
|
@ -94,15 +88,18 @@ alert( isBoss ); // true is OK is pressed
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
`alert`
|
||||||
<li>`alert` shows a message.</li>
|
: shows a message.
|
||||||
<li>`prompt` shows a message asking the user to input text. It returns the text or, if CANCEL or [key Esc] is clicked, all browsers except Safari return `null`.</li>
|
|
||||||
<li>`confirm` shows a message and waits the user to press "OK" or "CANCEL". It returns `true` for OK and `false` for CANCEL/[key Esc].</li>
|
|
||||||
</ul>
|
|
||||||
There are two limitations shared by all the methods above:
|
|
||||||
<ol>
|
|
||||||
<li>The exact location of the modal window is determined by the browser. Usually it's in the center.</li>
|
|
||||||
<li>The exact look of the window also depends on the browser. We can't modify it.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
That is the price for simplicity. There are other ways to show nicer windows and interact with the visitor, but if "bells and whistles" do not matter much, these methods work just fine.
|
`prompt`
|
||||||
|
: shows a message asking the user to input text. It returns the text or, if CANCEL or `key:Esc` is clicked, all browsers except Safari return `null`.
|
||||||
|
|
||||||
|
`confirm`
|
||||||
|
: shows a message and waits the user to press "OK" or "CANCEL". It returns `true` for OK and `false` for CANCEL/`key:Esc`.
|
||||||
|
|
||||||
|
There are two limitations shared by all the methods above:
|
||||||
|
|
||||||
|
1. The exact location of the modal window is determined by the browser. Usually it's in the center.
|
||||||
|
2. The exact look of the window also depends on the browser. We can't modify it.
|
||||||
|
|
||||||
|
That is the price for simplicity. There are other ways to show nicer windows and richer interaction with the visitor, but if "bells and whistles" do not matter much, these methods work just fine.
|
||||||
|
|
|
@ -4,8 +4,7 @@ Any string except an empty one (and `"0"` is not empty) becomes `true` in the lo
|
||||||
|
|
||||||
We can run and check:
|
We can run and check:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
if ("0") {
|
if ("0") {
|
||||||
alert( 'Hello' );
|
alert( 'Hello' );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# if (a string with zero)
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# if (a string with zero)
|
||||||
|
|
||||||
Will `alert` be shown?
|
Will `alert` be shown?
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
|
|
||||||
```html
|
[html run src="ifelse_task2/index.html"]
|
||||||
<!--+ run src="ifelse_task2/index.html" -->
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
# The name of JavaScript
|
importance: 2
|
||||||
|
|
||||||
[importance 2]
|
---
|
||||||
|
|
||||||
|
# The name of JavaScript
|
||||||
|
|
||||||
Using the `if..else` construct, write the code which asks: 'What is the "official" name of JavaScript?'
|
Using the `if..else` construct, write the code which asks: 'What is the "official" name of JavaScript?'
|
||||||
|
|
||||||
If the visitor enters "ECMAScript", then output "Right!", otherwise -- output: "Didn't know? ECMAScript!"
|
If the visitor enters "ECMAScript", then output "Right!", otherwise -- output: "Didn't know? ECMAScript!"
|
||||||
|
|
||||||
<img src="ifelse_task2.png">
|

|
||||||
|
|
||||||
[demo src="ifelse_task2"]
|
[demo src="ifelse_task2"]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let value = prompt('Type a number', 0);
|
let value = prompt('Type a number', 0);
|
||||||
|
|
||||||
if (value > 0) {
|
if (value > 0) {
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
# Show the sign
|
importance: 2
|
||||||
|
|
||||||
[importance 2]
|
---
|
||||||
|
|
||||||
|
# Show the sign
|
||||||
|
|
||||||
Using `if..else`, write the code which gets a number via `prompt` and then shows in `alert`:
|
Using `if..else`, write the code which gets a number via `prompt` and then shows in `alert`:
|
||||||
|
|
||||||
<ul>
|
- `1`, if the value is greater than zero,
|
||||||
<li>`1`, if the value is greater than zero,</li>
|
- `-1`, if less than zero,
|
||||||
<li>`-1`, if less than zero,</li>
|
- `0`, if equals zero.
|
||||||
<li>`0`, if equals zero.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
In this task we assume that the input is always a number.
|
In this task we assume that the input is always a number.
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
```js
|
```js run demo
|
||||||
//+ run demo
|
|
||||||
let userName = prompt('Who's there?', '');
|
let userName = prompt('Who's there?', '');
|
||||||
|
|
||||||
if (userName == 'Admin') {
|
if (userName == 'Admin') {
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
# Check the login
|
importance: 3
|
||||||
|
|
||||||
[importance 3]
|
---
|
||||||
|
|
||||||
|
# Check the login
|
||||||
|
|
||||||
Write the code which asks for a login with `prompt`.
|
Write the code which asks for a login with `prompt`.
|
||||||
|
|
||||||
If the visitor enters `"Admin"`, then `prompt` for a password, if the input is an empty line or [key Esc] -- show "Canceled.", if it's another string -- then show "I don't know you".
|
If the visitor enters `"Admin"`, then `prompt` for a password, if the input is an empty line or `key:Esc` -- show "Canceled.", if it's another string -- then show "I don't know you".
|
||||||
|
|
||||||
The password is checked as follows:
|
The password is checked as follows:
|
||||||
<ul>
|
|
||||||
<li>If it equals "TheMaster", then show "Welcome!",</li>
|
- If it equals "TheMaster", then show "Welcome!",
|
||||||
<li>Another string -- show "Wrong password",</li>
|
- Another string -- show "Wrong password",
|
||||||
<li>For an empty string or cancelled input, show "Canceled."</li>
|
- For an empty string or cancelled input, show "Canceled."
|
||||||
</ul>
|
|
||||||
|
|
||||||
The schema:
|
The schema:
|
||||||
|
|
||||||
<img src="ifelse_task.png">
|

|
||||||
|
|
||||||
Please use nested `if` blocks. Mind the overall readability of the code.
|
Please use nested `if` blocks. Mind the overall readability of the code.
|
||||||
|
|
||||||
[demo /]
|
[demo]
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Rewrite 'if' into '?'
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Rewrite 'if' into '?'
|
||||||
|
|
||||||
Rewrite this `if` using the ternary operator `'?'`:
|
Rewrite this `if` using the ternary operator `'?'`:
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Rewrite 'if..else' into '?'
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Rewrite 'if..else' into '?'
|
||||||
|
|
||||||
Rewrite `if..else` using multiple ternary operators `'?'`.
|
Rewrite `if..else` using multiple ternary operators `'?'`.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Conditional operators: if, '?'
|
# Conditional operators: if, '?'
|
||||||
|
|
||||||
Sometimes we need to perform different actions basing on a condition. There's an `if` operator for that and also the "question mark" `?` operator for conditional evaluation.
|
Sometimes we need to perform different actions basing on a condition.
|
||||||
|
|
||||||
|
There's an `if` operator for that and also the "question mark" operator: `"?"` for conditional evaluation.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
|
@ -10,8 +12,7 @@ The "if" operator gets a condition, evaluates it and -- if the result is `true`
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
@ -19,7 +20,7 @@ if (year == 2015) alert( 'You are right!' );
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
In the example above, the condition is a simple equality: `year == 2015`, but it can be much more complex.
|
In the example above, the condition is a simple equality check: `year == 2015`, but it can be much more complex.
|
||||||
|
|
||||||
If there's more than one command to execute -- we can use a code block in figure brackets:
|
If there's more than one command to execute -- we can use a code block in figure brackets:
|
||||||
|
|
||||||
|
@ -37,10 +38,9 @@ It is recommended to use figure brackets every time with `if`, even if there's o
|
||||||
The `if (…)` operator evaluates the condition in brackets and converts it to boolean type.
|
The `if (…)` operator evaluates the condition in brackets and converts it to boolean type.
|
||||||
|
|
||||||
Let's recall the rules. In the logical context:
|
Let's recall the rules. In the logical context:
|
||||||
<ul>
|
|
||||||
<li>A number `0`, an empty string `""`, `null`, `undefined` and `NaN` are `false`,</li>
|
- A number `0`, an empty string `""`, `null`, `undefined` and `NaN` are `false`,
|
||||||
<li>Other values -- `true`.</li>
|
- Other values -- `true`.
|
||||||
</ul>
|
|
||||||
|
|
||||||
So, the code under this condition would never execute:
|
So, the code under this condition would never execute:
|
||||||
|
|
||||||
|
@ -73,8 +73,7 @@ if (cond) {
|
||||||
The `if` operator may contain an optional "else" block. It executes when the condition is wrong.
|
The `if` operator may contain an optional "else" block. It executes when the condition is wrong.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
||||||
|
|
||||||
if (year == 2015) {
|
if (year == 2015) {
|
||||||
|
@ -90,8 +89,7 @@ Sometimes we'd like to test several variants of a condition. There's an `else if
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
||||||
|
|
||||||
if (year < 2015) {
|
if (year < 2015) {
|
||||||
|
@ -105,20 +103,18 @@ if (year < 2015) {
|
||||||
|
|
||||||
In the code above JavaScript first checks `year < 2015`, if it is falsy then goes to the next condition `year > 2015`. Any number of `else if` may follow with an optional last `else`.
|
In the code above JavaScript first checks `year < 2015`, if it is falsy then goes to the next condition `year > 2015`. Any number of `else if` may follow with an optional last `else`.
|
||||||
|
|
||||||
|
|
||||||
## Ternary operator '?'
|
## Ternary operator '?'
|
||||||
|
|
||||||
Sometimes we need to assign a variable depending on a condition.
|
Sometimes we need to assign a variable depending on a condition.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
let hasAccess;
|
let hasAccess;
|
||||||
let age = prompt('How old are you?', '');
|
let age = prompt('How old are you?', '');
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
if (age > 14) {
|
if (age > 18) {
|
||||||
hasAccess = true;
|
hasAccess = true;
|
||||||
} else {
|
} else {
|
||||||
hasAccess = false;
|
hasAccess = false;
|
||||||
|
@ -142,36 +138,33 @@ The `condition` is evaluated, if it's truthy then `value1` is returned, otherwis
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let hasAccess = (age > 14) ? true : false;
|
let hasAccess = (age > 18) ? true : false;
|
||||||
```
|
```
|
||||||
|
|
||||||
We can omit brackets around `age > 14`, because the question mark operator has a low precedence. It executes after comparisons, so:
|
We can omit brackets around `age > 14`, because the question mark operator has a low precedence. It executes after comparisons, so:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// the same
|
// the same
|
||||||
let hasAccess = age > 14 ? true : false;
|
let hasAccess = age > 18 ? true : false;
|
||||||
```
|
```
|
||||||
|
|
||||||
...But brackets make the code more readable. So it's recommended to put them.
|
...But brackets make the code more readable. So it's recommended to put them.
|
||||||
|
|
||||||
[smart]
|
````smart
|
||||||
In the described case it is possible to evade the question mark operator, because the comparison by itself returns `true/false`:
|
In the described case it is possible to evade the question mark operator, because the comparison by itself returns `true/false`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// the same
|
// the same
|
||||||
let hasAccess = age > 14;
|
let hasAccess = age > 18;
|
||||||
```
|
```
|
||||||
|
````
|
||||||
But that's only in this case. Generally, the question mark can return any value.
|
|
||||||
[/smart]
|
|
||||||
|
|
||||||
## Multiple '?'
|
## Multiple '?'
|
||||||
|
|
||||||
A sequence of question mark `"?"` operators allows to return a value depending on more than one condition.
|
A sequence of question mark `"?"` operators allows to return a value depending on more than one condition.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let age = prompt('age?', 18);
|
let age = prompt('age?', 18);
|
||||||
|
|
||||||
let message = (age < 3) ? 'Hi, baby!' :
|
let message = (age < 3) ? 'Hi, baby!' :
|
||||||
|
@ -184,9 +177,12 @@ alert( message );
|
||||||
|
|
||||||
It may be difficult at first to grasp what's going on. But looking more carefully we note that it's just an ordinary sequence of tests.
|
It may be difficult at first to grasp what's going on. But looking more carefully we note that it's just an ordinary sequence of tests.
|
||||||
|
|
||||||
The question mark first checks for `age < 3`. If true -- returns `'Hi, baby!'`, otherwise -- goes to the right side of the colon `":"` and checks for `age < 18`. If that's true -- returns `'Hello!'`, otherwise checks for `age < 100` and returns `'Greetings!'` if that is so... At last, if all checks are falsy, the `message` becomes `'What an unusual age!'`.
|
1. The first question mark checks for `age < 3`.
|
||||||
|
2. If true -- returns `'Hi, baby!'`, otherwise -- goes to the right side of the colon `":"` and checks for `age < 18`.
|
||||||
|
3. If that's true -- returns `'Hello!'`, otherwise checks for `age < 100` and returns `'Greetings!'` if that is so...
|
||||||
|
4. At last, if all checks are falsy, the `message` becomes `'What an unusual age!'`.
|
||||||
|
|
||||||
The same with `if..else`:
|
The same logic using `if..else`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
if (age < 3) {
|
if (age < 3) {
|
||||||
|
@ -204,8 +200,7 @@ if (age < 3) {
|
||||||
|
|
||||||
Sometimes the question mark `'?'` is used as a replacement for `if`:
|
Sometimes the question mark `'?'` is used as a replacement for `if`:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
let company = prompt('Which company created JavaScript?', '');
|
let company = prompt('Which company created JavaScript?', '');
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
@ -216,16 +211,15 @@ let company = prompt('Which company created JavaScript?', '');
|
||||||
|
|
||||||
Depending on the condition `company == 'Netscape'`, either the first or the second part after `"?"` gets executed and shows the alert.
|
Depending on the condition `company == 'Netscape'`, either the first or the second part after `"?"` gets executed and shows the alert.
|
||||||
|
|
||||||
We don't assign a result to a variable here, the `alert` doesn't return anything anyway.
|
We don't assign a result to a variable here, cause the `alert` doesn't return anything anyway, our purpose is only to execute it.
|
||||||
|
|
||||||
**It is not recommended to use a question mark in this way.**
|
**It is not recommended to use the question mark operator in this way.**
|
||||||
|
|
||||||
The notation seem to be shorter than `if`, that appeals to some programmers. Although it is less readable.
|
The notation seem to be shorter than `if`, that appeals to some programmers. But it is less readable.
|
||||||
|
|
||||||
Here's the same with `if` for comparison:
|
Here's the same with `if` for comparison:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
let company = prompt('Which company created JavaScript?', '');
|
let company = prompt('Which company created JavaScript?', '');
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
The answer is `2`, that's the first truthy value.
|
The answer is `2`, that's the first truthy value.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( null || 2 || undefined );
|
alert( null || 2 || undefined );
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# What's the result of OR?
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# What's the result of OR?
|
||||||
|
|
||||||
What the code below is going to output?
|
What the code below is going to output?
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
The answer: first `1`, then `2`.
|
The answer: first `1`, then `2`.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( alert(1) || 2 || alert(3) );
|
alert( alert(1) || 2 || alert(3) );
|
||||||
```
|
```
|
||||||
|
|
||||||
The call to `alert` does not return a value. Or, in other words, it returns `undefined`.
|
The call to `alert` does not return a value. Or, in other words, it returns `undefined`.
|
||||||
|
|
||||||
<ol>
|
1. The first OR `||` evaluates it's left operand `alert(1)`. That shows the first message with `1`.
|
||||||
<li>The first OR `||` evaluates it's left operand `alert(1)`. That shows the first message with `1`.</li>
|
2. The `alert` returns `undefined`, so OR goes on to the second operand in it's search of a truthy value.
|
||||||
<li>The `alert` returns `undefined`, so OR goes on to the second operand in it's search of a truthy value.</li>
|
3. The second operand `2` is truthy, so the execution is halted, `2` is returned and then shown by the outer alert.
|
||||||
<li>The second operand `2` is truthy, so the execution is halted, `2` is returned and then shown by the outer alert.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
There will be no `3`, because the evaluation does not reach `alert(3)`.
|
There will be no `3`, because the evaluation does not reach `alert(3)`.
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# What's the result of OR'ed alerts?
|
importance: 3
|
||||||
|
|
||||||
[importance 3]
|
---
|
||||||
|
|
||||||
|
# What's the result of OR'ed alerts?
|
||||||
|
|
||||||
What the code below will output?
|
What the code below will output?
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
The answer: `null`, because it's the first falsy value from the list.
|
The answer: `null`, because it's the first falsy value from the list.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 1 && null && 2 );
|
alert( 1 && null && 2 );
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# What is the result of AND?
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# What is the result of AND?
|
||||||
|
|
||||||
What this code is going to show?
|
What this code is going to show?
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
The answer: `1`, and then `undefined`.
|
The answer: `1`, and then `undefined`.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( alert(1) && alert(2) );
|
alert( alert(1) && alert(2) );
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# What is the result of AND'ed alerts?
|
importance: 3
|
||||||
|
|
||||||
[importance 3]
|
---
|
||||||
|
|
||||||
|
# What is the result of AND'ed alerts?
|
||||||
|
|
||||||
What will this code show?
|
What will this code show?
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
The answer: `3`.
|
The answer: `3`.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( null || 2 && 3 || 4 );
|
alert( null || 2 && 3 || 4 );
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# The result of OR AND OR
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# The result of OR AND OR
|
||||||
|
|
||||||
What will be the result?
|
What will be the result?
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Check the range between
|
importance: 3
|
||||||
|
|
||||||
[importance 3]
|
---
|
||||||
|
|
||||||
|
# Check the range between
|
||||||
|
|
||||||
Write an "if" condition to check that `age` is between `14` and `90` inclusively.
|
Write an "if" condition to check that `age` is between `14` and `90` inclusively.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Check the range outside
|
importance: 3
|
||||||
|
|
||||||
[importance 3]
|
---
|
||||||
|
|
||||||
|
# Check the range outside
|
||||||
|
|
||||||
Write an `if` condition to check that `age` is NOT between 14 and 90 inclusively.
|
Write an `if` condition to check that `age` is NOT between 14 and 90 inclusively.
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@ The answer: the first and the third will execute.
|
||||||
|
|
||||||
Details:
|
Details:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
// Runs.
|
// Runs.
|
||||||
// The result of -1 || 0 = -1, truthy
|
// The result of -1 || 0 = -1, truthy
|
||||||
if (-1 || 0) alert( 'first' );
|
if (-1 || 0) alert( 'first' );
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# A question about "if"
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# A question about "if"
|
||||||
|
|
||||||
Which of these `alert`s are going to execute?
|
Which of these `alert`s are going to execute?
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,7 @@ In JavaScript the operator is a little bit more tricky and powerful. But first l
|
||||||
|
|
||||||
A table of possible logical combinations:
|
A table of possible logical combinations:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( true || true ); // true
|
alert( true || true ); // true
|
||||||
alert( false || true ); // true
|
alert( false || true ); // true
|
||||||
alert( true || false ); // true
|
alert( true || false ); // true
|
||||||
|
@ -36,19 +35,17 @@ If an operand is not boolean, then it's converted to boolean for the evaluation.
|
||||||
|
|
||||||
For instance, a number `1` is treated as `true`, a number `0` -- as `false`:
|
For instance, a number `1` is treated as `true`, a number `0` -- as `false`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
if (1 || 0) { // works just like if( true || false )
|
if (1 || 0) { // works just like if( true || false )
|
||||||
alert( 'truthy!' );
|
alert( 'truthy!' );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Mainly, OR is used in the `if` expression to test if *any* of given conditions is correct.
|
Most of time, OR `||` is used in the `if` expression to test if *any* of given conditions is correct.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let hour = 9;
|
let hour = 9;
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
@ -60,8 +57,7 @@ if (hour < 10 || hour > 18) {
|
||||||
|
|
||||||
We can pass more conditions:
|
We can pass more conditions:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let hour = 12;
|
let hour = 12;
|
||||||
let isWeekend = true;
|
let isWeekend = true;
|
||||||
|
|
||||||
|
@ -84,18 +80,15 @@ result = value1 || value2 || value3;
|
||||||
|
|
||||||
The OR `"||"` operator is doing the following:
|
The OR `"||"` operator is doing the following:
|
||||||
|
|
||||||
<ul>
|
- Evalutes operands from left to right.
|
||||||
<li>Evalutes operands from left to right.</li>
|
- For each value converts it to boolean and stops immediately returning it if it's true.
|
||||||
<li>For each value converts it to boolean and stops immediately if it's true.</li>
|
- The value is returned in it's original form, without the conversion.
|
||||||
<li>Returns the value where it stopped. The value is returned in it's original form, without the conversion.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
In other words, it returns the first truthy value or the last one if no such value found.
|
In other words, it returns the first truthy value or the last one if no such value found.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 1 || 0 ); // 1 (is truthy)
|
alert( 1 || 0 ); // 1 (is truthy)
|
||||||
alert( true || 'no matter what' ); // (true is truthy)
|
alert( true || 'no matter what' ); // (true is truthy)
|
||||||
|
|
||||||
|
@ -108,61 +101,55 @@ This logic does not contradict to what was spoken above. If you check this behav
|
||||||
|
|
||||||
But there leads to some interesting usages compared to a "pure, classical, boolean-only OR".
|
But there leads to some interesting usages compared to a "pure, classical, boolean-only OR".
|
||||||
|
|
||||||
<ol>
|
1. **Getting the first truthy value from the list of variables or expressions.**
|
||||||
<li>**Getting the first truthy value from the list of variables or expressions.**
|
|
||||||
|
|
||||||
Imagine, we have several variables, which can either contain the data or be `null/undefined`. And we need to choose the first one with data.
|
Imagine we have several variables, which can either contain the data or be `null/undefined`. And we need to choose the first one with data.
|
||||||
|
|
||||||
Using OR for that:
|
Using OR `||` for that:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let currentUser = null;
|
||||||
let currentUser = null;
|
let defaultUser = "John";
|
||||||
let defaultUser = "John";
|
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
let name = currentUser || defaultUser || "unnamed";
|
let name = currentUser || defaultUser || "unnamed";
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
alert( name ); // selects "John" – the first truthy value
|
alert( name ); // selects "John" – the first truthy value
|
||||||
```
|
```
|
||||||
|
|
||||||
If both `currentUser` and `defaultUser` were falsy then `"unnamed"` would be the result.
|
If both `currentUser` and `defaultUser` were falsy then `"unnamed"` would be the result.
|
||||||
</li>
|
2. **Short-circuit evaluation.**
|
||||||
<li>**Short-circuit evaluation.**
|
|
||||||
|
|
||||||
Operands can be not only values, but arbitrary expressions. OR evaluates and tests them from left to right. The evaluation stops when a truthy value is reached, and the value is returned. The process is called "a short-circuit evaluation", because it goes as short as possible from left to right.
|
Operands can be not only values, but arbitrary expressions. OR evaluates and tests them from left to right. The evaluation stops when a truthy value is reached, and the value is returned. The process is called "a short-circuit evaluation", because it goes as short as possible from left to right.
|
||||||
|
|
||||||
This is clearly seen when the expression given as the second argument has a side effect. Like a variable assignment.
|
This is clearly seen when the expression given as the second argument has a side effect. Like a variable assignment.
|
||||||
|
|
||||||
If we run the example below, `x` will not get assigned:
|
If we run the example below, `x` would not get assigned:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
let x;
|
||||||
let x;
|
|
||||||
|
|
||||||
*!*true*/!* || (x = 1);
|
*!*true*/!* || (x = 1);
|
||||||
|
|
||||||
alert(x); // undefined, (x = 1) not evaluated
|
alert(x); // undefined, because (x = 1) not evaluated
|
||||||
```
|
```
|
||||||
|
|
||||||
...And if the first argument were `false`, then `OR` would goes on and evaluate the second one thus running the assignment:
|
...And if the first argument were `false`, then `OR` would goes on and evaluate the second one thus running the assignment:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
let x;
|
||||||
let x;
|
|
||||||
|
|
||||||
*!*false*/!* || (x = 1);
|
*!*false*/!* || (x = 1);
|
||||||
|
|
||||||
alert(x); // 1
|
alert(x); // 1
|
||||||
```
|
```
|
||||||
An assignment is a simple case, other side effects can be involved.
|
|
||||||
|
|
||||||
As we can see, such use case is a "shorter way to `if`". The first operand is converted to boolean and if it's false then the second one is evaluated. It's recommended to use `if` for that for code clarity.
|
An assignment is a simple case, other side effects can be involved.
|
||||||
|
|
||||||
</li>
|
As we can see, such use case is a "shorter way to do `if`". The first operand is converted to boolean and if it's false then the second one is evaluated.
|
||||||
</ol>
|
|
||||||
|
|
||||||
|
Most of time it's better to use `if` for that for code clarity.
|
||||||
|
|
||||||
## && (AND)
|
## && (AND)
|
||||||
|
|
||||||
|
@ -174,8 +161,7 @@ result = a && b;
|
||||||
|
|
||||||
In classic programming AND returns `true` if both operands are truthy and `false` -- otherwise:
|
In classic programming AND returns `true` if both operands are truthy and `false` -- otherwise:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( true && true ); // true
|
alert( true && true ); // true
|
||||||
alert( false && true ); // false
|
alert( false && true ); // false
|
||||||
alert( true && false ); // false
|
alert( true && false ); // false
|
||||||
|
@ -184,8 +170,7 @@ alert( false && false ); // false
|
||||||
|
|
||||||
An example with `if`:
|
An example with `if`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let hour = 12;
|
let hour = 12;
|
||||||
let minute = 30;
|
let minute = 30;
|
||||||
|
|
||||||
|
@ -196,34 +181,34 @@ if (hour == 12 && minute == 30) {
|
||||||
|
|
||||||
Just as for OR, any value is allowed as an operand of AND and gets converted to a boolean in the process:
|
Just as for OR, any value is allowed as an operand of AND and gets converted to a boolean in the process:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
if (1 && 0) { // evaluated as true && false
|
if (1 && 0) { // evaluated as true && false
|
||||||
alert( "won't work, because the result is falsy" );
|
alert( "won't work, because the result is falsy" );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
More formally, given multiple AND'ed values:
|
|
||||||
|
## AND seeks the first falsy value
|
||||||
|
|
||||||
|
Given multiple AND'ed values:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
result = value1 && value2 && value3;
|
result = value1 && value2 && value3;
|
||||||
```
|
```
|
||||||
|
|
||||||
The AND `"&&"` operator is doing the following:
|
The AND `"&&"` operator is doing the following:
|
||||||
<ul>
|
|
||||||
<li>Evalutes operands from left to right.</li>
|
|
||||||
<li>For each value converts it to a boolean. If the result is `false`, stops.</li>
|
|
||||||
<li>Returns the value where it stopped "as is", without the conversion.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
In other words, AND returns the first falsy value or the last one if all are truthy.
|
- Evalutes operands from left to right.
|
||||||
|
- For each value converts it to a boolean. If the result is `false`, stops and returns it without conversion.
|
||||||
|
- If values finished (all are truthy), returns the last one.
|
||||||
|
|
||||||
|
In other words, AND returns the first falsy value or the last one if none found.
|
||||||
|
|
||||||
The rules above are similar to OR. The difference is that AND returns the first *falsy* value while OR returns the first *truthy* one.
|
The rules above are similar to OR. The difference is that AND returns the first *falsy* value while OR returns the first *truthy* one.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
// if the first operand is truthy,
|
// if the first operand is truthy,
|
||||||
// && returns the second one.
|
// && returns the second one.
|
||||||
alert( 1 && 0 ); // 0
|
alert( 1 && 0 ); // 0
|
||||||
|
@ -235,38 +220,33 @@ alert( null && 5 ); // null
|
||||||
alert( 0 && "no matter what" ); // 0
|
alert( 0 && "no matter what" ); // 0
|
||||||
```
|
```
|
||||||
|
|
||||||
We can also pass several values in a row. The first falsy one is returned:
|
We can also pass several values in a row. See how the first falsy one is returned:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 1 && 2 && null && 3 ); // null
|
alert( 1 && 2 && null && 3 ); // null
|
||||||
```
|
```
|
||||||
|
|
||||||
...Or the last one if all of them are truthy:
|
...And now when all of them are truthy:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
alert( 1 && 2 && 3 ); // 3, the last one
|
||||||
alert( 1 && 2 && 3 ); // 3, all truthy
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
````smart header="AND `&&` executes before OR `||`"
|
||||||
[smart header="AND `&&` executes before OR `||`"]
|
|
||||||
The precedence of the AND `&&` operator is higher than OR `||`, so it executes before OR.
|
The precedence of the AND `&&` operator is higher than OR `||`, so it executes before OR.
|
||||||
|
|
||||||
In the code below `1 && 0` is calculated first:
|
In the code below `1 && 0` is calculated first:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 5 || 1 && 0 ); // 5
|
alert( 5 || 1 && 0 ); // 5
|
||||||
```
|
```
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
Just like OR, the AND `&&` operator can sometimes replace `if`.
|
Just like OR, the AND `&&` operator can sometimes replace `if`.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let x = 1;
|
let x = 1;
|
||||||
|
|
||||||
(x > 0) && alert( 'Greater than zero!' );
|
(x > 0) && alert( 'Greater than zero!' );
|
||||||
|
@ -276,8 +256,7 @@ The action in the right part of `&&` would execute only if the evaluation reache
|
||||||
|
|
||||||
So we basically have an analogue for:
|
So we basically have an analogue for:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let x = 1;
|
let x = 1;
|
||||||
|
|
||||||
if (x > 0) {
|
if (x > 0) {
|
||||||
|
@ -291,7 +270,7 @@ So it is recommended to use every construct for it's purpose. Use `if` if we wan
|
||||||
|
|
||||||
## ! (NOT)
|
## ! (NOT)
|
||||||
|
|
||||||
The boolean NOT operator is represented with an exclamation `"!"`.
|
The boolean NOT operator is represented with an exclamation sign `"!"`.
|
||||||
|
|
||||||
The syntax is one of the simplest:
|
The syntax is one of the simplest:
|
||||||
|
|
||||||
|
@ -301,33 +280,28 @@ result = !value;
|
||||||
|
|
||||||
The operator accepts a single argument and does the following:
|
The operator accepts a single argument and does the following:
|
||||||
|
|
||||||
<ol>
|
1. Converts the operand to boolean type: `true/false`.
|
||||||
<li>Converts the operand to boolean type: `true/false`.</li>
|
2. Returns an inverse value.
|
||||||
<li>Returns an inverse value.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( !true ); // false
|
alert( !true ); // false
|
||||||
alert( !0 ); // true
|
alert( !0 ); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
A double NOT is sometimes used for converting a value to boolean type:
|
A double NOT is sometimes used for converting a value to boolean type:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( !!"non-empty string" ); // true
|
alert( !!"non-empty string" ); // true
|
||||||
alert( !!null ); // false
|
alert( !!null ); // false
|
||||||
```
|
```
|
||||||
|
|
||||||
That is: the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again, so we have a plain value-to-boolean conversion.
|
That is: the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again, so we have a plain value-to-boolean conversion.
|
||||||
|
|
||||||
Although, there's a more obvious way to do that: a built-in `Boolean` function:
|
There's a little more verbose to do the same -- a built-in `Boolean` function:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( Boolean("non-empty string") ); // true
|
alert( Boolean("non-empty string") ); // true
|
||||||
alert( Boolean(null) ); // false
|
alert( Boolean(null) ); // false
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
The answer: `1`.
|
The answer: `1`.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i = 3;
|
let i = 3;
|
||||||
|
|
||||||
while (i) {
|
while (i) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Last loop value
|
importance: 3
|
||||||
|
|
||||||
[importance 3]
|
---
|
||||||
|
|
||||||
|
# Last loop value
|
||||||
|
|
||||||
What is be the last value alerted by this code? Why?
|
What is be the last value alerted by this code? Why?
|
||||||
|
|
||||||
|
|
|
@ -1,37 +1,31 @@
|
||||||
The task demonstrates how postfix/prefix forms can lead to different results when used in comparisons.
|
The task demonstrates how postfix/prefix forms can lead to different results when used in comparisons.
|
||||||
|
|
||||||
<ol>
|
1. **From 1 to 4**
|
||||||
<li>**From 1 to 4**
|
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let i = 0;
|
||||||
let i = 0;
|
while (++i < 5) alert( i );
|
||||||
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.
|
||||||
</li>
|
2. **From 1 to 5**
|
||||||
<li>**From 1 to 5**
|
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let i = 0;
|
||||||
let i = 0;
|
while (i++ < 5) alert( i );
|
||||||
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.
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
# Which values shows the while?
|
importance: 4
|
||||||
|
|
||||||
[importance 4]
|
---
|
||||||
|
|
||||||
|
# Which values shows the while?
|
||||||
|
|
||||||
For every loop, scribe down which values it shows, in your opinion.
|
For every loop, scribe down which values it shows, in your opinion.
|
||||||
|
|
||||||
And then compare with the answer.
|
And then compare with the answer.
|
||||||
|
|
||||||
<ol>
|
1. The prefix form `++i`:
|
||||||
<li>The prefix form `++i`:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (++i < 5) alert( i );
|
while (++i < 5) alert( i );
|
||||||
```
|
```
|
||||||
|
2. The postfix form `i++`
|
||||||
|
|
||||||
</li>
|
```js
|
||||||
<li>The postfix form `i++`
|
let i = 0;
|
||||||
|
while (i++ < 5) alert( i );
|
||||||
|
```
|
||||||
|
|
||||||
```js
|
|
||||||
let i = 0;
|
|
||||||
while (i++ < 5) alert( i );
|
|
||||||
```
|
|
||||||
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
**The answer: from `0` to `4` in both cases.**
|
**The answer: from `0` to `4` in both cases.**
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
for (let i = 0; i < 5; ++i) alert( i );
|
for (let i = 0; i < 5; ++i) alert( i );
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) alert( i );
|
for (let i = 0; i < 5; i++) alert( i );
|
||||||
```
|
```
|
||||||
|
|
||||||
That can be easily deducted from the algorithm of `for`:
|
That can be easily deducted from the algorithm of `for`:
|
||||||
<ol>
|
|
||||||
<li>Execute once `i=0` before everything.</li>
|
1. Execute once `i=0` before everything.
|
||||||
<li>Check the condition `i<5`</li>
|
2. Check the condition `i<5`
|
||||||
<li>If `true` -- execute the loop body `alert(i)`, and then `i++`</li>
|
3. If `true` -- execute the loop body `alert(i)`, and then `i++`
|
||||||
</ol>
|
|
||||||
|
|
||||||
The increment `i++` is separated from the condition check (2). That's just another statement.
|
The increment `i++` is separated from the condition check (2). That's just another statement.
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
# Which values get shown by the "for" loop?
|
importance: 4
|
||||||
|
|
||||||
[importance 4]
|
---
|
||||||
|
|
||||||
|
# Which values get shown by the "for" loop?
|
||||||
|
|
||||||
For each loop scribe down which values it is going to show.
|
For each loop scribe down which values it is going to show.
|
||||||
|
|
||||||
Then compare with the answer.
|
Then compare with the answer.
|
||||||
|
|
||||||
<ol>
|
1. The postfix form:
|
||||||
<li>The postfix form:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
for (let i = 0; i < 5; i++) alert( i );
|
for (let i = 0; i < 5; i++) alert( i );
|
||||||
```
|
```
|
||||||
|
2. The prefix form:
|
||||||
|
|
||||||
</li>
|
```js
|
||||||
<li>The prefix form:
|
for (let i = 0; i < 5; ++i) alert( i );
|
||||||
|
```
|
||||||
|
|
||||||
```js
|
|
||||||
for (let i = 0; i < 5; ++i) alert( i );
|
|
||||||
```
|
|
||||||
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
```js
|
```js run demo
|
||||||
//+ run demo
|
|
||||||
for (let i = 2; i <= 10; i++) {
|
for (let i = 2; i <= 10; i++) {
|
||||||
if (i % 2 == 0) {
|
if (i % 2 == 0) {
|
||||||
alert( i );
|
alert( i );
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# Output even numbers in the loop
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Output even numbers in the loop
|
||||||
|
|
||||||
Use the `for` loop to output even numbers from `2` to `10`.
|
Use the `for` loop to output even numbers from `2` to `10`.
|
||||||
|
|
||||||
[demo /]
|
[demo]
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < 3) {
|
while (i < 3) {
|
||||||
alert( `number ${i}!` );
|
alert( `number ${i}!` );
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# Replace "for" with "while"
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Replace "for" with "while"
|
||||||
|
|
||||||
Rewrite the code changing the `for` loop to `while` without altering it's behavior (the output should stay same).
|
Rewrite the code changing the `for` loop to `while` without altering it's behavior (the output should stay same).
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
alert( `number ${i}!` );
|
alert( `number ${i}!` );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
|
|
||||||
```js
|
```js run demo
|
||||||
//+ run demo
|
|
||||||
let num;
|
let num;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -9,9 +8,8 @@ do {
|
||||||
```
|
```
|
||||||
|
|
||||||
The loop `do..while` repeats while both checks are truthy:
|
The loop `do..while` repeats while both checks are truthy:
|
||||||
<ol>
|
|
||||||
<li>The check for `num <= 100` -- that is, the entered value is still not greater than `100`.</li>
|
1. The check for `num <= 100` -- that is, the entered value is still not greater than `100`.
|
||||||
<li>The check for a truthiness of `num` checks that `num != null` and `num != ""` simultaneously.</li>
|
2. The check for a truthiness of `num` checks that `num != null` and `num != ""` simultaneously.
|
||||||
</ol>
|
|
||||||
|
|
||||||
P.S. By the way, if `num` is `null` then `num <= 100` would return `false`, not `true`!
|
P.S. By the way, if `num` is `null` then `num <= 100` would return `false`, not `true`!
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Repeat until the input is incorrect
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Repeat until the input is incorrect
|
||||||
|
|
||||||
Write a loop which prompts for a number greater than `100`. If the visitor enters another number -- ask him to repeat the input, and so on.
|
Write a loop which prompts for a number greater than `100`. If the visitor enters another number -- ask him to repeat the input, and so on.
|
||||||
|
|
||||||
|
@ -8,4 +10,5 @@ The loop must ask for a number until either the visitor enters a number greater
|
||||||
|
|
||||||
Here we can assume that the visitor only inputs numbers. There's no need to implement the special handling for a non-numeric input in this task.
|
Here we can assume that the visitor only inputs numbers. There's no need to implement the special handling for a non-numeric input in this task.
|
||||||
|
|
||||||
[demo /]
|
[demo]
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,7 @@ For each i in the interval {
|
||||||
|
|
||||||
The code using a label:
|
The code using a label:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
nextPrime:
|
nextPrime:
|
||||||
for (let i = 2; i < 10; i++) { // for each i...
|
for (let i = 2; i < 10; i++) { // for each i...
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Output prime numbers
|
importance: 3
|
||||||
|
|
||||||
[importance 3]
|
---
|
||||||
|
|
||||||
|
# Output prime numbers
|
||||||
|
|
||||||
An integer number greater than `1` is called a [prime](https://en.wikipedia.org/wiki/Prime_number) if it cannot be not divided without a remainder by anything except `1` and itself.
|
An integer number greater than `1` is called a [prime](https://en.wikipedia.org/wiki/Prime_number) if it cannot be not divided without a remainder by anything except `1` and itself.
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ For example, when we need to output goods from the list one after another. Or ju
|
||||||
*Loops* are a way to repeat the same part of code multiple times.
|
*Loops* are a way to repeat the same part of code multiple times.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## The "while" loop
|
## The "while" loop
|
||||||
|
|
||||||
The `while` loop has the following syntax:
|
The `while` loop has the following syntax:
|
||||||
|
@ -21,8 +22,7 @@ While the `condition` is `true` -- the `code` from the loop body is executed.
|
||||||
|
|
||||||
For instance, the loop below outputs `i` while `i<3`:
|
For instance, the loop below outputs `i` while `i<3`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < 3) { // shows 0, then 1, then 2
|
while (i < 3) { // shows 0, then 1, then 2
|
||||||
alert( i );
|
alert( i );
|
||||||
|
@ -38,8 +38,7 @@ The `while` converts `condition` to a logical value. It can be any expression, n
|
||||||
|
|
||||||
For instance, the shorter way to write `while (i!=0)` could be `while (i)`:
|
For instance, the shorter way to write `while (i!=0)` could be `while (i)`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i = 3;
|
let i = 3;
|
||||||
*!*
|
*!*
|
||||||
while (i) { // when i becomes 0, the condition is falsy and the loop stops
|
while (i) { // when i becomes 0, the condition is falsy and the loop stops
|
||||||
|
@ -49,18 +48,16 @@ while (i) { // when i becomes 0, the condition is falsy and the loop stops
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="Brackes are not required for a single-line body"]
|
````smart header="Brackes are not required for a single-line body"
|
||||||
|
|
||||||
If the loop body has a single statement, we can omit the brackets `{…}`:
|
If the loop body has a single statement, we can omit the brackets `{…}`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i = 3;
|
let i = 3;
|
||||||
*!*
|
*!*
|
||||||
while (i) alert(i--);
|
while (i) alert(i--);
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
## The "do..while" loop
|
## The "do..while" loop
|
||||||
|
|
||||||
|
@ -76,8 +73,7 @@ The loop will first execute the body and then check the condition.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
do {
|
do {
|
||||||
alert( i );
|
alert( i );
|
||||||
|
@ -101,8 +97,7 @@ for (begin; condition; step) {
|
||||||
|
|
||||||
Let's see these parts in an example. The loop below runs `alert(i)` for `i` from `0` up to (but not including) `3`:
|
Let's see these parts in an example. The loop below runs `alert(i)` for `i` from `0` up to (but not including) `3`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i;
|
let i;
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) { // shows 0, then 1, then 2
|
for (i = 0; i < 3; i++) { // shows 0, then 1, then 2
|
||||||
|
@ -110,45 +105,41 @@ for (i = 0; i < 3; i++) { // shows 0, then 1, then 2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Here the parts are:
|
Let's split the last example into parts:
|
||||||
<ul>
|
|
||||||
<li>**Begin:** `i=0`.</li>
|
|
||||||
<li>**Condition:** `i<3`.</li>
|
|
||||||
<li>**Step:** `i++`.</li>
|
|
||||||
<li>**Body:** `alert(i)`, the code inside figure brackets. Brackets not required for a single statement.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
The `for` loop execution follows these steps:
|
begin: `i=0`
|
||||||
|
: Executes once upon entering the loop.
|
||||||
|
|
||||||
<ol>
|
condition: `i<3`
|
||||||
<li>**Begin**: `i=0` executes only once upon entering the loop.</li>
|
: Checked before every loop iteration, if fails the loop stops.
|
||||||
<li>**Condition**: `i<3` is checked before every iteration. If it fails, the loop stops.</li>
|
|
||||||
<li>**Body**: `alert(i)` runs is the condition is truthy.</li>
|
|
||||||
<li>**Step**: `i++` executes after the `body` on each iteration, but before the `condition` check.</li>
|
|
||||||
<li>Continue to step 2.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
In other words, the execution flow is:
|
body: `alert(i)`
|
||||||
|
: Runs again and again while the condition is truthy
|
||||||
|
|
||||||
|
step: `i++`
|
||||||
|
: Executes after the body on each iteration, but before the condition check.
|
||||||
|
|
||||||
|
The execution flow is:
|
||||||
```
|
```
|
||||||
Begin
|
Begin
|
||||||
→ (if condition → run body and step)
|
→ (if condition → run body and run step)
|
||||||
→ (if condition → run body and step)
|
→ (if condition → run body and run step)
|
||||||
→ ... repeat until the condition is falsy.
|
→ ... repeat until the condition is falsy.
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="Inline variable declaration"]
|
````smart header="Inline variable declaration"
|
||||||
We can declare a "counter" variable right in the beginning of the loop.
|
We can declare a "counter" variable right in the beginning of the loop.
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
for (*!*let*/!* i = 0; i < 3; i++) {
|
for (*!*let*/!* i = 0; i < 3; i++) {
|
||||||
alert(i); // 0, 1, 2
|
alert(i); // 0, 1, 2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
[/smart]
|
|
||||||
|
|
||||||
|
The variable will be visible only inside the loop.
|
||||||
|
````
|
||||||
|
|
||||||
## Skipping of "for" parts
|
## Skipping parts
|
||||||
|
|
||||||
Any part of the `for` can be skipped.
|
Any part of the `for` can be skipped.
|
||||||
|
|
||||||
|
@ -156,8 +147,7 @@ For example, we can omit `begin` if we don't need to do anything at the loop sta
|
||||||
|
|
||||||
Like here:
|
Like here:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
for (; i < 3; i++) {
|
for (; i < 3; i++) {
|
||||||
|
@ -169,8 +159,7 @@ It would work same as `for(let i=0; ...)`.
|
||||||
|
|
||||||
We can also remove the `step` part:
|
We can also remove the `step` part:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
for (; i < 3;) {
|
for (; i < 3;) {
|
||||||
|
@ -189,12 +178,11 @@ for (;;) {
|
||||||
|
|
||||||
Please note that the semicolons `;` must present, otherwise it would be a syntax error.
|
Please note that the semicolons `;` must present, otherwise it would be a syntax error.
|
||||||
|
|
||||||
[smart header="`for..in`"]
|
```smart header="`for..in` and `for..of`"
|
||||||
There is also a special construct `for..in` to iterate over object properties.
|
There are special constructs: `for..in` and `for..of` for more advanced iterations over objects.
|
||||||
|
|
||||||
We'll get to it later while [talking about objects](#for..in).
|
|
||||||
[/smart]
|
|
||||||
|
|
||||||
|
We'll get to them later, in chapters about objects.
|
||||||
|
```
|
||||||
|
|
||||||
## Breaking the loop
|
## Breaking the loop
|
||||||
|
|
||||||
|
@ -223,29 +211,29 @@ alert( 'Sum: ' + sum );
|
||||||
|
|
||||||
The `break` directive is activated in the line `(*)` if the user enters an empty line or cancels the input. It stops the loop immediately, passing the control to the first line after it's loop. Namely, `alert`.
|
The `break` directive is activated in the line `(*)` if the user enters an empty line or cancels the input. It stops the loop immediately, passing the control to the first line after it's loop. Namely, `alert`.
|
||||||
|
|
||||||
Actually, the composition: "an infinite loop + break" is a great thing for situations when the condition must be checked not in beginning/end of the loop, but in the middle.
|
The composition: "infinite loop + break as needed" is a great thing for situations when the condition must be checked not in beginning/end of the loop, but in the middle. Or even in several places of the body.
|
||||||
|
|
||||||
## Continue to the next iteration [#continue]
|
## Continue to the next iteration [#continue]
|
||||||
|
|
||||||
The `continue` directive is a younger sister of `break`. It doesn't stop the whole loop. Instead if stops the current iteration and forces the loop to start a new one (if the condition allows).
|
The `continue` directive is a "lighter version" of `break`. It doesn't stop the whole loop. Instead if stops the current iteration and forces the loop to start a new one (if the condition allows).
|
||||||
|
|
||||||
We can use it if we're done on the current iteration and would like to move on to the next.
|
We can use it if we're done on the current iteration and would like to move on to the next.
|
||||||
|
|
||||||
The loop above uses `continue` to output only odd values:
|
The loop above uses `continue` to output only odd values:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
|
|
||||||
|
// if true, skip the remaining part of the body
|
||||||
*!*if (i % 2 == 0) continue;*/!*
|
*!*if (i % 2 == 0) continue;*/!*
|
||||||
|
|
||||||
alert(i);
|
alert(i); // 1, then 3, 5, 7, 9
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For even `i` the `continue` directive stops body execution, passing the control to the next iteration of `for` (with the next number). So the `alert` is only called for odd values.
|
For even values of `i` the `continue` directive stops body execution, passing the control to the next iteration of `for` (with the next number). So the `alert` is only called for odd values.
|
||||||
|
|
||||||
[smart header="`continue` allows to decrease nesting level"]
|
````smart header="The directive `continue` helps to decrease nesting level"
|
||||||
A loop for odd-only values could look like this:
|
A loop for odd-only values could look like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -261,12 +249,12 @@ for (let i = 0; i < 10; i++) {
|
||||||
From the technical point of view it's identical. Surely, we can just wrap the code in the `if` block instead of `continue`.
|
From the technical point of view it's identical. Surely, we can just wrap the code in the `if` block instead of `continue`.
|
||||||
|
|
||||||
But as a side-effect we got one more figure brackets nesting level. If the code inside `if` is longer than a few lines, that may decrease the overall readability.
|
But as a side-effect we got one more figure brackets nesting level. If the code inside `if` is longer than a few lines, that may decrease the overall readability.
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
[warn header="No `break/continue` to the right side of '?'"]
|
````warn header="No `break/continue` to the right side of '?'"
|
||||||
Please note that syntax constructs that are not expressions cannot be used in `'?'`. In particular, directives `break/continue` are disallowed there.
|
Please note that syntax constructs that are not expressions cannot be used in `'?'`. In particular, directives `break/continue` are disallowed there.
|
||||||
|
|
||||||
For example, if one would rewrite an `if` like that into a question mark:
|
For example, if one we took this code:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
if (i > 5) {
|
if (i > 5) {
|
||||||
|
@ -276,15 +264,18 @@ if (i > 5) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
...Then the code like this will give a syntax error:
|
...And rewrote it using a question mark:
|
||||||
|
|
||||||
```js
|
|
||||||
//+ no-beautify
|
```js no-beautify
|
||||||
(i > 5) ? alert(i) : *!*continue*/!*; // continue not allowed here
|
(i > 5) ? alert(i) : *!*continue*/!*; // continue not allowed here
|
||||||
```
|
```
|
||||||
|
|
||||||
|
...Then it won't work. The code like this will give a syntax error:
|
||||||
|
|
||||||
|
|
||||||
That's just another reason not to use a question mark operator `'?'` instead of `if`.
|
That's just another reason not to use a question mark operator `'?'` instead of `if`.
|
||||||
[/warn]
|
````
|
||||||
|
|
||||||
## Labels for break/continue
|
## Labels for break/continue
|
||||||
|
|
||||||
|
@ -292,9 +283,7 @@ Sometimes we need to break out from multiple nested loops at once.
|
||||||
|
|
||||||
For example, in the code below we loop over `i` and `j` asking for values on coordinates `(i, j)` from `(0,0)` to `(3,3)`:
|
For example, in the code below we loop over `i` and `j` asking for values on coordinates `(i, j)` from `(0,0)` to `(3,3)`:
|
||||||
|
|
||||||
|
```js run no-beautify
|
||||||
```js
|
|
||||||
//+ run no-beautify
|
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
|
|
||||||
for (let j = 0; j < 3; j++) {
|
for (let j = 0; j < 3; j++) {
|
||||||
|
@ -324,8 +313,7 @@ We can put the `labelName` after a break statement, and it will break out of the
|
||||||
|
|
||||||
Like here:
|
Like here:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
*!*outer:*/!* for (let i = 0; i < 3; i++) {
|
*!*outer:*/!* for (let i = 0; i < 3; i++) {
|
||||||
|
|
||||||
for (let j = 0; j < 3; j++) {
|
for (let j = 0; j < 3; j++) {
|
||||||
|
@ -347,15 +335,14 @@ So the control goes straight from `(*)` to `alert('Done!')`.
|
||||||
|
|
||||||
We can also move a label into the separate string:
|
We can also move a label into the separate string:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
outer:
|
outer:
|
||||||
for (let i = 0; i < 3; i++) { ... }
|
for (let i = 0; i < 3; i++) { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
The `continue` directive can also be used with a label. In this case the execution would jump onto the next iteration of the labelled loop.
|
The `continue` directive can also be used with a label. In this case the execution would jump onto the next iteration of the labelled loop.
|
||||||
|
|
||||||
[warn header="Labels are not a \"goto\""]
|
````warn header="Labels are not a \"goto\""
|
||||||
Labels do not allow to jump into an arbitrary place of code.
|
Labels do not allow to jump into an arbitrary place of code.
|
||||||
|
|
||||||
For example, it is impossible to do like this:
|
For example, it is impossible to do like this:
|
||||||
|
@ -365,18 +352,16 @@ break label; // jumps to label? No.
|
||||||
label: for(...)
|
label: for(...)
|
||||||
```
|
```
|
||||||
|
|
||||||
The call to a `break` is only possible from inside the loop, and the label must be somewhere upwards from the `break`.
|
The call to a `break/continue` is only possible from inside the loop, and the label must be somewhere upwards from the directive.
|
||||||
[/warn]
|
````
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
There are 3 types of loops in JavaScript:
|
There are 3 types of loops in JavaScript:
|
||||||
|
|
||||||
<ul>
|
- `while` -- the condition is checked before each iteration.
|
||||||
<li>`while` -- the condition is checked before each iteration.</li>
|
- `do..while` -- the condition is checked after each iteration.
|
||||||
<li>`do..while` -- the condition is checked after each iteration.</li>
|
- `for` -- the condition is checked before each iteration, additional settings available.
|
||||||
<li>`for` -- the condition is checked before each iteration, additional settings available.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
To make in "infinite" loop, usually the `while(true)` construct is used. Such a loop, just like any other, can be stopped with the `break` directive.
|
To make in "infinite" loop, usually the `while(true)` construct is used. Such a loop, just like any other, can be stopped with the `break` directive.
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@ To be precise, the `if` must use a strict comparison `'==='`.
|
||||||
|
|
||||||
In reality though, probably a simple `'=='` would do.
|
In reality though, probably a simple `'=='` would do.
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
if(browser == 'Edge') {
|
if(browser == 'Edge') {
|
||||||
alert("You've got the Edge!");
|
alert("You've got the Edge!");
|
||||||
} else if (browser == 'Chrome'
|
} else if (browser == 'Chrome'
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Rewrite the "switch" into an "if"
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Rewrite the "switch" into an "if"
|
||||||
|
|
||||||
Write the code using `if..else` which would correspond to the following `switch`:
|
Write the code using `if..else` which would correspond to the following `switch`:
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
The first two checks are a usual `case`. The third one is split into two cases:
|
The first two checks are a usual `case`. The third one is split into two cases:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = +prompt('a?', '');
|
let a = +prompt('a?', '');
|
||||||
|
|
||||||
switch (a) {
|
switch (a) {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# Rewrite "if" into "switch"
|
importance: 4
|
||||||
|
|
||||||
[importance 4]
|
---
|
||||||
|
|
||||||
|
# Rewrite "if" into "switch"
|
||||||
|
|
||||||
Rewrite the code below using a single `switch` statement:
|
Rewrite the code below using a single `switch` statement:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = +prompt('a?', '');
|
let a = +prompt('a?', '');
|
||||||
|
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
|
|
|
@ -5,12 +5,12 @@ A `switch` statement can replace multiple `if` checks.
|
||||||
It gives a more descriptive way to compare a value with multiple variants.
|
It gives a more descriptive way to compare a value with multiple variants.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## The syntax
|
## The syntax
|
||||||
|
|
||||||
It looks like this:
|
It looks like this:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
switch(x) {
|
switch(x) {
|
||||||
case 'value1': // if (x === 'value1')
|
case 'value1': // if (x === 'value1')
|
||||||
...
|
...
|
||||||
|
@ -26,20 +26,15 @@ switch(x) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<ul>
|
- The value of `x` is checked for a strict equality to the value from the first `case`, that is: `value1`, then to the second `value2` and so on.
|
||||||
<li>The value of `x` is checked for a strict equality to the value from the first `case`, that is: `value1`, then to the second `value2` and so on.
|
- If the equality is found -- `switch` starts to execute the code starting from the corresponding `case`, and to the nearest `break` (or to the end of `switch`).
|
||||||
</li>
|
- If no case matched then the `default` code is executed (if exists).
|
||||||
<li>If the equality is found -- `switch` starts to execute the code starting from the corresponding `case`, and to the nearest `break` (or to the end of `switch`).
|
|
||||||
</li>
|
|
||||||
<li>If no case matched then the `default` code is executed (if exists).</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
## An example
|
## An example
|
||||||
|
|
||||||
An example of `switch` (the executed code is highlighted):
|
An example of `switch` (the executed code is highlighted):
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = 2 + 2;
|
let a = 2 + 2;
|
||||||
|
|
||||||
switch (a) {
|
switch (a) {
|
||||||
|
@ -67,8 +62,7 @@ Then `4`. That's the match, so the execution starts from `case 4` and till the n
|
||||||
|
|
||||||
An example without `break`:
|
An example without `break`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = 2 + 2;
|
let a = 2 + 2;
|
||||||
|
|
||||||
switch (a) {
|
switch (a) {
|
||||||
|
@ -93,13 +87,12 @@ alert( 'Too big' );
|
||||||
alert( "I don't know such values" );
|
alert( "I don't know such values" );
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="Any expresion can be a `switch/case` argument"]
|
````smart header="Any expresion can be a `switch/case` argument"
|
||||||
Both `switch` and case allow arbitrary expresions.
|
Both `switch` and case allow arbitrary expresions.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = "1";
|
let a = "1";
|
||||||
let b = 0;
|
let b = 0;
|
||||||
|
|
||||||
|
@ -114,7 +107,7 @@ switch (+a) {
|
||||||
alert('no-no, see the code above, it executes');
|
alert('no-no, see the code above, it executes');
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
## Grouping of "case"
|
## Grouping of "case"
|
||||||
|
|
||||||
|
@ -122,9 +115,7 @@ Several variants of `case` can be grouped.
|
||||||
|
|
||||||
For example, if we want the same code for `case 3` and `case 5`:
|
For example, if we want the same code for `case 3` and `case 5`:
|
||||||
|
|
||||||
|
```js run no-beautify
|
||||||
```js
|
|
||||||
//+ run no-beautify
|
|
||||||
let a = 2 + 2;
|
let a = 2 + 2;
|
||||||
|
|
||||||
switch (a) {
|
switch (a) {
|
||||||
|
@ -153,9 +144,7 @@ Let's emphase that the equality check is always strict. The values must be of th
|
||||||
|
|
||||||
For example, let's consider the code:
|
For example, let's consider the code:
|
||||||
|
|
||||||
|
```js run
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
let arg = prompt("Enter a value?")
|
let arg = prompt("Enter a value?")
|
||||||
switch (arg) {
|
switch (arg) {
|
||||||
case '0':
|
case '0':
|
||||||
|
@ -174,10 +163,7 @@ switch (arg) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<ol>
|
1. For `0`, `1`, the first `alert` runs.
|
||||||
<li>For `0`, `1`, the first `alert` runs.</li>
|
2. For `2` the second `alert` runs.
|
||||||
<li>For `2` the second `alert` runs.</li>
|
3. But for `3`, the result of the `prompt` is a string `"3"`, which is not strictly equal `===` to the number `3`. So we've got a dead code in `case 3`! The `default` variant will execite.
|
||||||
<li>But for `3`, the result of the `prompt` is a string `"3"`, which is not strictly equal `===` to the number `3`. So we've got a dead code in `case 3`! The `default` variant will execite.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Is "else" required?
|
importance: 4
|
||||||
|
|
||||||
[importance 4]
|
---
|
||||||
|
|
||||||
|
# Is "else" required?
|
||||||
|
|
||||||
The following function returns `true` if the parameter `age` is greater than `18`.
|
The following function returns `true` if the parameter `age` is greater than `18`.
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
importance: 4
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Rewrite the function using '?' or '||'
|
# Rewrite the function using '?' or '||'
|
||||||
|
|
||||||
[importance 4]
|
|
||||||
|
|
||||||
|
|
||||||
The following function returns `true` if the parameter `age` is greater than `18`.
|
The following function returns `true` if the parameter `age` is greater than `18`.
|
||||||
|
|
||||||
Otherwise it asks for a confirmation and returns its result.
|
Otherwise it asks for a confirmation and returns its result.
|
||||||
|
@ -20,7 +21,7 @@ function checkAge(age) {
|
||||||
Rewrite it, to perform the same, but without `if`, in a single line.
|
Rewrite it, to perform the same, but without `if`, in a single line.
|
||||||
|
|
||||||
Make two variants of `checkAge`:
|
Make two variants of `checkAge`:
|
||||||
<ol>
|
|
||||||
<li>Using a question mark operator `'?'`</li>
|
1. Using a question mark operator `'?'`
|
||||||
<li>Using OR `||`</li>
|
2. Using OR `||`
|
||||||
</ol>
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Function min(a, b)
|
importance: 1
|
||||||
|
|
||||||
[importance 1]
|
---
|
||||||
|
|
||||||
|
# Function min(a, b)
|
||||||
|
|
||||||
Write a function `min(a,b)` which returns the least of two numbers `a` and `b`.
|
Write a function `min(a,b)` which returns the least of two numbers `a` and `b`.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
|
|
||||||
```js
|
```js run demo
|
||||||
//+ run demo
|
|
||||||
function pow(x, n) {
|
function pow(x, n) {
|
||||||
let result = x;
|
let result = x;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Function pow(x,n)
|
importance: 4
|
||||||
|
|
||||||
[importance 4]
|
---
|
||||||
|
|
||||||
|
# Function pow(x,n)
|
||||||
|
|
||||||
Write a function `pow(x,n)` that returns `x` in power `n`. Or, in other words, multiplies `x` by itself `n` times and returns the result.
|
Write a function `pow(x,n)` that returns `x` in power `n`. Or, in other words, multiplies `x` by itself `n` times and returns the result.
|
||||||
|
|
||||||
|
@ -12,6 +14,6 @@ pow(1, 100) = 1 * 1 * ...*1 = 1
|
||||||
|
|
||||||
Create a web-page that prompts for `x` and `n`, and then shows the result of `pow(x,n)`.
|
Create a web-page that prompts for `x` and `n`, and then shows the result of `pow(x,n)`.
|
||||||
|
|
||||||
[demo /]
|
[demo]
|
||||||
|
|
||||||
P.S. In this task the function is allowed to support only natural values of `n`: integers up from `1`.
|
P.S. In this task the function is allowed to support only natural values of `n`: integers up from `1`.
|
|
@ -24,14 +24,13 @@ function showMessage() {
|
||||||
|
|
||||||
The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* in the brackets (empty in the example above) and finally the code of the function, also named "the function body".
|
The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* in the brackets (empty in the example above) and finally the code of the function, also named "the function body".
|
||||||
|
|
||||||
<img src="function_basics.png">
|

|
||||||
|
|
||||||
Our new function can be called by it's name.
|
Our new function can be called by it's name.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
function showMessage() {
|
function showMessage() {
|
||||||
alert( 'Hello everyone!' );
|
alert( 'Hello everyone!' );
|
||||||
}
|
}
|
||||||
|
@ -54,8 +53,7 @@ A variable declared inside a function is only visible inside that function.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
function showMessage() {
|
function showMessage() {
|
||||||
*!*
|
*!*
|
||||||
let message = "Hello, I'm JavaScript!"; // local variable
|
let message = "Hello, I'm JavaScript!"; // local variable
|
||||||
|
@ -73,8 +71,7 @@ alert( message ); // <-- Error! The variable is local to the function
|
||||||
|
|
||||||
A function can access an outer variable as well, for example:
|
A function can access an outer variable as well, for example:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
let *!*userName*/!* = 'John';
|
let *!*userName*/!* = 'John';
|
||||||
|
|
||||||
function showMessage() {
|
function showMessage() {
|
||||||
|
@ -89,8 +86,7 @@ The function has a full access to an outer variable. It can modify it as well.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let *!*userName*/!* = 'John';
|
let *!*userName*/!* = 'John';
|
||||||
|
|
||||||
function showMessage() {
|
function showMessage() {
|
||||||
|
@ -115,8 +111,7 @@ For example, if we had `let` before `userName` in the line (1) then the function
|
||||||
|
|
||||||
In the code below the local `userName` shadows the outer one:
|
In the code below the local `userName` shadows the outer one:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let userName = 'John';
|
let userName = 'John';
|
||||||
|
|
||||||
function showMessage() {
|
function showMessage() {
|
||||||
|
@ -131,18 +126,16 @@ function showMessage() {
|
||||||
// the function will create and use it's own userName
|
// the function will create and use it's own userName
|
||||||
showMessage();
|
showMessage();
|
||||||
|
|
||||||
*!*
|
|
||||||
alert( userName ); // John, the function did not access the outer variable
|
alert( userName ); // John, the function did not access the outer variable
|
||||||
*/!*
|
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="Global variables"]
|
```smart header="Global variables"
|
||||||
Variables declared outside of any function, such as the outer `userName` in the code above, are called *global*.
|
Variables declared outside of any function, such as the outer `userName` in the code above, are called *global*.
|
||||||
|
|
||||||
Global variables are visible from any function.
|
Global variables are visible from any function.
|
||||||
|
|
||||||
They should only be used if the data is so important that it really must be seen from anywhere.
|
They should only be used if the data is so important that it really must be seen from anywhere.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
|
@ -150,39 +143,38 @@ We can pass arbitrary data to function using it's parameters (also called *funct
|
||||||
|
|
||||||
In the example below, the function has two parameters: `from` and `text`.
|
In the example below, the function has two parameters: `from` and `text`.
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
function showMessage(*!*from, text*/!*) { // arguments: from, text
|
function showMessage(*!*from, text*/!*) { // arguments: from, text
|
||||||
|
|
||||||
from = "[" + from + "]";
|
|
||||||
|
|
||||||
alert(from + ': ' + text);
|
alert(from + ': ' + text);
|
||||||
}
|
}
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
showMessage('Ann', 'Hello!'); // [Ann]: Hello!
|
showMessage('Ann', 'Hello!'); // Ann: Hello!
|
||||||
showMessage('Ann', "What's up?"); // [Ann]: What's up?
|
showMessage('Ann', "What's up?"); // Ann: What's up?
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
When the function is called, the values in the brackets are copied to local variables `from` and `next`. The function can modify them.
|
When the function is called, the values in the brackets are copied to local variables `from` and `next`.
|
||||||
|
|
||||||
Note that the changes are not seen from outside:
|
Please note that because the function can modify them. The changes are made to copies, so they won't affect anything outside:
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run
|
```js run
|
||||||
function showMessage(from, text) {
|
function showMessage(from, text) {
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
from = '[' + from + ']'; // changes the local from
|
from = '*' + from + '*'; // make "from" look nicer
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
alert( from + ': ' + text );
|
alert( from + ': ' + text );
|
||||||
}
|
}
|
||||||
|
|
||||||
let from = "Ann";
|
let from = "Ann";
|
||||||
|
|
||||||
showMessage(from, "Hello");
|
showMessage(from, "Hello"); // *Ann*: Hello
|
||||||
|
|
||||||
// the old value of "from" is still here, the function modified a local copy
|
// the value of "from" is the same, the function modified a local copy
|
||||||
alert( from ); // Ann
|
alert( from ); // Ann
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -198,10 +190,9 @@ showMessage("Ann");
|
||||||
|
|
||||||
That's not an error. Such call would output `"Ann: undefined"`, because `text === undefined`.
|
That's not an error. Such call would output `"Ann: undefined"`, because `text === undefined`.
|
||||||
|
|
||||||
But we can modify the function to detect missed parameter and assign a "default value" to it:
|
If we want to track when the function is called with a single argument and use a "default" value in this case, then we can check if `text` is defined, like here:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
function showMessage(from, text) {
|
function showMessage(from, text) {
|
||||||
*!*
|
*!*
|
||||||
if (text === undefined) {
|
if (text === undefined) {
|
||||||
|
@ -218,46 +209,37 @@ showMessage("Ann"); // Ann: no text given
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
Optional arguments are usually given at the end of the list.
|
There are also other ways to supply "default values" for missing arguments:
|
||||||
|
|
||||||
There are three most used ways to assign default values:
|
- Use operator `||`:
|
||||||
|
|
||||||
<ol>
|
```js
|
||||||
<li>We can check if the argument equals `undefined`, and if yes then assign a default value to it. That's demonstrated by the example above.</li>
|
function showMessage(from, text) {
|
||||||
<li>Use operator `||`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
function showMessage(from, text) {
|
|
||||||
text = text || 'no text given';
|
text = text || 'no text given';
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This way is shorter, but the argument is considered missing also if it's falsy, like an empty line, `0` or `null`.
|
This way is shorter, but the argument is considered missing also if it's falsy, like an empty line, `0` or `null`.
|
||||||
</li>
|
- ES-2015 introduced a neater syntax for default values:
|
||||||
<li>ES-2015 introduced a neater syntax for default values:
|
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
function showMessage(from, *!*text = 'no text given'*/!*) {
|
||||||
function showMessage(from, *!*text = 'no text given'*/!*) {
|
|
||||||
alert( from + ": " + text );
|
alert( from + ": " + text );
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage("Ann"); // Ann: no text for you
|
showMessage("Ann"); // Ann: no text given
|
||||||
```
|
```
|
||||||
|
|
||||||
Here `'no text given'` is a string, but it can be any other value or expression, which is only evaluated and assigned if the parameter is missing.
|
Here `'no text given'` is a string, but it can be any other value or expression, which is only evaluated and assigned if the parameter is missing.
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
## Returning a value
|
## Returning a value
|
||||||
|
|
||||||
A function can return a value into the calling code as the result.
|
A function can return a value back into the calling code as the result.
|
||||||
|
|
||||||
The simplest example would be a function that sums two values:
|
The simplest example would be a function that sums two values:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
function sum(a, b) {
|
function sum(a, b) {
|
||||||
*!*return*/!* a + b;
|
*!*return*/!* a + b;
|
||||||
}
|
}
|
||||||
|
@ -268,15 +250,18 @@ alert( result ); // 3
|
||||||
|
|
||||||
The directive `return` can be in any place of the function. When the execution reaches it, the function stops, and the value is returned to the calling code (assigned to `result` above).
|
The directive `return` can be in any place of the function. When the execution reaches it, the function stops, and the value is returned to the calling code (assigned to `result` above).
|
||||||
|
|
||||||
There may be many uses of `return` in a function. For instance:
|
There may be many occurences of `return` in a single function. For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
function checkAge(age) {
|
function checkAge(age) {
|
||||||
if (age > 18) {
|
if (age > 18) {
|
||||||
|
*!*
|
||||||
return true;
|
return true;
|
||||||
|
*/!*
|
||||||
} else {
|
} else {
|
||||||
|
*!*
|
||||||
return confirm('Got a permission from the parents?');
|
return confirm('Got a permission from the parents?');
|
||||||
|
*/!*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,85 +293,74 @@ function showMovie(age) {
|
||||||
|
|
||||||
In the code above, if `checkAge(age)` returns `false`, then `showMovie` won't proceed to the `alert`.
|
In the code above, if `checkAge(age)` returns `false`, then `showMovie` won't proceed to the `alert`.
|
||||||
|
|
||||||
|
````smart header="A function with an empty `return` or without it returns `undefined`"
|
||||||
[smart header="A function with an empty `return` or without it returns `undefined`"]
|
|
||||||
If a function does not return a value, it is the same as if it returns `undefined`:
|
If a function does not return a value, it is the same as if it returns `undefined`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
function doNothing() { /* empty */ }
|
function doNothing() { /* empty */ }
|
||||||
|
|
||||||
alert( doNothing() ); // undefined
|
alert( doNothing() === undefined ); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
An empty `return` is also the same as `return undefined`:
|
An empty `return` is also the same as `return undefined`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
function doNothing() {
|
function doNothing() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
alert( doNothing() === undefined ); // true
|
alert( doNothing() === undefined ); // true
|
||||||
```
|
```
|
||||||
|
````
|
||||||
[/smart]
|
|
||||||
|
|
||||||
## Naming a function [#function-naming]
|
## Naming a function [#function-naming]
|
||||||
|
|
||||||
Functions are actions. So their name is usually a verb.
|
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.
|
||||||
|
|
||||||
Usually, function names have verbal prefixes which vaguely describe the action.
|
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.
|
||||||
|
|
||||||
There is an agreement within the team on the terms here. For instance, functions that start with `"show"` -- usually show something:
|
For instance, functions that start with `"show"` -- usually show something.
|
||||||
|
|
||||||
```js
|
|
||||||
//+ no-beautify
|
|
||||||
showMessage(..) // shows a message
|
|
||||||
```
|
|
||||||
|
|
||||||
Function starting with...
|
Function starting with...
|
||||||
<ul>
|
|
||||||
<li>`"get"` -- allow to get something,</li>
|
- `"get"` -- allow to get something,
|
||||||
<li>`"calc"` -- calculate something,</li>
|
- `"calc"` -- calculate something,
|
||||||
<li>`"create"` -- create something,</li>
|
- `"create"` -- create something,
|
||||||
<li>`"check"` -- check something and return a boolean, etc.</li>
|
- `"check"` -- check something and return a boolean, etc.
|
||||||
</ul>
|
|
||||||
|
|
||||||
Examples of such names:
|
Examples of such names:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
showMessage(..) // shows a message
|
||||||
getAge(..) // return the age (get it somehow)
|
getAge(..) // returns the age (gets it somehow)
|
||||||
calcSum(..) // calculate a sum and return the result
|
calcSum(..) // calculates a sum and returns the result
|
||||||
createForm(..) // create a form, usually returns it
|
createForm(..) // creates a form (and usually returns it)
|
||||||
checkPermission(..) // check a permission, return true/false
|
checkPermission(..) // checks a permission, returns true/false
|
||||||
```
|
```
|
||||||
|
|
||||||
The agreement about prefixes is very convenient. A glance on a function name, even on the prefix of it, gives an understanding what it does and what kind of value it returns.
|
With prefixes at place, a glance at a function name gives an understanding what kind of work it does and what kind of value it returns.
|
||||||
|
|
||||||
[smart header="One function -- one action"]
|
```smart header="One function -- one action"
|
||||||
A function should do exactly what is suggested by its name.
|
A function should do exactly what is suggested by its name, no more.
|
||||||
|
|
||||||
Two independant actions usually deserve two functions, even if they are usually called together (in that case we can make a 3rd function calling those two).
|
Two independant actions usually deserve two functions, even if they are usually called together (in that case we can make a 3rd function calling those two).
|
||||||
|
|
||||||
Few examples of breaking this rule:
|
Few examples of breaking this rule:
|
||||||
<ul>
|
|
||||||
<li>`getAge` -- if shows the age to the visitor (should only get).</li>
|
|
||||||
<li>`createForm` -- if modifies the document, adds a form to it (should only create it and return).</li>
|
|
||||||
<li>`checkPermission` -- if displays the `access granted/denied` message or stores the result of the check (should only perform the check and return the result).</li>
|
|
||||||
</ul>
|
|
||||||
[/smart]
|
|
||||||
|
|
||||||
|
- `getAge` -- would be bad if it shows an `alert` with the age (should only get).
|
||||||
|
- `createForm` -- would be bad if it modifies the document, adding a form to it (should only create it and return).
|
||||||
|
- `checkPermission` -- would be bad if displays the `access granted/denied` message (should only perform the check and return the result).
|
||||||
|
|
||||||
[smart header="Ultrashort function names"]
|
These examples reflect few common meanings of prefixes, the final word comes from you and your team. Maybe it's pretty normal for your code to behave differently. But you should to have a firm understanding what a prefix means, what a prefixed function can and what it can not do. All same-prefixed functions should obey the rules. And the team should share the knowledge.
|
||||||
|
```
|
||||||
|
|
||||||
|
```smart header="Ultrashort function names"
|
||||||
Functions that are used *very often* sometimes have ultrashort names.
|
Functions that are used *very often* sometimes have ultrashort names.
|
||||||
|
|
||||||
For example, [jQuery](http://jquery.com) framework defines a function `$`, [LoDash](http://lodash.com/) library has it's core function named `_`.
|
For example, [jQuery](http://jquery.com) framework defines a function `$`, [LoDash](http://lodash.com/) library has it's core function named `_`.
|
||||||
|
|
||||||
These are exceptions. Generally functions names should be concise, but descriptive.
|
These are exceptions. Generally functions names should be concise, but descriptive.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
@ -398,11 +372,9 @@ function name(parameters, delimited, by, comma) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<ul>
|
- Values passed to function as parameters are copied to its local variables.
|
||||||
<li>Values passed to function as parameters are copied to its local variables.</li>
|
- A function may access outer variables. But it works only one-way. The code outside of the function doesn't see its local variables.
|
||||||
<li>A function may access outer variables. But it works only one-way. The code outside of the function doesn't see its local variables.</li>
|
- A function can return a value. If it doesn't then its result is `undefined`.
|
||||||
<li>A function can return a value. If it doesn't then its result is `undefined`.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
It is possible for a function to access variables defined outside of it.
|
It is possible for a function to access variables defined outside of it.
|
||||||
|
|
||||||
|
@ -412,14 +384,9 @@ It is always easier to understand a function which gets parameters, works with t
|
||||||
|
|
||||||
Function naming:
|
Function naming:
|
||||||
|
|
||||||
<ul>
|
- A name should clearly describe what the function does. When we see a function call in the code, a good name instantly gives us an understanding what it does and returns.
|
||||||
<li>A name should clearly describe what the function does. When we see a function call in the code, a good name instantly gives us an understanding what it does and returns.</li>
|
- A function is an action, so function names are usually verbal.
|
||||||
<li>A function is an action, so function names are usually verbal.</li>
|
- There is a bunch of commonly adapted verbal prefixes like `create…`, `show…`, `get…`, `check…` etc which can help. The main point is to be consistent about their meaning.
|
||||||
<li>There is a bunch of commonly adapted verbal prefixes like `create…`, `show…`, `get…`, `check…` etc which can help. The main point is to be consistent about their meaning.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Functions are the main building blocks of scripts. Now we covered the basics, so we actually can use them.
|
|
||||||
|
|
||||||
But we are going to return to them, going more deeply in their advanced features.
|
|
||||||
|
|
||||||
|
Functions are the main building blocks of scripts. Now we covered the basics, so we actually can start creating and using them. But that's only the beginning of the path. We are going to return to them many times, going more deeply in their advanced features.
|
||||||
|
|
||||||
|
|
|
@ -1,40 +1,6 @@
|
||||||
# Function expressions
|
# Function expressions
|
||||||
|
|
||||||
Function Expression is an analternative syntax for declaring a function.
|
In JavaScript, a function is a value.
|
||||||
|
|
||||||
It looks like this:
|
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
let func = function(parameters) {
|
|
||||||
// body
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
For instance:
|
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
let sayHi = function(person) {
|
|
||||||
alert( `Hello, ${person}` );
|
|
||||||
};
|
|
||||||
|
|
||||||
sayHi('John'); // Hello, John
|
|
||||||
```
|
|
||||||
|
|
||||||
The function `sayHi` created in the example above is identical to:
|
|
||||||
|
|
||||||
```js
|
|
||||||
function sayHi(person) {
|
|
||||||
alert( `Hello, ${person}` );
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Function is a value
|
|
||||||
|
|
||||||
Function Expression clearly demonstrates one simple thing.
|
|
||||||
|
|
||||||
**In JavaScript, a function is a value.**
|
|
||||||
|
|
||||||
We can declare it as we did before:
|
We can declare it as we did before:
|
||||||
|
|
||||||
|
@ -44,7 +10,9 @@ function sayHi() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
...Or as a function expression:
|
This syntax is called a "Function Declaration".
|
||||||
|
|
||||||
|
...But there is another way of creating a function:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let sayHi = function() {
|
let sayHi = function() {
|
||||||
|
@ -52,14 +20,17 @@ let sayHi = function() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The meaning of these lines is the same: create a function, put it into the variable `sayHi`.
|
The latter syntax is called a "Function Expression".
|
||||||
|
|
||||||
Yes, no matter, how it is defined -- it's just a value, stored in the variable `sayHi`.
|
The meaning of these code samples is the same: "create a function and put it into the variable `sayHi`".
|
||||||
|
|
||||||
We can even show it using `alert`:
|
Yes, no matter, how the function is defined -- it's just a value, stored in the variable `sayHi`.
|
||||||
|
|
||||||
```js
|
Let's stress: a function is not a "magical language structure". Both syntaxes mean the same: create a special "function" value and put it into the variable.
|
||||||
//+ run
|
|
||||||
|
We can even print out that value using `alert`:
|
||||||
|
|
||||||
|
```js run
|
||||||
function sayHi() {
|
function sayHi() {
|
||||||
alert( "Hello" );
|
alert( "Hello" );
|
||||||
}
|
}
|
||||||
|
@ -69,12 +40,18 @@ alert( sayHi ); // shows the function code
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that there are no brackets after `sayHi` in the last line. The function is not called there. Instead the `alert` shows it's string representation, that is the source code.
|
Note that there are no brackets after `sayHi` in the last line.
|
||||||
|
|
||||||
As the function is a value, we can also copy it to another variable:
|
The function is not called there. There are programming languages where any use of function name causes it's call, but JavaScript is not like that. In JavaScript, a function is a value and we can deal with that as a value, like print string representation, that is the source code.
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run no-beautify
|
It is a special value though, in the sense that we can call it using brackets: `"sayHi()"`, but only if we explicitly put brackets into the code.
|
||||||
|
|
||||||
|
Other actions with functions are also available, in the same fashion as with other values.
|
||||||
|
|
||||||
|
We can copy a function to another variable:
|
||||||
|
|
||||||
|
```js run no-beautify
|
||||||
function sayHi() { // (1) create
|
function sayHi() { // (1) create
|
||||||
alert( "Hello" );
|
alert( "Hello" );
|
||||||
}
|
}
|
||||||
|
@ -83,130 +60,127 @@ let func = sayHi; // (2) copy
|
||||||
|
|
||||||
func(); // Hello // (3) call the copy (it works)!
|
func(); // Hello // (3) call the copy (it works)!
|
||||||
|
|
||||||
sayHi = null; // (4) nullify the old variable
|
sayHi = null; // (4) store null in the old variable
|
||||||
sayHi(); // error! (null now)
|
sayHi(); // error! (now null, the function is overwritten)
|
||||||
|
|
||||||
|
func(); // the copy still works
|
||||||
```
|
```
|
||||||
|
|
||||||
<ol>
|
In more detail:
|
||||||
<li>Function declaration `(1)` creates the function and puts it into the variable `sayHi`"</li>
|
1. Function Declaration `(1)` creates the function and puts it into the variable `sayHi`"
|
||||||
<li>Line `(2)` copies it into variable `func`.
|
2. Line `(2)` copies it into variable `func`.
|
||||||
|
|
||||||
Please note again: there are no brackets after `sayHi`. If they were, then `func = sayHi()` would write *the result* of the call `sayHi()` into `func`, not the function `sayHi` itself.</li>
|
Please note again: there are no brackets after `sayHi`. If they were, then `func = sayHi()` would write *the result* of the call `sayHi()` into `func`, not the function `sayHi` itself.
|
||||||
<li>At the moment `(3)` the function can be called both as `sayHi()` and `func()`.</li>
|
3. At the moment `(3)` the function can be called both as `sayHi()` and `func()`.
|
||||||
<li>...We can overwrite `sayHi` easily. As `func`, it is a normal variable. Naturally, the call attempt would fail in the case `(4)`.</li>
|
4. ...We can overwrite `sayHi`, it have had the function, but now it stores `null`. Naturally, the call attempt would fail.
|
||||||
</ol>
|
5. But `func` still has the function, it is still callable.
|
||||||
|
|
||||||
Again, it does not matter how to create a function here. If we change the first line above into a Function Expression: `let sayHi = function() {`, everything would be the same.
|
Note, that we could use a Function Expression in the first line: `let sayHi = function() { ... }`. Everything would work the same.
|
||||||
|
|
||||||
[smart header="A function is a value representing an \"action\""]
|
```smart header="A function is a value representing an \"action\""
|
||||||
Regular values like strings or numbers represent the *data*.
|
Regular values like strings or numbers represent the *data*.
|
||||||
|
|
||||||
A function can be perceived as an *action*.
|
A function can be perceived as an *action*.
|
||||||
|
|
||||||
We can copy it between variables and run when we want.
|
We can copy it between variables and run when we want.
|
||||||
[/smart]
|
|
||||||
|
|
||||||
|
|
||||||
Function Expressions are very convenient for creating an action in-place and passing it along the code.
|
|
||||||
|
|
||||||
For instance, let's consider the following real-life task.
|
|
||||||
|
|
||||||
Function `ask(question, yes, no)` should accept a textual `question` and two other functions: `yes` and `no`. It asks a question and, if the user responds positively, executes `yes()`, otherwise `no()`.
|
|
||||||
|
|
||||||
It could look like this:
|
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
function ask(question, yes, no) {
|
|
||||||
if (confirm(question)) yes()
|
|
||||||
else no();
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
In real-life `ask` would be usually much more complex, because it would draw a nice window and take care about how to present the `question` to the user etc. But here we consider the general form of such function, so `confirm` is enough.
|
## Why Function Expression?
|
||||||
|
|
||||||
So, how do we use it?
|
Now let's go back: we have two ways of declaring a function. Why so? What's about Function Expressions that makes it a good addition?
|
||||||
|
|
||||||
If we had only Function Declarations in our toolbox, we could declare `showOk/showCancel` and pass them:
|
**Function Expressions are very convenient for creating an action in-place and passing it along the code.**
|
||||||
|
|
||||||
|
There is a built-in [setTimeout](https://developer.mozilla.org/en/docs/Web/API/WindowTimers/setTimeout) function in JavaScript, that can schedule a function to run after a given period of time.
|
||||||
|
|
||||||
```js
|
The syntax is: `setTimeout(func, ms, ...arguments)`:
|
||||||
function showOk() {
|
|
||||||
alert( "Ok, proceeding." );
|
`func`
|
||||||
|
: The function to run.
|
||||||
|
|
||||||
|
`ms`
|
||||||
|
: The number of milliseconds (1/1000 of a second) to schedule the call after.
|
||||||
|
|
||||||
|
`arguments`
|
||||||
|
: One of more arguments to pass to the function.
|
||||||
|
|
||||||
|
What if we wanted to say "Hello" in a second?
|
||||||
|
|
||||||
|
One could write a code like this:
|
||||||
|
|
||||||
|
```js run
|
||||||
|
function sayHi() {
|
||||||
|
alert("Hello!")
|
||||||
}
|
}
|
||||||
|
|
||||||
function showCancel() {
|
setTimeout(sayHi, 1000);
|
||||||
alert( "Execution canceled." );
|
|
||||||
}
|
|
||||||
|
|
||||||
// usage
|
|
||||||
ask("Should we proceed?", showOk, showCancel);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
...But Function Expressions allow us to solve the task much more elegantly:
|
That would work. But we have declared a function that has no future use.
|
||||||
|
|
||||||
```js
|
A Function Expression is much cleaner:
|
||||||
ask("Should we proceed?",
|
|
||||||
function() { alert( "Ok, proceeding." ); },
|
```js run
|
||||||
function() { alert( "Execution canceled." ); },
|
setTimeout(function() {
|
||||||
);
|
alert("Hello!")
|
||||||
|
}, 1000);
|
||||||
```
|
```
|
||||||
|
|
||||||
Here we can declare actions in-place, exactly when we need it.
|
Such functions are sometimes called "anonymous" meaning that they are defined without a name. So to say, we can't reuse them, because there is no variable for them. But here it's exactly what we want.
|
||||||
|
|
||||||
Such functions are sometimes called "anonymous" meaning that they are defined without a name. So to say, we can't reuse them outside of `ask`, because there is no variable for them. But for this kind of task it's exactly what we want.
|
|
||||||
|
|
||||||
Creating functions in-place is very natural and in the spirit of JavaScript.
|
Creating functions in-place is very natural and in the spirit of JavaScript.
|
||||||
|
|
||||||
|
|
||||||
## Function Expression vs Function Declaration
|
## Function Expression vs Function Declaration
|
||||||
|
|
||||||
The "classic" syntax of the function that looks like `function name(params) {...}` is called a "Function Declaration".
|
Let's briefly reformulate the distinction between these two.
|
||||||
|
|
||||||
We can formulate the following distinction:
|
- *Function Declaration:* a function, declared as a separate statement, in the main code flow.
|
||||||
<ul>
|
|
||||||
<li>*Function Declaration* -- is a function, declared as a separate statement.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Function Declaration
|
// Function Declaration
|
||||||
function sum(a, b) {
|
function sum(a, b) {
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
- *Function Expression:* a function, created in the context of an expression.
|
||||||
|
|
||||||
</li>
|
Here the function is created in the context of an "assignment expression", it's an expression:
|
||||||
<li>*Function Expression* -- is a function, created in the context of an expression.
|
```js
|
||||||
|
// Function Expression
|
||||||
In the example above the function was created in the context of an "assignment expression":
|
let sum = function(a, b) {
|
||||||
```js
|
|
||||||
// Function Expression
|
|
||||||
let sum = function(a, b) {
|
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
</li>
|
Here the function is created inside another function call:
|
||||||
</ul>
|
|
||||||
|
|
||||||
The main differences between them are visibility and creation time.
|
```js
|
||||||
|
// Function Expression
|
||||||
|
setTimeout(function() {
|
||||||
|
alert("Hello!")
|
||||||
|
}, 1000);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creation time
|
||||||
|
|
||||||
|
There are more differences between them besides the syntax.
|
||||||
|
|
||||||
**Function Expressions are created when the execution reaches them.**
|
**Function Expressions are created when the execution reaches them.**
|
||||||
|
|
||||||
That's easy. Once the execution flow passes to the right side of the assignment -- here we go, the function is made and can be used (assigned, called etc) from now on.
|
That's rather obvious. Once the execution flow passes to the right side of the assignment -- here we go, the function is made and can be used (assigned, called etc) from now on.
|
||||||
|
|
||||||
Function Declarations are different. They are treated in a special way.
|
Function Declarations are different.
|
||||||
|
|
||||||
When JavaScript prepares to run the code block, it looks for Function Declarations in it and creates the functions. We can think of it as an "initialization stage". Then it runs the code.
|
**Function Declarations are created before the script or a code block begins to execute and are visible in the whole scropt/block.**
|
||||||
|
|
||||||
**Function Declarations are created before the code block begins to execute and is visible in the whole block.**
|
In other words, when JavaScript *prepares* to run the script or a code block, it first looks for Function Declarations in it and creates the functions. We can think of it as an "initialization stage". Then it runs the code.
|
||||||
|
|
||||||
If the Function Declaration is not inside a code block `{...}`, then it is created when the script starts and is visible in the whole script. All declarations in the examples above are not in the code block.
|
|
||||||
|
|
||||||
As a natural effect, a function declared as Function Declaration can be called earlier than it is defined.
|
As a natural effect, a function declared as Function Declaration can be called earlier than it is defined.
|
||||||
|
|
||||||
For instance, this works:
|
For instance, this works:
|
||||||
|
|
||||||
```js
|
```js run refresh untrusted
|
||||||
//+ run refresh untrusted
|
|
||||||
*!*
|
*!*
|
||||||
sayHi("John"); // Hello, John
|
sayHi("John"); // Hello, John
|
||||||
*/!*
|
*/!*
|
||||||
|
@ -220,8 +194,7 @@ Function Declaration `sayHi` is created when the script starts and is visible ev
|
||||||
|
|
||||||
...And if there were Function Expression, then it wouldn't work:
|
...And if there were Function Expression, then it wouldn't work:
|
||||||
|
|
||||||
```js
|
```js run refresh untrusted
|
||||||
//+ run refresh untrusted
|
|
||||||
*!*
|
*!*
|
||||||
sayHi("John"); // error!
|
sayHi("John"); // error!
|
||||||
*/!*
|
*/!*
|
||||||
|
@ -231,17 +204,18 @@ let sayHi = function(name) { // (*)
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Function Expressions are created in the process of evaluation of the expression with them. So, in the code above, the function would be created and assigned to `sayHi` only when the execution reaches the line `(*)`. Too late.
|
Function Expressions are created when the execution reaches them. No magic. That would happen only in the line `(*)`. Too late.
|
||||||
|
|
||||||
Now let's explore the visibility thing.
|
|
||||||
|
### Visibility
|
||||||
|
|
||||||
|
Now let's explore the visibility differences.
|
||||||
|
|
||||||
Imagine, we need to declare `welcome()` depending on some data we get in run-time.
|
Imagine, we need to declare `welcome()` depending on some data we get in run-time.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
|
|
||||||
let age = prompt("What is your age?", 18);
|
let age = prompt("What is your age?", 18);
|
||||||
|
|
||||||
if (age < 18) {
|
if (age < 18) {
|
||||||
|
@ -263,33 +237,34 @@ welcome(); // Error: welcome is not defined
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
In the code above, we mean to create function `welcome()` depending on the `age`. So, that it can't be called later, probably from another place of the code, in case of an event or such.
|
In the code above, we'd like to create function `welcome()` depending on the `age`. So, that it can't be called later, probably from another place of the code, in case of an event or such, doesn't matter now.
|
||||||
|
|
||||||
But that doesn't work, because Function Declaration `function welcome()` is visible only inside the block where it resides.
|
But that doesn't work.
|
||||||
|
|
||||||
|
**A Function Declaration is visible only inside the code block where it resides.**
|
||||||
|
|
||||||
We can call it from within the block, but not from outside:
|
We can call it from within the block, but not from outside:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let age = 16; // take 16 as an example
|
||||||
let age = 15; // let's consider 15 as an example
|
|
||||||
|
|
||||||
if (age < 18) {
|
if (age < 18) {
|
||||||
*!*
|
*!*
|
||||||
welcome(); // \ (works)
|
welcome(); // \ (runs)
|
||||||
*/!*
|
*/!*
|
||||||
// |
|
// |
|
||||||
function welcome() { // |
|
function welcome() { // |
|
||||||
alert("Hello!"); // | available here
|
alert("Hello!"); // | welcome is available everywhere in its block
|
||||||
} // |
|
} // |
|
||||||
// |
|
// |
|
||||||
*!*
|
*!*
|
||||||
welcome(); // / (works)
|
welcome(); // / (runs)
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// \
|
// \
|
||||||
function welcome() { // |
|
function welcome() { // |
|
||||||
alert("Greetings!"); // | available here
|
alert("Greetings!"); // | another welcome is limited to its own block
|
||||||
} // |
|
} // |
|
||||||
// /
|
// /
|
||||||
}
|
}
|
||||||
|
@ -299,13 +274,9 @@ welcome(); // Error: outside of the block there's no welcome
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
What can we do to fix the problem? One of the ways is to use a Function Expression and assign `welcome` to the variable which has the proper visibility:
|
What can we do to fix the problem? One of the ways is to use a Function Expression and assign `welcome` to the variable which is declared outside of `if` and has the proper visibility:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
|
|
||||||
|
```js run
|
||||||
let age = prompt("What is your age?", 18);
|
let age = prompt("What is your age?", 18);
|
||||||
|
|
||||||
let welcome;
|
let welcome;
|
||||||
|
@ -331,9 +302,7 @@ welcome(); // ok now
|
||||||
|
|
||||||
Or we could go on to simplify it even further using a question mark operator `?`:
|
Or we could go on to simplify it even further using a question mark operator `?`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
|
|
||||||
let age = prompt("What is your age?", 18);
|
let age = prompt("What is your age?", 18);
|
||||||
|
|
||||||
let welcome = (age < 18) ?
|
let welcome = (age < 18) ?
|
||||||
|
@ -349,26 +318,19 @@ welcome(); // ok now
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="So, a Declaration or an Expression?"]
|
```smart header="What to choose: a Declaration or an Expression?"
|
||||||
As a rule of thumb, if we want just to declare a function, then a Function Declaration is prefered. It gives more freedom in how to organize our code, because we can put "helper functions" below. It's also a little bit easier to read and look up them in the text.
|
As a rule of thumb, a Function Declaration is prefered. It gives more freedom in how to organize our code, because we can call it both above and below. It's also a little bit easier to look up Function Declarations in the text.
|
||||||
|
|
||||||
Only if a Function Declaration does not suit us for some reason, then a Function Expression should be used.
|
|
||||||
[/smart]
|
|
||||||
|
|
||||||
|
But if a Function Declaration does not suit us for some reason, or we need to create an anonymous function "at-place", then a Function Expression should be used.
|
||||||
|
```
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
- Functions are values. They can be assigned, copied or declared in any place of the code.
|
||||||
<li>
|
- If the function is declared as a separate statement -- it's called a Function Declaration.
|
||||||
Functions are values. They can be assigned, copied or declared in any place of the code.
|
- If the function is created as a part of an expression -- it's a Function Expression.
|
||||||
<ul>
|
- Function Declarations are processed before the code block is executed. So they are available everywhere in the block. Or in the whole script if not enclosed in a block.
|
||||||
<li>If the function is declared as a separate statement -- it's called a Function Declaration.</li>
|
- Function Expressions are created when the execution flow reaches them.
|
||||||
<li>If the function is created as a part of an expression -- it's a Function Expression.</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>Function Declarations are processed before the code block is executed. So they are available everywhere in the block. Or in the whole script if not enclosed in a block.</li>
|
|
||||||
<li>Function Expressions are created when the execution flow reaches them.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Novice programmers sometimes overuse Function Expression by creating many functions with `let func = function()`.
|
Novice programmers sometimes overuse Function Expression by creating many functions with `let func = function()`.
|
||||||
|
|
||||||
|
@ -376,8 +338,7 @@ But in most cases Function Declaration is preferable.
|
||||||
|
|
||||||
Compare, which code is more readable:
|
Compare, which code is more readable:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
// Function Expression
|
// Function Expression
|
||||||
let f = function() { ... }
|
let f = function() { ... }
|
||||||
|
|
||||||
|
@ -385,6 +346,6 @@ let f = function() { ... }
|
||||||
function f() { ... }
|
function f() { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
Function Declaration is shorter and more obvious. The additional bonus -- it can be called before the declaration.
|
Function Declaration is shorter and more obvious. The additional bonus -- it can be called before the actual declaration.
|
||||||
|
|
||||||
Use Function Expression only when the function must be created at-place, inside another expression.
|
Use Function Expression to write elegant code when the function must be created at-place, inside another expression or when Function Declaration doesn't fit well for the task.
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
The HTML code:
|
The HTML code:
|
||||||
|
|
||||||
```html
|
[html src="index.html"]
|
||||||
<!--+ src="index.html" -->
|
|
||||||
```
|
|
||||||
|
|
||||||
For the file `alert.js` in the same folder:
|
For the file `alert.js` in the same folder:
|
||||||
|
|
||||||
```js
|
[js src="alert.js"]
|
||||||
//+ src="alert.js"
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
importance: 5
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Show an alert with an external script
|
# Show an alert with an external script
|
||||||
|
|
||||||
[importance 5]
|
Take the solution of the previous task <info:task/hello-alert>. Modify it by extracting the script content into an external file `alert.js`, residing in the same folder.
|
||||||
|
|
||||||
Take the solution of the previous task [](/task/hello-alert). Modify it by extracting the script content into an external file `alert.js`, residing in the same folder.
|
|
||||||
|
|
||||||
Open the page, ensures that the alert works.
|
Open the page, ensures that the alert works.
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
Answers:
|
Answers:
|
||||||
<ol>
|
|
||||||
<li>The first is `big.js`, that's a normal sequence for external `<script>` tags.</li>
|
1. The first is `big.js`, that's a normal sequence for external `<script>` tags.
|
||||||
<li>The first is `small.js`, because `async` makes script behave independently of each other and the page. The first to loads runs first.</li>
|
2. The first is `small.js`, because `async` makes script behave independently of each other and the page. The first to loads runs first.
|
||||||
<li>The first is `big.js`, because "deferred" scripts keep relative execution order.</li>
|
3. The first is `big.js`, because "deferred" scripts keep relative execution order.
|
||||||
</ol>
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Which script executes first?
|
importance: 4
|
||||||
|
|
||||||
[importance 4]
|
---
|
||||||
|
|
||||||
|
# Which script executes first?
|
||||||
|
|
||||||
In the questions below, there are two scripts: `small.js` and `big.js`.
|
In the questions below, there are two scripts: `small.js` and `big.js`.
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ We can give a full URL al well, for instance:
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
To attach several scripts, use multiple tags:
|
To attach several scripts, use multiple tags:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
@ -27,7 +26,7 @@ To attach several scripts, use multiple tags:
|
||||||
…
|
…
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart]
|
```smart
|
||||||
As a rule, only simplest scripts are put into HTML. More complex ones reside in separate files.
|
As a rule, only 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 in its [cache](https://en.wikipedia.org/wiki/Web_cache).
|
||||||
|
@ -35,10 +34,9 @@ The benefit of a separate file is that the browser will download it and then sto
|
||||||
After it, other pages which want the same script will take it from the cache instead of downloading it. So the file is actually downloaded only once.
|
After it, other pages which want the same script will take it from the cache instead of downloading it. So the file is actually downloaded only once.
|
||||||
|
|
||||||
That saves traffic and makes pages faster.
|
That saves traffic and makes pages faster.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
|
````warn header="If `src` is set, the script content is ignored."
|
||||||
[warn header="If `src` is set, the script content is ignored."]
|
|
||||||
A single `<script>` tag may not have both an `src` and the code inside.
|
A single `<script>` tag may not have both an `src` and the code inside.
|
||||||
|
|
||||||
This won't work:
|
This won't work:
|
||||||
|
@ -59,7 +57,7 @@ The example above can be split into two scripts to work:
|
||||||
alert(1);
|
alert(1);
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
[/warn]
|
````
|
||||||
|
|
||||||
## Asynchronous scripts: defer/async
|
## Asynchronous scripts: defer/async
|
||||||
|
|
||||||
|
@ -69,8 +67,7 @@ As we noted before, when the browser meets a `<script>` tag, it must execute it
|
||||||
|
|
||||||
For example, in the code below -- until all rabbits are counted, the bottom `<p>` is not shown:
|
For example, in the code below -- until all rabbits are counted, the bottom `<p>` is not shown:
|
||||||
|
|
||||||
```html
|
```html run height=100
|
||||||
<!--+ run height=100 -->
|
|
||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
|
@ -118,7 +115,7 @@ Sometimes, a script may contain a very important code that really must be loaded
|
||||||
|
|
||||||
Usually it's ok that a visitor can see the page content while the script is loading.
|
Usually it's ok that a visitor can see the page content while the script is loading.
|
||||||
|
|
||||||
[warn header="Blocking is dangerous"]
|
````warn header="Blocking is dangerous"
|
||||||
There are situations when such blocking is even dangerous.
|
There are situations when such blocking is even dangerous.
|
||||||
|
|
||||||
Let's say we attach a script from the banner system, or a 3rd-party integration code.
|
Let's say we attach a script from the banner system, or a 3rd-party integration code.
|
||||||
|
@ -139,15 +136,14 @@ And what if their server is overloaded and responds slowly? Our visitors will wa
|
||||||
|
|
||||||
Here's an example of such "slow" script (the delay is artificial here):
|
Here's an example of such "slow" script (the delay is artificial here):
|
||||||
|
|
||||||
```html
|
```html run height=100
|
||||||
<!--+ run height=100 -->
|
|
||||||
Wait. The text belown will shown up only after the script executes.
|
Wait. The text belown will shown up only after the script executes.
|
||||||
|
|
||||||
<script src="/article/external-script/banner.js?speed=0"></script>
|
<script src="/article/external-script/banner.js?speed=0"></script>
|
||||||
|
|
||||||
<p>…Important information!</p>
|
<p>…Important information!</p>
|
||||||
```
|
```
|
||||||
[/warn]
|
````
|
||||||
|
|
||||||
So, how to "fix" the blocking behavior?
|
So, how to "fix" the blocking behavior?
|
||||||
|
|
||||||
|
@ -155,41 +151,35 @@ Our first attempt could be to put all such scripts to the bottom of the `<body>`
|
||||||
|
|
||||||
But the solution is not perfect:
|
But the solution is not perfect:
|
||||||
|
|
||||||
<ol>
|
1. The script won't start loading until the whole page loads. If the page is large, then the delay may be significant. We'd like the browser to start loading a script early, but still do not block the page.
|
||||||
<li>The script won't start loading until the whole page loads. If the page is large, then the delay may be significant. We'd like the browser to start loading a script early, but still do not block the page.</li>
|
2. If there is more than one script at the bottom of the page, and the first script is slow, then the second one will have to wait for it. Browser executes only one `<script>` tag in one moment. So scripts queue one after another. That's not always welcome: ads and counter should run independently.
|
||||||
<li>If there is more than one script at the bottom of the page, and the first script is slow, then the second one will have to wait for it. Browser executes only one `<script>` tag in one moment. So scripts queue one after another. That's not always welcome: ads and counter should run independently.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
And here come the attributes `async` and `defer`.
|
And here come the attributes `async` and `defer`.
|
||||||
|
|
||||||
<dl>
|
The `async` attribute.
|
||||||
<dt>The `async` attribute.</dt>
|
: The script is executed asynchronously. In other words, when the browser meets `<script async src="...">`, it does not stop showing the page. It just initiates script loading and goes on. When the script loads -- it runs.
|
||||||
<dd>The script is executed asynchronously. In other words, when the browser meets `<script async src="...">`, it does not stop showing the page. It just initiates script loading and goes on. When the script loads -- it runs.</dd>
|
|
||||||
<dt>The `defer` attribute.</dt>
|
The `defer` attribute.
|
||||||
<dd>The script with `defer` also executes asynchronously, like async. But there are two essential differences:
|
<dd>The script with `defer` also executes asynchronously, like async. But there are two essential differences:
|
||||||
|
|
||||||
<ol>
|
1. The browser guarantees to keep the relative order of "deferred" scripts.
|
||||||
<li>The browser guarantees to keep the relative order of "deferred" scripts.</li>
|
2. A "deferred" script always executes after HTML-document is fully loaded.
|
||||||
<li>A "deferred" script always executes after HTML-document is fully loaded.</li>
|
|
||||||
</ol>
|
|
||||||
We'll discuss them more in-depth further in this chapter.
|
We'll discuss them more in-depth further in this chapter.
|
||||||
</dl>
|
|
||||||
|
|
||||||
[smart header="`async` together with `defer`"]
|
```smart header="`async` together with `defer`"
|
||||||
We can't use both `defer` and `async` on a single script. If we do that, `defer` will be ignored.
|
We can't use both `defer` and `async` on a single script. If we do that, `defer` will be ignored.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
[warn header="Attributes `async/defer` -- only for external scripts"]
|
```warn header="Attributes `async/defer` -- only for external scripts"
|
||||||
Attribute `async/defer` work only when set on a script with `src`.
|
Attribute `async/defer` work only when set on a script with `src`.
|
||||||
|
|
||||||
On a script without `src` like <code><script>...</script></code>, they will be ignored.
|
On a script without `src` like <code><script>...</script></code>, they will be ignored.
|
||||||
[/warn]
|
```
|
||||||
|
|
||||||
Let's modify the "blocking script" example that we've seen before, adding `async`:
|
Let's modify the "blocking script" example that we've seen before, adding `async`:
|
||||||
|
|
||||||
|
```html run height=100
|
||||||
```html
|
|
||||||
<!--+ run height=100 -->
|
|
||||||
Wait. The text belown will shown up only after the script executes.
|
Wait. The text belown will shown up only after the script executes.
|
||||||
|
|
||||||
<script *!*async*/!* src="/article/external-script/banner.js?speed=0"></script>
|
<script *!*async*/!* src="/article/external-script/banner.js?speed=0"></script>
|
||||||
|
@ -199,7 +189,6 @@ Wait. The text belown will shown up only after the script executes.
|
||||||
|
|
||||||
Now if we run it, we'll see that the whole document is displayed immediately, and the external script runs when it loads.
|
Now if we run it, we'll see that the whole document is displayed immediately, and the external script runs when it loads.
|
||||||
|
|
||||||
|
|
||||||
## Defer vs Async: order
|
## Defer vs Async: order
|
||||||
|
|
||||||
Let's discuss these differences in more detail.
|
Let's discuss these differences in more detail.
|
||||||
|
@ -246,17 +235,14 @@ And in another case a script may need the whole document to do some work with it
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
- Scripts in an external file can be inserted on the page via `<script src="path"></script>`.
|
||||||
<li>Scripts in an external file can be inserted on the page via `<script src="path"></script>`.</li>
|
- Normally, the browser doesn't show the document after the script until it executes. Unless the script has `async` or `defer` attributes.
|
||||||
<li>Normally, the browser doesn't show the document after the script until it executes. Unless the script has `async` or `defer` attributes.</li>
|
- Both `async` and `defer` allow the browser to start script loading and then continue to parse/show the page. They only work on external scripts.
|
||||||
<li>Both `async` and `defer` allow the browser to start script loading and then continue to parse/show the page. They only work on external scripts.</li>
|
- The difference is that `defer` keeps the relative script order and always executes after the document is fully loaded. In contrast, `async` script executes when it loads, without any conditions.
|
||||||
<li>The difference is that `defer` keeps the relative script order and always executes after the document is fully loaded. In contrast, `async` script executes when it loads, without any conditions.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Before inserting an external `<script src="…">` tag, we should always consider the side-effect of blocking the page rendering. Especially if it's a 3rd-party script. And if we don't want that, then `defer/async` can come in handy.
|
Before inserting an external `<script src="…">` tag, we should always consider the side-effect of blocking the page rendering. Especially if it's a 3rd-party script. And if we don't want that, then `defer/async` can come in handy.
|
||||||
|
|
||||||
|
````smart header="Running ahead..."
|
||||||
[smart header="Running ahead..."]
|
|
||||||
For an advanced reader who knows that new tags can be added on page dynamically, we'd like to note that dynamic `<script>` tags behave as if they have `async` by default.
|
For an advanced reader who knows that new tags can be added on page dynamically, we'd like to note that dynamic `<script>` tags behave as if they have `async` by default.
|
||||||
|
|
||||||
In other words, they run as they load without an order.
|
In other words, they run as they load without an order.
|
||||||
|
@ -280,7 +266,5 @@ addScript('3.js'); // that is: 1 -> 2 -> 3
|
||||||
```
|
```
|
||||||
|
|
||||||
We'll cover page dynamic tags and page manipulation in detail later, in the second part of the tutorial.
|
We'll cover page dynamic tags and page manipulation in detail later, in the second part of the tutorial.
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
|
|
||||||
Вы могли заметить следующие недостатки, сверху-вниз:
|
Вы могли заметить следующие недостатки, сверху-вниз:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
function pow(x,n) // <- отсутствует пробел между аргументами
|
function pow(x,n) // <- отсутствует пробел между аргументами
|
||||||
{ // <- фигурная скобка на отдельной строке
|
{ // <- фигурная скобка на отдельной строке
|
||||||
var result=1; // <- нет пробелов вокруг знака =
|
var result=1; // <- нет пробелов вокруг знака =
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# Ошибки в стиле
|
importance: 4
|
||||||
|
|
||||||
[importance 4]
|
---
|
||||||
|
|
||||||
|
# Ошибки в стиле
|
||||||
|
|
||||||
Какие недостатки вы видите в стиле этого примера?
|
Какие недостатки вы видите в стиле этого примера?
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
function pow(x,n)
|
function pow(x,n)
|
||||||
{
|
{
|
||||||
var result=1;
|
var result=1;
|
||||||
|
|
|
@ -7,11 +7,12 @@ That is actually an art of programming -- to take a complex task and describe it
|
||||||
One thing to help is a good code style. In this chapter we cover it's components.
|
One thing to help is a good code style. In this chapter we cover it's components.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
A cheatsheep with the rules (more details below):
|
A cheatsheet with the rules (more details below):
|
||||||
|
|
||||||
<img src="code-style.png">
|

|
||||||
<!--
|
<!--
|
||||||
```js
|
```js
|
||||||
function pow(x, n) {
|
function pow(x, n) {
|
||||||
|
@ -34,6 +35,7 @@ if (n < 0) {
|
||||||
alert( pow(x, n) );
|
alert( pow(x, n) );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
Nothing is "carved in stone" here, so let's discuss the rules in detail.
|
Nothing is "carved in stone" here, so let's discuss the rules in detail.
|
||||||
|
@ -42,61 +44,67 @@ Nothing is "carved in stone" here, so let's discuss the rules in detail.
|
||||||
|
|
||||||
In most JavaScript projects figure brackets are written on the same line. A so-called "egyptian" style. There's also a space before an opening bracket.
|
In most JavaScript projects figure brackets are written on the same line. A so-called "egyptian" style. There's also a space before an opening bracket.
|
||||||
|
|
||||||
If the code has only one line, then there are options:
|
A corner-case if a single-line `if/for`. 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:
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
if (n < 0) {alert(`Power ${n} is not supported`);}
|
if (n < 0) {alert(`Power ${n} is not supported`);}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (n < 0) alert(`Power ${n} is not supported`);
|
if (n < 0) alert(`Power ${n} is not supported`);
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
alert(`Power ${n} is not supported`);
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
alert(`Power ${n} is not supported`);
|
alert(`Power ${n} is not supported`);
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
-->
|
-->
|
||||||
<img src="figure-bracket-style.png">
|

|
||||||
|
|
||||||
For a real short code like `if (cond) return null`, one line is acceptable... But still a separate line for each statement is usually easier to read.
|
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.
|
||||||
|
|
||||||
### Line length
|
### Line length
|
||||||
|
|
||||||
Line length is limited. No one likes to eye-follow a long horizontal line. Doesn't matter if it's a text or a OR'ed list of `if` conditions. It's better to split it.
|
The maximal line length should be limited. No one likes to eye-follow a long horizontal line. Doesn't matter if it's a text or an OR'ed list of `if` conditions. It's better to split it.
|
||||||
|
|
||||||
Maximal line length is agreed on the team-level. It's usually 80 or 120 characters.
|
The maximal line length is agreed on the team-level. It's usually 80 or 120 characters.
|
||||||
|
|
||||||
### Indents
|
### Indents
|
||||||
|
|
||||||
There are two types of indents:
|
There are two types of indents:
|
||||||
|
|
||||||
<ul>
|
- **A horizontal indent: 2(4) spaces.**
|
||||||
<li>**A horizontal indent: 2(4) spaces.**
|
|
||||||
|
|
||||||
Usually spaces are used, because they allow more flexible configurations of indents than the "Tab" symbol.
|
A horizantal identation is made using either spaces or the "Tab" symbol (displayed as 2 or 4 or even 8 spaces, but 8 is too much).
|
||||||
|
|
||||||
For instance, we can align the arguments with the opening bracket:
|
Which one to choose is a kind of an old holy war. Spaces are a little more common nowadays.
|
||||||
|
|
||||||
```js
|
One of advantages of spaces over tabs is that they allow more flexible configurations of indents than the "Tab" symbol.
|
||||||
//+ no-beautify
|
|
||||||
show(parameters,
|
For instance, we can align the arguments with the opening bracket, like this:
|
||||||
|
|
||||||
|
```js no-beautify
|
||||||
|
show(parameters,
|
||||||
aligned,
|
aligned,
|
||||||
one,
|
one,
|
||||||
after,
|
after,
|
||||||
another);
|
another
|
||||||
```
|
) {
|
||||||
</li>
|
// ...
|
||||||
<li>**A vertical indent, line breaks for splitting the code in 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:
|
- **A vertical indent, line breaks for splitting the code in logical blocks.**
|
||||||
|
|
||||||
```js
|
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:
|
||||||
function pow(x, n) {
|
|
||||||
|
```js
|
||||||
|
function pow(x, n) {
|
||||||
let result = 1;
|
let result = 1;
|
||||||
// <--
|
// <--
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
|
@ -104,39 +112,24 @@ function pow(x, n) {
|
||||||
}
|
}
|
||||||
// <--
|
// <--
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Insert an additional line break where it helps to make the code more readable. There should not be more than 9 lines of code without a vertical indentation.
|
Insert an additional line break where it helps to make the code more readable. There should not be more than 9 lines of code without a vertical indentation.
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
### A semicolon
|
### A semicolon
|
||||||
|
|
||||||
Semicolons must be after each statement. Even if could possiblty be skipped.
|
A semicolons should be after each statement. Even if could possibly be skipped.
|
||||||
|
|
||||||
There are languages where a semicolon is truly optional. It's rarely used there.
|
There are languages where a semicolon is truly optional. It's rarely used there.
|
||||||
|
|
||||||
But in JavaScript a line break is sometimes interpreted as a semicolon and sometimes not. That leaves a place for programming errors, so semicolons must be at place, just as discussed [before](#semicolon).
|
But in JavaScript a line break is sometimes interpreted as a semicolon and sometimes not. That leaves a place for programming errors, so semicolons should be at place.
|
||||||
|
|
||||||
## The Naming
|
### Nesting levels
|
||||||
|
|
||||||
The general rule:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Variable name should be a noun.</li>
|
|
||||||
<li>Function name should be a verb, or start with a verbal prefix. There can be exceptions if covered by another rule.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
English language and camel-case notation is used.
|
|
||||||
|
|
||||||
Also discussed before -- [function naming](#function-naming) and [variables naming](#variable-naming).
|
|
||||||
|
|
||||||
## Nesting levels
|
|
||||||
|
|
||||||
There should not be too many nesting levels.
|
There should not be too many nesting levels.
|
||||||
|
|
||||||
Sometimes it's a good idea to [use the "continue"](#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 the loop to evade extra nesting in `if(..) { ... }`:
|
||||||
|
|
||||||
Instead of:
|
Instead of:
|
||||||
|
|
||||||
|
@ -191,7 +184,7 @@ function isEven(n) {
|
||||||
|
|
||||||
If there's a `return` inside the `if` block, then we need no `else` after it.
|
If there's a `return` inside the `if` block, then we need no `else` after it.
|
||||||
|
|
||||||
...Of course we can write even shorter here:
|
By the way, the very this function we can be implemented in a shorter way:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function isEven(n) {
|
function isEven(n) {
|
||||||
|
@ -199,19 +192,40 @@ function isEven(n) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
...But if the code `!(n % 2)` is less obvious for you than the former variant then use the former one.
|
But the code became less obvious.
|
||||||
|
|
||||||
|
...Of course we can write even shorter here:
|
||||||
|
**The most important not shortness, but simplicity and readability of the code.**
|
||||||
|
|
||||||
|
A shorter code is not always simpler to understand and maintain.
|
||||||
|
|
||||||
|
## The Naming
|
||||||
|
|
||||||
|
As a general rule:
|
||||||
|
|
||||||
|
- A variable name should be a noun.
|
||||||
|
- A function name should be a verb, or start with a verbal prefix. There can be exceptions if covered by another rule.
|
||||||
|
|
||||||
|
The camel-case notation is used for long words.
|
||||||
|
|
||||||
|
We discussed that before -- see [function basics](info:function-basics#function-naming) and [variables](info:variables#variable-naming).
|
||||||
|
|
||||||
|
A name should be descriptive and long enough, with the exception of:
|
||||||
|
- loop counter variables, `i` is a well-recognized name for a loop counter.
|
||||||
|
- functions/libraries that are well known and used very often.
|
||||||
|
- other cases when the code readability doesn't suffer.
|
||||||
|
|
||||||
**The most important for us is not shortness, but simplicity and readability of the code.**
|
|
||||||
|
|
||||||
It's quite not always the case that a brief code is simpler to understand.
|
|
||||||
|
|
||||||
## Functions = Comments
|
## Functions = Comments
|
||||||
|
|
||||||
Functions should be short and do exactly one thing. If that thing is big, maybe it's worth to split the function into parts.
|
Functions should be short and do exactly one thing. If that thing is big, maybe it's worth to split the function into parts.
|
||||||
|
|
||||||
Sometimes following this rule may be not easy, but it's a definitely good thing. So what's with the comments?
|
Sometimes following this rule may be not easy, but it's a definitely good thing.
|
||||||
|
|
||||||
A separate function is not only easier to test and debug -- it's very existance is a great comment.
|
...So what's here about comments?
|
||||||
|
|
||||||
|
A separate function is not only easier to test and debug -- it's very existance is a great comment!
|
||||||
|
|
||||||
For instance, compare the two functions `showPrimes(n)` below. Each one outputs [prime numbers](https://en.wikipedia.org/wiki/Prime_number) up to `n`.
|
For instance, compare the two functions `showPrimes(n)` below. Each one outputs [prime numbers](https://en.wikipedia.org/wiki/Prime_number) up to `n`.
|
||||||
|
|
||||||
|
@ -256,56 +270,50 @@ The second variant is easier to understand isn't it? Instead of the code piece w
|
||||||
|
|
||||||
There are three way to place the "helper" functions used in the code.
|
There are three way to place the "helper" functions used in the code.
|
||||||
|
|
||||||
<ol>
|
1. Above the code that uses them:
|
||||||
<li>Above the code that uses them:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// *!*function declarations*/!*
|
// *!*function declarations*/!*
|
||||||
function createElement() {
|
function createElement() {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
function setHandler(elem) {
|
function setHandler(elem) {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
function walkAround() {
|
function walkAround() {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
// *!*the code which uses them*/!*
|
// *!*the code which uses them*/!*
|
||||||
var elem = createElement();
|
var elem = createElement();
|
||||||
setHandler(elem);
|
setHandler(elem);
|
||||||
walkAround();
|
walkAround();
|
||||||
```
|
```
|
||||||
|
2. Code first, then functions
|
||||||
|
|
||||||
</li>
|
```js
|
||||||
<li>Code first, then functions
|
// *!*the code which uses the functions*/!*
|
||||||
|
var elem = createElement();
|
||||||
|
setHandler(elem);
|
||||||
|
walkAround();
|
||||||
|
|
||||||
```js
|
// --- *!*helper functions*/!* ---
|
||||||
// *!*the code which uses the functions*/!*
|
|
||||||
var elem = createElement();
|
|
||||||
setHandler(elem);
|
|
||||||
walkAround();
|
|
||||||
|
|
||||||
// --- *!*helper functions*/!* ---
|
function createElement() {
|
||||||
|
|
||||||
function createElement() {
|
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
function setHandler(elem) {
|
function setHandler(elem) {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
function walkAround() {
|
function walkAround() {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
3. Mixed, a function is described when it's first used.
|
||||||
</li>
|
|
||||||
<li>Mixed, a function is described when it's first used.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
Most of time, the second variant is preferred.
|
Most of time, the second variant is preferred.
|
||||||
|
|
||||||
|
@ -331,40 +339,35 @@ That's because when reading a code, we first want to know "what it does". If the
|
||||||
|
|
||||||
## Хорошие комментарии
|
## Хорошие комментарии
|
||||||
|
|
||||||
|
|
||||||
А какие комментарии полезны и приветствуются?
|
А какие комментарии полезны и приветствуются?
|
||||||
|
|
||||||
<ul>
|
- **Архитектурный комментарий -- "как оно, вообще, устроено".**
|
||||||
<li>**Архитектурный комментарий -- "как оно, вообще, устроено".**
|
|
||||||
|
|
||||||
Какие компоненты есть, какие технологии использованы, поток взаимодействия. О чём и зачем этот скрипт. Взгляд с высоты птичьего полёта. Эти комментарии особенно нужны, если вы не один, а проект большой.
|
Какие компоненты есть, какие технологии использованы, поток взаимодействия. О чём и зачем этот скрипт. Взгляд с высоты птичьего полёта. Эти комментарии особенно нужны, если вы не один, а проект большой.
|
||||||
|
|
||||||
Для описания архитектуры, кстати, создан специальный язык [UML](http://ru.wikipedia.org/wiki/Unified_Modeling_Language), красивые диаграммы, но можно и без этого. Главное -- чтобы понятно.
|
Для описания архитектуры, кстати, создан специальный язык [UML](http://ru.wikipedia.org/wiki/Unified_Modeling_Language), красивые диаграммы, но можно и без этого. Главное -- чтобы понятно.
|
||||||
</li>
|
- **Справочный комментарий перед функцией -- о том, что именно она делает, какие параметры принимает и что возвращает.**
|
||||||
<li>**Справочный комментарий перед функцией -- о том, что именно она делает, какие параметры принимает и что возвращает.**
|
|
||||||
|
|
||||||
Для таких комментариев существует синтаксис [JSDoc](http://en.wikipedia.org/wiki/JSDoc).
|
Для таких комментариев существует синтаксис [JSDoc](http://en.wikipedia.org/wiki/JSDoc).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/**
|
/**
|
||||||
* Возвращает x в степени n, только для натуральных n
|
* Возвращает x в степени n, только для натуральных n
|
||||||
*
|
*
|
||||||
* @param {number} x Число для возведения в степень.
|
* @param {number} x Число для возведения в степень.
|
||||||
* @param {number} n Показатель степени, натуральное число.
|
* @param {number} n Показатель степени, натуральное число.
|
||||||
* @return {number} x в степени n.
|
* @return {number} x в степени n.
|
||||||
*/
|
*/
|
||||||
function pow(x, n) {
|
function pow(x, n) {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Такие комментарии позволяют сразу понять, что принимает и что делает функция, не вникая в код.
|
Такие комментарии позволяют сразу понять, что принимает и что делает функция, не вникая в код.
|
||||||
|
|
||||||
Кстати, они автоматически обрабатываются многими редакторами, например [Aptana](http://aptana.com) и редакторами от [JetBrains](http://www.jetbrains.com/), которые учитывают их при автодополнении, а также выводят их в автоподсказках при наборе кода.
|
Кстати, они автоматически обрабатываются многими редакторами, например [Aptana](http://aptana.com) и редакторами от [JetBrains](http://www.jetbrains.com/), которые учитывают их при автодополнении, а также выводят их в автоподсказках при наборе кода.
|
||||||
|
|
||||||
Кроме того, есть инструменты, например [JSDoc 3](https://github.com/jsdoc3/jsdoc), которые умеют генерировать по таким комментариям документацию в формате HTML. Более подробную информацию об этом можно также найти на сайте [](http://usejsdoc.org/).
|
Кроме того, есть инструменты, например [JSDoc 3](https://github.com/jsdoc3/jsdoc), которые умеют генерировать по таким комментариям документацию в формате HTML. Более подробную информацию об этом можно также найти на сайте <http://usejsdoc.org/>.
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
**...Но куда более важными могут быть комментарии, которые объясняют не *что*, а *почему* в коде происходит именно это!**
|
**...Но куда более важными могут быть комментарии, которые объясняют не *что*, а *почему* в коде происходит именно это!**
|
||||||
|
|
||||||
|
@ -374,30 +377,23 @@ function pow(x, n) {
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
<dl>
|
Есть несколько способов решения задачи. Почему выбран именно этот?
|
||||||
<dt>Есть несколько способов решения задачи. Почему выбран именно этот?</dt>
|
: Например, пробовали решить задачу по-другому, но не получилось -- напишите об этом. Почему вы выбрали именно этот способ решения? Особенно это важно в тех случаях, когда используется не первый приходящий в голову способ, а какой-то другой.
|
||||||
<dd>
|
|
||||||
Например, пробовали решить задачу по-другому, но не получилось -- напишите об этом. Почему вы выбрали именно этот способ решения? Особенно это важно в тех случаях, когда используется не первый приходящий в голову способ, а какой-то другой.
|
|
||||||
|
|
||||||
Без этого возможна, например, такая ситуация:
|
Без этого возможна, например, такая ситуация:
|
||||||
<ul>
|
|
||||||
<li>Вы открываете код, который был написан какое-то время назад, и видите, что он "неоптимален".</li>
|
|
||||||
<li>Думаете: "Какой я был дурак", и переписываете под "более очевидный и правильный" вариант.</li>
|
|
||||||
<li>...Порыв, конечно, хороший, да только этот вариант вы уже обдумали раньше. И отказались, а почему -- забыли. В процессе переписывания вспомнили, конечно (к счастью), но результат - потеря времени на повторное обдумывание.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Комментарии, которые объясняют выбор решения, очень важны. Они помогают понять происходящее и предпринять правильные шаги при развитии кода.
|
- Вы открываете код, который был написан какое-то время назад, и видите, что он "неоптимален".
|
||||||
</dd>
|
- Думаете: "Какой я был дурак", и переписываете под "более очевидный и правильный" вариант.
|
||||||
<dt>Какие неочевидные возможности обеспечивает этот код? Где ещё они используются?</dt>
|
- ...Порыв, конечно, хороший, да только этот вариант вы уже обдумали раньше. И отказались, а почему -- забыли. В процессе переписывания вспомнили, конечно (к счастью), но результат - потеря времени на повторное обдумывание.
|
||||||
<dd>
|
|
||||||
В хорошем коде должно быть минимум неочевидного. Но там, где это есть -- пожалуйста, комментируйте.
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
Комментарии, которые объясняют выбор решения, очень важны. Они помогают понять происходящее и предпринять правильные шаги при развитии кода.
|
||||||
|
|
||||||
[smart header="Комментарии -- это важно"]
|
Какие неочевидные возможности обеспечивает этот код? Где ещё они используются?
|
||||||
|
: В хорошем коде должно быть минимум неочевидного. Но там, где это есть -- пожалуйста, комментируйте.
|
||||||
|
|
||||||
|
```smart header="Комментарии -- это важно"
|
||||||
Один из показателей хорошего разработчика -- качество комментариев, которые позволяют эффективно поддерживать код, возвращаться к нему после любой паузы и легко вносить изменения.
|
Один из показателей хорошего разработчика -- качество комментариев, которые позволяют эффективно поддерживать код, возвращаться к нему после любой паузы и легко вносить изменения.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
## Руководства по стилю
|
## Руководства по стилю
|
||||||
|
|
||||||
|
@ -407,13 +403,11 @@ function pow(x, n) {
|
||||||
|
|
||||||
Большинство есть на английском, сообщите мне, если найдёте хороший перевод:
|
Большинство есть на английском, сообщите мне, если найдёте хороший перевод:
|
||||||
|
|
||||||
<ul>
|
- [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
|
||||||
<li>[Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)</li>
|
- [JQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
|
||||||
<li>[JQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)</li>
|
- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)
|
||||||
<li>[Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)</li>
|
- [Idiomatic.JS](https://github.com/rwldrn/idiomatic.js) (есть [перевод](https://github.com/rwldrn/idiomatic.js/tree/master/translations/ru_RU))
|
||||||
<li>[Idiomatic.JS](https://github.com/rwldrn/idiomatic.js) (есть [перевод](https://github.com/rwldrn/idiomatic.js/tree/master/translations/ru_RU))</li>
|
- [Dojo Style Guide](http://dojotoolkit.org/community/styleGuide)
|
||||||
<li>[Dojo Style Guide](http://dojotoolkit.org/community/styleGuide)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Для того, чтобы начать разработку, вполне хватит элементов стилей, обозначенных в этой главе. В дальнейшем, посмотрев эти руководства, вы можете выработать и свой стиль, но лучше не делать его особенно "уникальным и неповторимым", себе дороже потом будет с людьми сотрудничать.
|
Для того, чтобы начать разработку, вполне хватит элементов стилей, обозначенных в этой главе. В дальнейшем, посмотрев эти руководства, вы можете выработать и свой стиль, но лучше не делать его особенно "уникальным и неповторимым", себе дороже потом будет с людьми сотрудничать.
|
||||||
|
|
||||||
|
@ -423,11 +417,9 @@ function pow(x, n) {
|
||||||
|
|
||||||
Самые известные -- это:
|
Самые известные -- это:
|
||||||
|
|
||||||
<ul>
|
- [JSLint](http://www.jslint.com/) -- проверяет код на соответствие [стилю JSLint](http://www.jslint.com/lint.html), в онлайн-интерфейсе вверху можно ввести код, а внизу различные настройки проверки, чтобы сделать её более мягкой.
|
||||||
<li>[JSLint](http://www.jslint.com/) -- проверяет код на соответствие [стилю JSLint](http://www.jslint.com/lint.html), в онлайн-интерфейсе вверху можно ввести код, а внизу различные настройки проверки, чтобы сделать её более мягкой. </li>
|
- [JSHint](http://www.jshint.com/) -- вариант JSLint с большим количеством настроек.
|
||||||
<li>[JSHint](http://www.jshint.com/) -- вариант JSLint с большим количеством настроек.</li>
|
- [Closure Linter](https://developers.google.com/closure/utilities/) -- проверка на соответствие [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml).
|
||||||
<li>[Closure Linter](https://developers.google.com/closure/utilities/) -- проверка на соответствие [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml).</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
В частности, JSLint и JSHint интегрированы с большинством редакторов, они гибко настраиваются под нужный стиль и совершенно незаметно улучшают разработку, подсказывая, где и что поправить.
|
В частности, JSLint и JSHint интегрированы с большинством редакторов, они гибко настраиваются под нужный стиль и совершенно незаметно улучшают разработку, подсказывая, где и что поправить.
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 76 KiB |
Binary file not shown.
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 152 KiB |
|
@ -12,23 +12,20 @@
|
||||||
|
|
||||||
Операторы разделяются точкой с запятой:
|
Операторы разделяются точкой с запятой:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert('Привет'); alert('Мир');
|
alert('Привет'); alert('Мир');
|
||||||
```
|
```
|
||||||
|
|
||||||
Как правило, перевод строки тоже подразумевает точку с запятой. Так тоже будет работать:
|
Как правило, перевод строки тоже подразумевает точку с запятой. Так тоже будет работать:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert('Привет')
|
alert('Привет')
|
||||||
alert('Мир')
|
alert('Мир')
|
||||||
```
|
```
|
||||||
|
|
||||||
...Однако, иногда JavaScript не вставляет точку с запятой. Например:
|
...Однако, иногда JavaScript не вставляет точку с запятой. Например:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
let a = 2
|
let a = 2
|
||||||
+3
|
+3
|
||||||
|
|
||||||
|
@ -37,8 +34,7 @@ alert(a); // 5
|
||||||
|
|
||||||
Бывают случаи, когда это ведёт к ошибкам, которые достаточно трудно найти и исправить, например:
|
Бывают случаи, когда это ведёт к ошибкам, которые достаточно трудно найти и исправить, например:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert("После этого сообщения будет ошибка")
|
alert("После этого сообщения будет ошибка")
|
||||||
|
|
||||||
[1, 2].forEach(alert)
|
[1, 2].forEach(alert)
|
||||||
|
@ -50,62 +46,53 @@ alert("После этого сообщения будет ошибка")
|
||||||
|
|
||||||
Поддерживаются однострочные комментарии `// ...` и многострочные `/* ... */`:
|
Поддерживаются однострочные комментарии `// ...` и многострочные `/* ... */`:
|
||||||
|
|
||||||
Подробнее: [](/structure).
|
Подробнее: <info:structure>.
|
||||||
|
|
||||||
## Переменные и типы
|
## Переменные и типы
|
||||||
|
|
||||||
<ul>
|
- Объявляются директивой `let`. Могут хранить любое значение:
|
||||||
<li>Объявляются директивой `let`. Могут хранить любое значение:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let x = 5;
|
let x = 5;
|
||||||
x = "Петя";
|
x = "Петя";
|
||||||
```
|
```
|
||||||
|
- Есть 5 "примитивных" типов и объекты:
|
||||||
|
|
||||||
</li>
|
```js no-beautify
|
||||||
<li>Есть 5 "примитивных" типов и объекты:
|
x = 1; // число
|
||||||
|
x = "Тест"; // строка, кавычки могут быть одинарные или двойные
|
||||||
|
x = true; // булево значение true/false
|
||||||
|
x = null; // спец. значение (само себе тип)
|
||||||
|
x = undefined; // спец. значение (само себе тип)
|
||||||
|
```
|
||||||
|
|
||||||
```js
|
Также есть специальные числовые значения `Infinity` (бесконечность) и `NaN`.
|
||||||
//+ no-beautify
|
|
||||||
x = 1; // число
|
|
||||||
x = "Тест"; // строка, кавычки могут быть одинарные или двойные
|
|
||||||
x = true; // булево значение true/false
|
|
||||||
x = null; // спец. значение (само себе тип)
|
|
||||||
x = undefined; // спец. значение (само себе тип)
|
|
||||||
```
|
|
||||||
|
|
||||||
Также есть специальные числовые значения `Infinity` (бесконечность) и `NaN`.
|
Значение `NaN` обозначает ошибку и является результатом числовой операции, если она некорректна.
|
||||||
|
- **Значение `null` не является "ссылкой на нулевой адрес/объект" или чем-то подобным. Это просто специальное значение.**
|
||||||
|
|
||||||
Значение `NaN` обозначает ошибку и является результатом числовой операции, если она некорректна.
|
Оно присваивается, если мы хотим указать, что значение переменной неизвестно.
|
||||||
</li>
|
|
||||||
<li>**Значение `null` не является "ссылкой на нулевой адрес/объект" или чем-то подобным. Это просто специальное значение.**
|
|
||||||
|
|
||||||
Оно присваивается, если мы хотим указать, что значение переменной неизвестно.
|
Например:
|
||||||
|
|
||||||
Например:
|
```js
|
||||||
|
let age = null; // возраст неизвестен
|
||||||
|
```
|
||||||
|
- **Значение `undefined` означает "переменная не присвоена".**
|
||||||
|
|
||||||
```js
|
Например:
|
||||||
let age = null; // возраст неизвестен
|
|
||||||
```
|
|
||||||
|
|
||||||
</li>
|
```js
|
||||||
<li>**Значение `undefined` означает "переменная не присвоена".**
|
let x;
|
||||||
|
alert( x ); // undefined
|
||||||
|
```
|
||||||
|
|
||||||
Например:
|
Можно присвоить его и явным образом: `x = undefined`, но так делать не рекомендуется.
|
||||||
|
|
||||||
```js
|
Про объекты мы поговорим в главе <info:object>, они в JavaScript сильно отличаются от большинства других языков.
|
||||||
let x;
|
- В имени переменной могут быть использованы любые буквы или цифры, но цифра не может быть первой. Символы доллар `$` и подчёркивание `_` допускаются наравне с буквами.
|
||||||
alert( x ); // undefined
|
|
||||||
```
|
|
||||||
|
|
||||||
Можно присвоить его и явным образом: `x = undefined`, но так делать не рекомендуется.
|
Подробнее: <info:variables>, <info:types-intro>.
|
||||||
|
|
||||||
Про объекты мы поговорим в главе [](/object), они в JavaScript сильно отличаются от большинства других языков.
|
|
||||||
</li>
|
|
||||||
<li>В имени переменной могут быть использованы любые буквы или цифры, но цифра не может быть первой. Символы доллар `$` и подчёркивание `_` допускаются наравне с буквами.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Подробнее: [](/variables), [](/types-intro).
|
|
||||||
|
|
||||||
## Строгий режим
|
## Строгий режим
|
||||||
|
|
||||||
|
@ -121,27 +108,24 @@ alert( x ); // undefined
|
||||||
|
|
||||||
Одно из важных изменений в современном стандарте -- все переменные нужно объявлять через `let`. Есть и другие, которые мы изучим позже, вместе с соответствующими возможностями языка.
|
Одно из важных изменений в современном стандарте -- все переменные нужно объявлять через `let`. Есть и другие, которые мы изучим позже, вместе с соответствующими возможностями языка.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Взаимодействие с посетителем
|
## Взаимодействие с посетителем
|
||||||
|
|
||||||
Простейшие функции для взаимодействия с посетителем в браузере:
|
Простейшие функции для взаимодействия с посетителем в браузере:
|
||||||
|
|
||||||
<dl>
|
["prompt(вопрос[, по_умолчанию])"](https://developer.mozilla.org/en/DOM/window.prompt)
|
||||||
<dt>["prompt(вопрос[, по_умолчанию])"](https://developer.mozilla.org/en/DOM/window.prompt)</dt>
|
: Задать `вопрос` и возвратить введённую строку, либо `null`, если посетитель нажал "Отмена".
|
||||||
<dd>Задать `вопрос` и возвратить введённую строку, либо `null`, если посетитель нажал "Отмена".</dd>
|
|
||||||
<dt>["confirm(вопрос)"](https://developer.mozilla.org/en/DOM/window.confirm)</dt>
|
["confirm(вопрос)"](https://developer.mozilla.org/en/DOM/window.confirm)
|
||||||
<dd>Задать `вопрос` и предложить кнопки "Ок", "Отмена". Возвращает, соответственно, `true/false`.</dd>
|
: Задать `вопрос` и предложить кнопки "Ок", "Отмена". Возвращает, соответственно, `true/false`.
|
||||||
<dt>["alert(сообщение)"](https://developer.mozilla.org/en/DOM/window.alert)</dt>
|
|
||||||
<dd>Вывести сообщение на экран.</dd>
|
["alert(сообщение)"](https://developer.mozilla.org/en/DOM/window.alert)
|
||||||
</dl>
|
: Вывести сообщение на экран.
|
||||||
|
|
||||||
Все эти функции являются *модальными*, т.е. не позволяют посетителю взаимодействовать со страницей до ответа.
|
Все эти функции являются *модальными*, т.е. не позволяют посетителю взаимодействовать со страницей до ответа.
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let userName = prompt("Введите имя?", "Василий");
|
let userName = prompt("Введите имя?", "Василий");
|
||||||
let isTeaWanted = confirm("Вы хотите чаю?");
|
let isTeaWanted = confirm("Вы хотите чаю?");
|
||||||
|
|
||||||
|
@ -149,47 +133,40 @@ alert( "Посетитель: " + userName );
|
||||||
alert( "Чай: " + isTeaWanted );
|
alert( "Чай: " + isTeaWanted );
|
||||||
```
|
```
|
||||||
|
|
||||||
Подробнее: [](/uibasic).
|
Подробнее: <info:uibasic>.
|
||||||
|
|
||||||
## Особенности операторов
|
## Особенности операторов
|
||||||
|
|
||||||
|
- **Для сложения строк используется оператор `+`.**
|
||||||
|
|
||||||
|
Если хоть один аргумент -- строка, то другой тоже приводится к строке:
|
||||||
|
|
||||||
|
```js run
|
||||||
|
alert( 1 + 2 ); // 3, число
|
||||||
|
alert( '1' + 2 ); // '12', строка
|
||||||
|
alert( 1 + '2' ); // '12', строка
|
||||||
|
```
|
||||||
|
- **Сравнение `===` проверяет точное равенство, включая одинаковый тип.** Это самый очевидный и надёжный способ сравнения.
|
||||||
|
|
||||||
|
**Остальные сравнения `== < <= > >=` осуществляют числовое приведение типа:**
|
||||||
|
|
||||||
|
```js run
|
||||||
|
alert( 0 == false ); // true
|
||||||
|
alert( true > 0 ); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
Исключение -- сравнение двух строк (см. далее).
|
||||||
|
|
||||||
|
**Исключение: значения `null` и `undefined` ведут себя в сравнениях не как ноль.**
|
||||||
<ul>
|
<ul>
|
||||||
<li>**Для сложения строк используется оператор `+`.**
|
<li>Они равны `null == undefined` друг другу и не равны ничему ещё. В частности, не равны нулю.
|
||||||
|
- В других сравнениях (кроме `===`) значение `null` преобразуется к нулю, а `undefined` -- становится `NaN` ("ошибка").
|
||||||
Если хоть один аргумент -- строка, то другой тоже приводится к строке:
|
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
alert( 1 + 2 ); // 3, число
|
|
||||||
alert( '1' + 2 ); // '12', строка
|
|
||||||
alert( 1 + '2' ); // '12', строка
|
|
||||||
```
|
|
||||||
|
|
||||||
</li>
|
|
||||||
<li>**Сравнение `===` проверяет точное равенство, включая одинаковый тип.** Это самый очевидный и надёжный способ сравнения.
|
|
||||||
|
|
||||||
**Остальные сравнения `== < <= > >=` осуществляют числовое приведение типа:**
|
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
alert( 0 == false ); // true
|
|
||||||
alert( true > 0 ); // true
|
|
||||||
```
|
|
||||||
|
|
||||||
Исключение -- сравнение двух строк (см. далее).
|
|
||||||
|
|
||||||
**Исключение: значения `null` и `undefined` ведут себя в сравнениях не как ноль.**
|
|
||||||
<ul>
|
|
||||||
<li>Они равны `null == undefined` друг другу и не равны ничему ещё. В частности, не равны нулю.</li>
|
|
||||||
<li>В других сравнениях (кроме `===`) значение `null` преобразуется к нулю, а `undefined` -- становится `NaN` ("ошибка").</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Такое поведение может привести к неочевидным результатам, поэтому лучше всего использовать для сравнения с ними `===`. Оператор `==` тоже можно, если не хотите отличать `null` от `undefined`.
|
Такое поведение может привести к неочевидным результатам, поэтому лучше всего использовать для сравнения с ними `===`. Оператор `==` тоже можно, если не хотите отличать `null` от `undefined`.
|
||||||
|
|
||||||
Например, забавное следствие этих правил для `null`:
|
Например, забавное следствие этих правил для `null`:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert( null > 0 ); // false, т.к. null преобразовано к 0
|
alert( null > 0 ); // false, т.к. null преобразовано к 0
|
||||||
alert( null >= 0 ); // true, т.к. null преобразовано к 0
|
alert( null >= 0 ); // true, т.к. null преобразовано к 0
|
||||||
alert( null == 0 ); // false, в стандарте явно указано, что null равен лишь undefined
|
alert( null == 0 ); // false, в стандарте явно указано, что null равен лишь undefined
|
||||||
|
@ -199,20 +176,18 @@ alert( null == 0 ); // false, в стандарте явно указано, ч
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
|
||||||
<li>**Сравнение строк -- лексикографическое, символы сравниваются по своим unicode-кодам.**
|
<li>**Сравнение строк -- лексикографическое, символы сравниваются по своим unicode-кодам.**
|
||||||
|
|
||||||
Поэтому получается, что строчные буквы всегда больше, чем прописные:
|
Поэтому получается, что строчные буквы всегда больше, чем прописные:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 'а' > 'Я' ); // true
|
alert( 'а' > 'Я' ); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Подробнее: [](/operators), [](/comparison).
|
Подробнее: <info:operators>, <info:comparison>.
|
||||||
|
|
||||||
## Логические операторы
|
## Логические операторы
|
||||||
|
|
||||||
|
@ -228,61 +203,55 @@ alert( 'а' > 'Я' ); // true
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 0 && 1 ); // 0
|
alert( 0 && 1 ); // 0
|
||||||
alert( 1 && 2 && 3 ); // 3
|
alert( 1 && 2 && 3 ); // 3
|
||||||
alert( null || 1 || 2 ); // 1
|
alert( null || 1 || 2 ); // 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Подробнее: [](/logical-ops).
|
Подробнее: <info:logical-ops>.
|
||||||
|
|
||||||
## Циклы
|
## Циклы
|
||||||
|
|
||||||
<ul>
|
- Поддерживаются три вида циклов:
|
||||||
<li>Поддерживаются три вида циклов:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// 1
|
// 1
|
||||||
while (условие) {
|
while (условие) {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2
|
// 2
|
||||||
do {
|
do {
|
||||||
...
|
...
|
||||||
} while (условие);
|
} while (условие);
|
||||||
|
|
||||||
// 3
|
// 3
|
||||||
for let i = 0; i < 10; i++) {
|
for let i = 0; i < 10; i++) {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
- Переменную можно объявлять прямо в цикле, но видна она будет и за его пределами.
|
||||||
|
- Поддерживаются директивы `break/continue` для выхода из цикла/перехода на следующую итерацию.
|
||||||
|
|
||||||
</li>
|
Для выхода одновременно из нескольких уровней цикла можно задать метку.
|
||||||
<li>Переменную можно объявлять прямо в цикле, но видна она будет и за его пределами.</li>
|
|
||||||
<li>Поддерживаются директивы `break/continue` для выхода из цикла/перехода на следующую итерацию.
|
|
||||||
|
|
||||||
Для выхода одновременно из нескольких уровней цикла можно задать метку.
|
Синтаксис: "`имя_метки:`", ставится она только перед циклами и блоками, например:
|
||||||
|
|
||||||
Синтаксис: "`имя_метки:`", ставится она только перед циклами и блоками, например:
|
```js
|
||||||
|
*!*outer:*/!*
|
||||||
```js
|
for(;;) {
|
||||||
*!*outer:*/!*
|
|
||||||
for(;;) {
|
|
||||||
...
|
...
|
||||||
for(;;) {
|
for(;;) {
|
||||||
...
|
...
|
||||||
*!*break outer;*/!*
|
*!*break outer;*/!*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Переход на метку возможен только изнутри цикла, и только на внешний блок по отношению к данному циклу. В произвольное место программы перейти нельзя.
|
Переход на метку возможен только изнутри цикла, и только на внешний блок по отношению к данному циклу. В произвольное место программы перейти нельзя.
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Подробнее: [](/while-for).
|
Подробнее: <info:while-for>.
|
||||||
|
|
||||||
## Конструкция switch
|
## Конструкция switch
|
||||||
|
|
||||||
|
@ -290,8 +259,7 @@ for(;;) {
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let age = prompt('Ваш возраст', 18);
|
let age = prompt('Ваш возраст', 18);
|
||||||
|
|
||||||
switch (age) {
|
switch (age) {
|
||||||
|
@ -307,14 +275,13 @@ switch (age) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Подробнее: [](/switch).
|
Подробнее: <info:switch>.
|
||||||
|
|
||||||
## Функции
|
## Функции
|
||||||
|
|
||||||
Синтаксис функций в JavaScript:
|
Синтаксис функций в JavaScript:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
// function имя(список параметров) { тело }
|
// function имя(список параметров) { тело }
|
||||||
function sum(a, b) {
|
function sum(a, b) {
|
||||||
let result = a + b;
|
let result = a + b;
|
||||||
|
@ -326,23 +293,17 @@ function sum(a, b) {
|
||||||
alert( sum(1, 2) ); // 3
|
alert( sum(1, 2) ); // 3
|
||||||
```
|
```
|
||||||
|
|
||||||
<ul>
|
- `sum` -- имя функции, ограничения на имя функции -- те же, что и на имя переменной.
|
||||||
<li>`sum` -- имя функции, ограничения на имя функции -- те же, что и на имя переменной.</li>
|
- Переменные, объявленные через `let` внутри функции, видны везде внутри этой функции, блоки `if`, `for` и т.п. на видимость не влияют.
|
||||||
<li>Переменные, объявленные через `let` внутри функции, видны везде внутри этой функции, блоки `if`, `for` и т.п. на видимость не влияют.</li>
|
- Параметры копируются в локальные переменные `a`, `b`.
|
||||||
<li>Параметры копируются в локальные переменные `a`, `b`.
|
- Функция без `return` считается возвращающей `undefined`. Вызов `return` без значения также возвращает `undefined`:
|
||||||
</li>
|
|
||||||
<li>Функция без `return` считается возвращающей `undefined`. Вызов `return` без значения также возвращает `undefined`:
|
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
function f() { }
|
||||||
function f() { }
|
alert( f() ); // undefined
|
||||||
alert( f() ); // undefined
|
```
|
||||||
```
|
|
||||||
|
|
||||||
</li>
|
Подробнее: <info:function-basics>.
|
||||||
</ul>
|
|
||||||
|
|
||||||
Подробнее: [](/function-basics).
|
|
||||||
|
|
||||||
## Function Declaration и Expression
|
## Function Declaration и Expression
|
||||||
|
|
||||||
|
@ -350,8 +311,7 @@ alert( f() ); // undefined
|
||||||
|
|
||||||
Её можно создать в любом месте кода и присвоить в переменную, вот так:
|
Её можно создать в любом месте кода и присвоить в переменную, вот так:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let sum = function(a, b) {
|
let sum = function(a, b) {
|
||||||
let result = a + b;
|
let result = a + b;
|
||||||
|
|
||||||
|
@ -367,7 +327,7 @@ alert( sum(1, 2) ); // 3
|
||||||
|
|
||||||
Обычно это удобно, но может быть проблемой, если нужно объявить функцию в зависимости от условия. В этом случае, а также в других ситуациях, когда хочется создать функцию "здесь и сейчас", используют Function Expression.
|
Обычно это удобно, но может быть проблемой, если нужно объявить функцию в зависимости от условия. В этом случае, а также в других ситуациях, когда хочется создать функцию "здесь и сейчас", используют Function Expression.
|
||||||
|
|
||||||
Детали: [](/function-declaration-expression).
|
Детали: <info:function-declaration-expression>.
|
||||||
|
|
||||||
## Named Function Expression
|
## Named Function Expression
|
||||||
|
|
||||||
|
@ -377,8 +337,7 @@ alert( sum(1, 2) ); // 3
|
||||||
|
|
||||||
Например, создадим функцию для вычисления факториала как Function Expression и дадим ей имя `me`:
|
Например, создадим функцию для вычисления факториала как Function Expression и дадим ей имя `me`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let factorial = function me(n) {
|
let factorial = function me(n) {
|
||||||
return (n == 1) ? n : n * me(n - 1);
|
return (n == 1) ? n : n * me(n - 1);
|
||||||
}
|
}
|
||||||
|
@ -391,7 +350,7 @@ alert( me ); // ошибка, нет такой переменной
|
||||||
|
|
||||||
Ограничение видимости для имени не работает в IE8-, но вызов с его помощью работает во всех браузерах.
|
Ограничение видимости для имени не работает в IE8-, но вызов с его помощью работает во всех браузерах.
|
||||||
|
|
||||||
Более развёрнуто: [](/named-function-expression).
|
Более развёрнуто: <info:named-function-expression>.
|
||||||
|
|
||||||
## Итого
|
## Итого
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
In this section we explore the code structure and statements.
|
In this section we explore the code structure and statements.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## Statements
|
## Statements
|
||||||
|
|
||||||
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.
|
||||||
|
@ -11,15 +12,13 @@ Another statement can be separated with a semicolon.
|
||||||
|
|
||||||
For example, here we split the message into two:
|
For example, here we split the message into two:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert( 'Hello' ); alert( 'World' );
|
alert( 'Hello' ); alert( 'World' );
|
||||||
```
|
```
|
||||||
|
|
||||||
Usually each statement is written on a separate line -- thus the code becomes more readable:
|
Usually each statement is written on a separate line -- thus the code becomes more readable:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert( 'Hello' );
|
alert( 'Hello' );
|
||||||
alert( 'World' );
|
alert( 'World' );
|
||||||
```
|
```
|
||||||
|
@ -30,8 +29,7 @@ The semicolon may be omitted in most cases when a line break exists.
|
||||||
|
|
||||||
This would also work:
|
This would also work:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert( 'Hello' )
|
alert( 'Hello' )
|
||||||
alert( 'World' )
|
alert( 'World' )
|
||||||
```
|
```
|
||||||
|
@ -42,8 +40,7 @@ In this case JavaScript interprets the line break as a splitter and automaticall
|
||||||
|
|
||||||
Consider this code as an example:
|
Consider this code as an example:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert(3 +
|
alert(3 +
|
||||||
1
|
1
|
||||||
+ 2);
|
+ 2);
|
||||||
|
@ -57,11 +54,10 @@ JavaScript does not insert semicolons here. It is intuitively obvious that the f
|
||||||
|
|
||||||
Errors which come appear in such cases are quite hard to find and fix.
|
Errors which come appear in such cases are quite hard to find and fix.
|
||||||
|
|
||||||
[smart header="An example of the error"]
|
````smart header="An example of the error"
|
||||||
For a curious reader who might be interested in a concrete example, check this code out:
|
For a curious reader who might be interested in a concrete example, check this code out:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
[1, 2].forEach(alert)
|
[1, 2].forEach(alert)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -71,8 +67,7 @@ Please don't think about the meaning of `[...].forEach` just for now -- it does
|
||||||
|
|
||||||
Now let's prepend an `alert` *without a semicolon* before it:
|
Now let's prepend an `alert` *without a semicolon* before it:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert( "..." ) // works
|
alert( "..." ) // works
|
||||||
[1, 2].forEach(alert) // doesn't work!
|
[1, 2].forEach(alert) // doesn't work!
|
||||||
```
|
```
|
||||||
|
@ -80,21 +75,18 @@ alert( "..." ) // works
|
||||||
Now only the phrase is shown, not the numbers. And we can see an error in the developer console.
|
Now only the phrase is shown, not the numbers. And we can see an error in the developer console.
|
||||||
|
|
||||||
But everything's fine if we add a semicolon:
|
But everything's fine if we add a semicolon:
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( "With the semicolon everything works" ); // printed
|
alert( "With the semicolon everything works" ); // printed
|
||||||
[1, 2].forEach(alert) // printed too
|
[1, 2].forEach(alert) // printed too
|
||||||
```
|
```
|
||||||
|
|
||||||
The error in the former variant occurs because JavaScript engine does not autoinsert a semicolon before square brackets `[...]`, so it was actually treated as a one-line statement:
|
The error in the former variant occurs because JavaScript engine does not autoinsert a semicolon before square brackets `[...]`, so it was actually treated as a one-line statement:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
// without semicolon after alert it becomes
|
// without semicolon after alert it becomes
|
||||||
alert( "..." )[1, 2].forEach(alert) // doesn't work!
|
alert( "..." )[1, 2].forEach(alert) // doesn't work!
|
||||||
```
|
```
|
||||||
|
````
|
||||||
[/smart]
|
|
||||||
|
|
||||||
As a conclusion, it's recommended to put semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community.
|
As a conclusion, it's recommended to put semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community.
|
||||||
|
|
||||||
|
@ -109,8 +101,7 @@ Comments can be put into any place of the script. They don't affect it's executi
|
||||||
It may occupy a full line of it's own or follow a statement.
|
It may occupy a full line of it's own or follow a statement.
|
||||||
|
|
||||||
Like this:
|
Like this:
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
// This says "Hello" (the comment occupies a line of it's own)
|
// This says "Hello" (the comment occupies a line of it's own)
|
||||||
alert( 'Hello' );
|
alert( 'Hello' );
|
||||||
|
|
||||||
|
@ -119,8 +110,7 @@ alert( 'World' ); // ...this says "World" (the comment follows a statement)
|
||||||
|
|
||||||
*Multiline comments* start with a slash and a star <code>"/*"</code> and end with a star and a slash <code>"*/"</code>, like this:
|
*Multiline comments* start with a slash and a star <code>"/*"</code> and end with a star and a slash <code>"*/"</code>, like this:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
/* An example with two messages.
|
/* An example with two messages.
|
||||||
This is a multiline comment.
|
This is a multiline comment.
|
||||||
*/
|
*/
|
||||||
|
@ -132,31 +122,29 @@ The content of comments is ignored, so if we put a code inside <code>/* ...
|
||||||
|
|
||||||
Sometimes it's used to temporarily disable a part of the code.
|
Sometimes it's used to temporarily disable a part of the code.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
/* Commenting out the code
|
/* Commenting out the code
|
||||||
alert( 'Hello' );
|
alert( 'Hello' );
|
||||||
*/
|
*/
|
||||||
alert( 'World' );
|
alert( 'World' );
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="Use hotkeys!"]
|
```smart header="Use hotkeys!"
|
||||||
In most editors a line of code can be commented out by [key Ctrl+/] hotkey for a single-line comment and something like [key Ctrl+Shift+/] -- for multiline comments (select a code and press the hotkey).
|
In most editors a line of code can be commented out by `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a code and press the hotkey).
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
[warn header="Nested comments are not supported!"]
|
````warn header="Nested comments are not supported!"
|
||||||
There may not be comments inside comments.
|
There may not be comments inside comments.
|
||||||
|
|
||||||
This code will die with an error:
|
This code will die with an error:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
/*
|
/*
|
||||||
/* nested comment ?!? */
|
/* nested comment ?!? */
|
||||||
*/
|
*/
|
||||||
alert( 'World' );
|
alert( 'World' );
|
||||||
```
|
```
|
||||||
[/warn]
|
````
|
||||||
|
|
||||||
Don't hesitate to comment.
|
Don't hesitate to comment.
|
||||||
|
|
||||||
|
@ -164,18 +152,15 @@ Comments increase the overall code footprint, but that's not a problem at all, b
|
||||||
|
|
||||||
There are various types of comments, answering different questions:
|
There are various types of comments, answering different questions:
|
||||||
|
|
||||||
<ul>
|
- What the code does?
|
||||||
<li>What the code does?</li>
|
- Why the code is written like that?
|
||||||
<li>Why the code is written like that?</li>
|
- Which counter-intuitive or implicit connections it has with other parts of the script?
|
||||||
<li>Which counter-intuitive or implicit connections it has with other parts of the script?</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
Further in the tutorial we'll make more notes about how to write the code better, easier to read and maintain. We'll also talk more about comments.
|
Further in the tutorial we'll make more notes about how to write the code better, easier to read and maintain. We'll also talk more about comments.
|
||||||
|
|
||||||
[smart header="The good code is inherently readable and self-commenting"]
|
```smart header="The good code is inherently readable and self-commenting"
|
||||||
Please note that the first type of comments ("what the code does") should be used to describe a "high-level" action, like the overall architecture, a function or a chunk of code. It's purpose is to give an overview, so a reader doesn't need to delve into the code and figure out.
|
Please note that the first type of comments ("what the code does") should be used to describe a "high-level" action, like the overall architecture, a function or a chunk of code. It's purpose is to give an overview, so a reader doesn't need to delve into the code and figure out.
|
||||||
|
|
||||||
Novice programmers sometimes tend to elaborate too much. Please don't. The good code is inherently readable. No need to describe what few lines do. Unless it's something hard to grasp, and *then* it's worth to consider rewriting the code at the first place rather than commenting it.
|
Novice programmers sometimes tend to elaborate too much. Please don't. The good code is inherently readable. No need to describe what few lines do. Unless it's something hard to grasp, and *then* it's worth to consider rewriting the code at the first place rather than commenting it.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
|
|
|
@ -23,36 +23,52 @@ For example
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
[warn header="There's no way to cancel `use strict`"]
|
```warn header="There's no way to cancel `use strict`"
|
||||||
There is no directive `"no use strict"` or alike, that would return the old behavior.
|
There is no directive `"no use strict"` or alike, that would return the old behavior.
|
||||||
|
|
||||||
Once we enter the strict mode, there's no return.
|
Once we enter the strict mode, there's no return.
|
||||||
[/warn]
|
```
|
||||||
|
|
||||||
|
````warn header="Ensure that 'use strict' is at the top"
|
||||||
|
Please make sure that `"use strict"` is on the top of the script, otherwise the strict mode may not be enabled.
|
||||||
|
|
||||||
|
There is no strict mode here:
|
||||||
|
|
||||||
|
```js no-strict
|
||||||
|
alert("some code");
|
||||||
|
// "use strict" below is ignored, must be not on the top
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// strict mode is not activated
|
||||||
|
```
|
||||||
|
|
||||||
|
Only comments may appear above `"use strict"`.
|
||||||
|
````
|
||||||
|
|
||||||
|
|
||||||
|
```smart header="`use strict` for functions"
|
||||||
|
We will learn [functions](/function-basics) very soon.
|
||||||
|
|
||||||
|
Looking ahead let's just note that `"use strict"` can be put at the start of a function instead of the whole script. Then the strict mode is enabled in this function only. But that limitation is exceptionally rarely needed.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
[smart header="`use strict` for functions"]
|
|
||||||
We will learn [functions](/function-basics) very soon. Looking ahead let's just note that `"use strict"` can be put at the start of a function instead of the whole script. Then the strict mode is enabled in this function only.
|
|
||||||
[/smart]
|
|
||||||
|
|
||||||
## Do I really need "use strict"?
|
## Do I really need "use strict"?
|
||||||
|
|
||||||
Actually, yes. All modern browsers support it.
|
Technically, we can `"use strict"`, the code will work in the "old mode". But it is suggested that you use it all the time.
|
||||||
|
|
||||||
More than that, there are several JavaScript features that enable strict mode implicitly, "by default". Namely, "classes" and "modules" automatically switch the interpreter to "strict mode".
|
1. First, because all modern browsers support it, except Internet Explorer 9 and lower.
|
||||||
|
2. Second, the modern JavaScript actually pushes us into the strict mode! There are several JavaScript features that enable strict mode automatically. Namely, "classes" and "modules" automatically switch the interpreter to "strict mode". So, it's hard to evade it.
|
||||||
|
3. And the last. If we're going to support Internet Explorer 9 and lower, that will not be a problem. It does not support `"use strict"` but the differences between the "old" and the "modern" modes are not that huge.
|
||||||
|
|
||||||
So there's no way to stay modern and evade `"use strict"`.
|
|
||||||
|
|
||||||
The only downside is Internet Explorer prior to version 10. Those browsers do not support `"use strict"`, so if we plan to support them, then our code must be compatible with the old behavior. But that's an easy thing to do if we keep it in mind.
|
|
||||||
|
|
||||||
Sometimes we can pass by a 3rd party library that do not work correctly when the calling code is in the strict mode. But that happens very rarely, and can usually be fixed on a per-library basis.
|
|
||||||
|
|
||||||
Here in the tutorial all code works correctly in `"use strict"`.
|
Here in the tutorial all code works correctly in `"use strict"`.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
- JavaScript without `"use strict"` may execute differently in some cases. Further in the tutorial we'll see what's different. Thankfully, not so much.
|
||||||
<li>JavaScript without `"use strict"` may execute differently in some cases. Further in the tutorial we'll see what's different. Thankfully, not so much.</li>
|
- Several modern features of the language enable `"use strict"` implicitly, so there's just no way to evade it.
|
||||||
<li>Several modern features of the language enable `"use strict"` implicitly, so there's just no way to evade it.</li>
|
- It is strongly advised to `"use strict"` everywhere, but keep in mind compability if we are to support old IE.
|
||||||
<li>It is strongly advised to `"use strict"` everywhere, but keep in mind compability if we are to support old IE.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
In the code below, each line corresponds to the item in the task list.
|
In the code below, each line corresponds to the item in the task list.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let admin, name; // can declare two variables at once
|
let admin, name; // can declare two variables at once
|
||||||
|
|
||||||
name = "John";
|
name = "John";
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
importance: 2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Working with variables
|
# Working with variables
|
||||||
|
|
||||||
[importance 2]
|
1. Declare two variables: `admin` and `name`.
|
||||||
|
2. Assign the value `"John"` to `name`.
|
||||||
<ol>
|
3. Copy the value from `name` to `admin`.
|
||||||
<li>Declare two variables: `admin` and `name`. </li>
|
4. Show the value of `admin` using `alert` (must output "John").
|
||||||
<li>Assign the value `"John"` to `name`.</li>
|
|
||||||
<li>Copy the value from `name` to `admin`.</li>
|
|
||||||
<li>Show the value of `admin` using `alert` (must output "John").</li>
|
|
||||||
</ol>
|
|
||||||
|
|
|
@ -18,4 +18,4 @@ Again, we could shorten that to `userName` if we know beyound the reasonable dou
|
||||||
|
|
||||||
Modern editors and autocomplete make long variable names easy to write. Don't save on them. Say, a name with 3 words in it is fine.
|
Modern editors and autocomplete make long variable names easy to write. Don't save on them. Say, a name with 3 words in it is fine.
|
||||||
|
|
||||||
And if your editor does not help here, get [a new one](/editor).
|
And if your editor does not have proper autocompletion, get [a new one](/editor).
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
importance: 3
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Giving the right name
|
# Giving the right name
|
||||||
|
|
||||||
[importance 3]
|
1. Create the variable to store the name of our planet. Assign the value `"Earth"` to it. What should be its name?
|
||||||
|
2. Create the variable to store the name of the current visitor. What about its name?
|
||||||
<ol>
|
|
||||||
<li>Create the variable to store the name of our planet. Assign the value `"Earth"` to it. What should be its name?</li>
|
|
||||||
<li>Create the variable to store the name of the current visitor. What about its name?</li>
|
|
||||||
</ol>
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ The statement below creates (in other words: *declares* or *defines*) the variab
|
||||||
let message;
|
let message;
|
||||||
```
|
```
|
||||||
|
|
||||||
Now we can store some data in it:
|
Now we can put some data into it:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let message;
|
let message;
|
||||||
|
@ -32,8 +32,7 @@ message = 'Hello'; // store the string
|
||||||
|
|
||||||
The string is now saved into the memory area assosiated with that variable. We can access it using the variable name:
|
The string is now saved into the memory area assosiated with that variable. We can access it using the variable name:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let message;
|
let message;
|
||||||
message = 'Hello!';
|
message = 'Hello!';
|
||||||
|
|
||||||
|
@ -44,14 +43,14 @@ alert( message ); // shows the variable content
|
||||||
|
|
||||||
To be concise we can merge the variable declaration and assignment into a single line:
|
To be concise we can merge the variable declaration and assignment into a single line:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
let message = 'Hello!';
|
let message = 'Hello!';
|
||||||
|
alert( message ); // same as above
|
||||||
```
|
```
|
||||||
|
|
||||||
We can also declare multiple variables in one line:
|
We can also declare multiple variables in one line:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
let user = 'John', age = 25, message = 'Hello';
|
let user = 'John', age = 25, message = 'Hello';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -59,14 +58,13 @@ That might seem shorter, but it's recommended, for the sake of beter readability
|
||||||
|
|
||||||
The rewritten code is a bit longer, but easier to read:
|
The rewritten code is a bit longer, but easier to read:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
let user = 'John';
|
let user = 'John';
|
||||||
let age = 25;
|
let age = 25;
|
||||||
let message = 'Hello';
|
let message = 'Hello';
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="`var` instead of `let`"]
|
````smart header="`var` instead of `let`"
|
||||||
In older scripts you may also find another keyword: `var` instead of `let`:
|
In older scripts you may also find another keyword: `var` instead of `let`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -75,8 +73,8 @@ In older scripts you may also find another keyword: `var` instead of `let`:
|
||||||
|
|
||||||
The `var` keyword is *almost* the same as `let`. It also declares a variable, but in a slightly different, "old-school" fashion.
|
The `var` keyword is *almost* the same as `let`. It also declares a variable, but in a slightly different, "old-school" fashion.
|
||||||
|
|
||||||
The subtle differences does not matter for us yet. We'll cover them in detail later when going deeper into the language.
|
The subtle differences does not matter for us yet. We'll cover them in detail later.
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
## Real-life analogy
|
## Real-life analogy
|
||||||
|
|
||||||
|
@ -84,14 +82,13 @@ We can easily grasp the concept of a "variable" if we imagine it as a "box" for
|
||||||
|
|
||||||
For instance, the variable `message` is a box with the value `"Hello!"` labelled `"message"`:
|
For instance, the variable `message` is a box with the value `"Hello!"` labelled `"message"`:
|
||||||
|
|
||||||
<img src="variable.png">
|

|
||||||
|
|
||||||
We can put any value into the box. And later -- we can change it.
|
We can put any value into the box (variable).
|
||||||
|
|
||||||
The value can be changed as many times as we need:
|
Also we can change it. The value can be changed as many times as we need:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let message;
|
let message;
|
||||||
|
|
||||||
message = 'Hello!';
|
message = 'Hello!';
|
||||||
|
@ -103,18 +100,17 @@ alert( message );
|
||||||
|
|
||||||
When the value is changed, the old data is removed from the variable:
|
When the value is changed, the old data is removed from the variable:
|
||||||
|
|
||||||
<img src="variable-change.png">
|

|
||||||
|
|
||||||
We can also declare two variables and copy the data from one into the other.
|
We can also declare two variables and copy the data from one into the other.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let hello = 'Hello world!';
|
let hello = 'Hello world!';
|
||||||
|
|
||||||
let message;
|
let message;
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
// copy value
|
// copy 'Hello world' into message
|
||||||
message = hello;
|
message = hello;
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
|
@ -123,22 +119,20 @@ alert( hello ); // Hello world!
|
||||||
alert( message ); // Hello world!
|
alert( message ); // Hello world!
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart]
|
```smart header="Functional languages"
|
||||||
It may be interesting to know that there also exist [functional](http://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) programming languages that forbid to change a variable value. For example, [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/).
|
It may be interesting to know that there also exist [functional](http://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) programming languages that forbid to change a variable value. For example, [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/).
|
||||||
|
|
||||||
In such languages, once the value is in the box -- it's there forever. If we need to store something else -- please create a new box (declare a new variable), can't reuse the old one.
|
In such languages, once the value is "in the box" -- it's there forever. If we need to store something else -- the language forces to create a new box (declare a new variable), we can't reuse the old one.
|
||||||
|
|
||||||
Though it may seem a little bit odd at the first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation infers certain benefits. Studying of such a language (even if you're not planning to use it soon) is recommended to broaden the mind.
|
Though it may seem a little bit odd at the first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation infers certain benefits. Studying of such a language (even if you're not planning to use it soon) is recommended to broaden one's mind.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
## Variable naming [#variable-naming]
|
## Variable naming [#variable-naming]
|
||||||
|
|
||||||
There are two limitations for the variable name in JavaScript:
|
There are two limitations for the variable name in JavaScript:
|
||||||
|
|
||||||
<ol>
|
1. The name must contain only letters, digits, symbols `$` and `_`.
|
||||||
<li>The name must contain only letters, digits, symbols `$` and `_`.</li>
|
2. The first character must not be a digit.
|
||||||
<li>The first character must not be a digit.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
Valid names, for instance:
|
Valid names, for instance:
|
||||||
|
|
||||||
|
@ -153,8 +147,7 @@ What's interesting -- the dollar sign `'$'` and the underscore `'_'` are conside
|
||||||
|
|
||||||
These names are valid:
|
These names are valid:
|
||||||
|
|
||||||
```js
|
```js run untrusted
|
||||||
//+ run untrusted
|
|
||||||
let $ = 1; // declared a variable with the name "$"
|
let $ = 1; // declared a variable with the name "$"
|
||||||
let _ = 2; // and now the variable with the name "_"
|
let _ = 2; // and now the variable with the name "_"
|
||||||
|
|
||||||
|
@ -163,50 +156,45 @@ alert( $ + _ ); // 3
|
||||||
|
|
||||||
Examples of incorrect variable names:
|
Examples of incorrect variable names:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
let 1a; // cannot start with a digit
|
let 1a; // cannot start with a digit
|
||||||
|
|
||||||
let my-name; // a hyphen '-' is not allowed in the name
|
let my-name; // a hyphen '-' is not allowed in the name
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="Case matters"]
|
```smart header="Case matters"
|
||||||
Variables named `apple` and `AppLE` -- are two different variables.
|
Variables named `apple` and `AppLE` -- are two different variables.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
[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:
|
It is possible to use any language, including cyrillic letters or even hieroglyphs, like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let имя = 123;
|
let имя = '...';
|
||||||
let 我 = 456;
|
let 我 = '...';
|
||||||
```
|
```
|
||||||
|
|
||||||
Technically, there is no error here, but there is an international tradition to use english words in variable names. Even if you're writing a small script, it may have a long life ahead. People coming with another language background may need to read it some time.
|
Technically, there is no error here, such names are allowed, but there is an international tradition to use English in variable names. Even if we're writing a small script, it may have a long life ahead. People coming with another language background may need to read it some time.
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
[warn header="Reserved names"]
|
````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, which cannot be used as variable names, because they are used by the language itself.
|
||||||
|
|
||||||
For example, words `let`, `class`, `return`, `function` are reserved.
|
For example, words `let`, `class`, `return`, `function` are reserved.
|
||||||
|
|
||||||
The code below will give a syntax error:
|
The code below will give a syntax error:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
let let = 5; // can't name a variable "let", error!
|
let let = 5; // can't name a variable "let", error!
|
||||||
let return = 5; // also can't name it "return", error!
|
let return = 5; // also can't name it "return", error!
|
||||||
```
|
```
|
||||||
[/warn]
|
````
|
||||||
|
|
||||||
|
|
||||||
## Non-Strict mode assignment
|
## Non-Strict mode assignment
|
||||||
|
|
||||||
Without strict mode, it is possible to create a variable without a `let`, by a mere assignment of the value:
|
Without strict mode, it is possible to create a variable without a `let`, by a mere assignment of the value:
|
||||||
|
|
||||||
```js
|
```js run no-strict
|
||||||
//+ run no-strict
|
|
||||||
num = 5; // the variable "num" is created if didn't exist
|
num = 5; // the variable "num" is created if didn't exist
|
||||||
|
|
||||||
alert(num);
|
alert(num);
|
||||||
|
@ -216,8 +204,7 @@ alert(num);
|
||||||
|
|
||||||
The code with `"use strict"` will give an error:
|
The code with `"use strict"` will give an error:
|
||||||
|
|
||||||
```js
|
```js run untrusted
|
||||||
//+ run untrusted
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
@ -225,32 +212,14 @@ num = 5; // error: num is not defined
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="Ensure that 'use strict' is at the top"]
|
|
||||||
Please make sure that `"use strict"` is on the top of the script, otherwise the strict mode may not be enabled.
|
|
||||||
|
|
||||||
There is no strict mode here:
|
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run untrusted no-strict
|
|
||||||
alert("some code");
|
|
||||||
// "use strict" below is ignored, must be not on the top
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
*!*
|
|
||||||
num = 5; // No error! strict mode is not activated
|
|
||||||
*/!*
|
|
||||||
```
|
|
||||||
Only comments may appear in the script before `"use strict"`, they are not counted.
|
|
||||||
[/smart]
|
|
||||||
|
|
||||||
## V8 needs "use strict" for "let"
|
## V8 needs "use strict" for "let"
|
||||||
|
|
||||||
In Chrome browser, Opera and Node.JS, powered by V8 engine, `"use strict"` is required if we want to use `let` and many other modern features of the language.
|
In Chrome browser, Opera and Node.JS, powered by V8 engine, `"use strict"` is required if we want to use `let` and many other modern features of the language.
|
||||||
|
|
||||||
Here, in the tutorial, there's a code which executes examples, and it auto-adds `"use strict"` most of time (except those rare cases which are described in the text as "without use strict").
|
Here in the tutorial most examples are executed in the strict mode (except rare cases which are described in the text as "without use strict").
|
||||||
|
|
||||||
But when you write JS, make sure that you do not forget `"use strict"`. Otherwise using `let` in V8 will give you an error.
|
But when you write JS, make sure that you do not forget `"use strict"`. Otherwise V8 will remind you about it by giving an error on `let`.
|
||||||
|
|
||||||
## Constants
|
## Constants
|
||||||
|
|
||||||
|
@ -258,24 +227,32 @@ Variables with a fixed value are called "constant variables" or just *constants*
|
||||||
|
|
||||||
To declare a constant variable, one can use `const`:
|
To declare a constant variable, one can use `const`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
const myBirthday = '18.04.1982';
|
const myBirthday = '18.04.1982';
|
||||||
|
|
||||||
myBirthday = '01.01.2001'; // error!
|
myBirthday = '01.01.2001'; // error, can't reassign the constant!
|
||||||
```
|
```
|
||||||
|
|
||||||
A constant variable never changes, so the further code can rely on that to calculate dependant values. For example, the age or a sign of the zodiac.
|
A constant variable never changes, so the further code can rely on that to calculate dependant values. For example, the age or a sign of the zodiac.
|
||||||
|
|
||||||
We can be sure that the calculated variables always hold a valid value, because `myBirthday` is not going to change.
|
```js run
|
||||||
|
const myBirthday = '18.04.1982';
|
||||||
|
|
||||||
[smart header="CONSTANT_NAMING"]
|
// do some calculations to get the age
|
||||||
There is a widespread practice to use constants as aliases for difficult-to-remember and hard-coded prior to execution values. Such constants are named using capitals and underscores.
|
const age = calculateAgeBasedOn(myBirthday);
|
||||||
|
```
|
||||||
|
|
||||||
|
Surely, the `age` is constant too. And it always corresponds to `myBirthday`, both constants are not going to change.
|
||||||
|
|
||||||
|
### Uppercases constants
|
||||||
|
|
||||||
|
There is a widespread practice to use constants as aliases for difficult-to-remember and hard-coded prior to execution values.
|
||||||
|
|
||||||
|
Such constants are named using capitals and underscores.
|
||||||
|
|
||||||
Like this:
|
Like this:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
const COLOR_RED = "#F00";
|
const COLOR_RED = "#F00";
|
||||||
const COLOR_GREEN = "#0F0";
|
const COLOR_GREEN = "#0F0";
|
||||||
const COLOR_BLUE = "#00F";
|
const COLOR_BLUE = "#00F";
|
||||||
|
@ -285,18 +262,22 @@ let color = COLOR_ORANGE;
|
||||||
alert( color ); // #FF7F00
|
alert( color ); // #FF7F00
|
||||||
```
|
```
|
||||||
|
|
||||||
`COLOR_ORANGE` is much easier to understand and remember than `"#FF7F00"`. Also it is much easier to make a typo in `"#FF7F00"` than in `COLOR_ORANGE`. Finally, that makes the code more readable.
|
`COLOR_ORANGE` is much easier to understand and remember than `"#FF7F00"`. Also it is much easier to make a typo in `"#FF7F00"` than in `COLOR_ORANGE`.
|
||||||
[/smart]
|
|
||||||
|
Such uppercased name is only used for constants that are "hard-coded" (written in the code before its execution).
|
||||||
|
|
||||||
|
An example of the opposite is a constant which value is calculated basing on a webpage content or a user input.
|
||||||
|
|
||||||
|
|
||||||
## Name things right
|
## Name things right
|
||||||
|
|
||||||
And there's one more thing.
|
We're almost done with the initial understanding of variables, but there's one more thing.
|
||||||
|
|
||||||
Please name the variables sensibly.
|
Please name the variables sensibly.
|
||||||
|
|
||||||
Variable naming is one of the most important and complex skills in programming. Just looking at variable names can obviously show which code is written by a beginner and which by an experienced guru.
|
Variable naming is one of the most important and complex skills in programming. Just looking at variable names can obviously show which code is written by a beginner and which by an experienced guru.
|
||||||
|
|
||||||
In the real project, most of time is spent on modifying and extending the existing code, rather than writing something completely torn-off and new.
|
In the real project, most of time is spent on modifying and extending the existing code, rather than writing something completely torn-off of the current base.
|
||||||
|
|
||||||
And when we return to the code after some time of absence, it's much easier to find the information that is well-labelled. Or, in other words, when the variables are named right.
|
And when we return to the code after some time of absence, it's much easier to find the information that is well-labelled. Or, in other words, when the variables are named right.
|
||||||
|
|
||||||
|
@ -304,33 +285,31 @@ Please spend some time thinking about the right name for a variable before decla
|
||||||
|
|
||||||
Few good-to-follow rules are:
|
Few good-to-follow rules are:
|
||||||
|
|
||||||
<ul>
|
- Use human-readable names like `userName` or `shoppingCart`.
|
||||||
<li>Use human-readable names like `userName` or `shoppingCart` instead of abbreviations or short names `a`, `b`, `c`.</li>
|
- Stay away from abbreviations or short names `a`, `b`, `c`, unless you really know what you're doing.
|
||||||
<li>Make the name maximally descriptive and concise. Examples of bad names are `data` and `value`. Any variable stores a "data" or a "value" after all. So such name says nothing. It is only ok to use them if it's exceptionally obvious which data or value is meant.</li>
|
- Make the name maximally descriptive and concise. Examples of bad names are `data` and `value`. Any variable stores a "data" or a "value" after all. So such name says nothing. It is only ok to use them if it's exceptionally obvious which data or value is meant.
|
||||||
<li>Agree on terms within the team and in your own mind. If a site visitor is called a "user" then we should name variables like `currentUser` or `newUser`, but not `currentVisitor` or a `newManInTown`.</li>
|
- Agree on terms within the team and in your own mind. If a site visitor is called a "user" then we should name variables like `currentUser` or `newUser`, but not `currentVisitor` or a `newManInTown`.
|
||||||
</ul>
|
|
||||||
|
|
||||||
Sounds simple? In fact it is. Creating best descriptive-and-concise names isn't. Go hard for it.
|
Sounds simple? Indeed it is. But creating good descriptive-and-concise names in practice is not. Go for it.
|
||||||
|
|
||||||
[smart header="Reuse or create?"]
|
```smart header="Reuse or create?"
|
||||||
There are some lazy programmers who instead of declaring a new variable, tend to reuse the existing one.
|
And the last piece of advice. There are some lazy programmers who instead of declaring a new variable, tend to reuse the existing one.
|
||||||
|
|
||||||
As the result, the variable is like a box where people throw different things without changing the sticker. What is inside it now? Who knows... We need to come closer and check.
|
As the result, the variable is like a box where people throw different things without changing the sticker. What is inside it now? Who knows... We need to come closer and check.
|
||||||
|
|
||||||
Such a programmer saves a little bit on variable declaration, but looses ten times more on debugging the code.
|
Such a programmer saves a little bit on variable declaration, but looses ten times more on debugging the code.
|
||||||
|
|
||||||
An extra variable is good, not evil.
|
An extra variable is good, not evil.
|
||||||
[/smart]
|
|
||||||
|
|
||||||
|
P.S. Modern JavaScript minifiers and browsers optimize code well enough so that won't create a performance issue.
|
||||||
|
```
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
We can declare variables to store data. That can be done using `var` or `let` or `const`.
|
We can declare variables to store data. That can be done using `var` or `let` or `const`.
|
||||||
|
|
||||||
<ul>
|
- `let` -- is a modern variable declaration. The code must be in strict mode to use `let` in Chrome (V8).
|
||||||
<li>`let` -- is a modern variable declaration. The code must be in strict mode to use `let` in Chrome (V8).</li>
|
- `var` -- is an old-school variable declaration. We'll study the subtle differences from `let` later.
|
||||||
<li>`var` -- is an old-school variable declaration. We'll study the subtle differences from `let` later, after we get familiar with the basics.</li>
|
- `const` -- is like `let`, but the variable can't be changed.
|
||||||
<li>`const` -- is like `let`, but the variable can't be changed.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Variables should be named in a way that allows to easily understand what's inside.
|
Variables should be named in a way that allows to easily understand what's inside.
|
|
@ -15,31 +15,31 @@ n = 12.345;
|
||||||
|
|
||||||
A *number* type serves both for integer and floating point numbers.
|
A *number* type serves both for integer and floating point numbers.
|
||||||
|
|
||||||
Besides numbers there are special "numeric values" which belong to that type: `Infinity`, `-Infinity` and `NaN`.
|
Besides regular numbers there are so-called "special numeric values" which also belong to that type: `Infinity`, `-Infinity` and `NaN`.
|
||||||
|
|
||||||
<ul>
|
- `Infinity` represents the mathematical [Infinity](https://en.wikipedia.org/wiki/Infinity). It is a value that's greater than any number.
|
||||||
<li>`Infinity` is meant to represent the mathematical [Infinity](https://en.wikipedia.org/wiki/Infinity).
|
|
||||||
|
|
||||||
We can get it as a result of division by zero:
|
We can get it as a result of division by zero:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
alert( 1 / 0 ); // Infinity
|
||||||
alert( 1 / 0 ); // Infinity
|
alert( -1 / 0 ); // -Infinity
|
||||||
alert( -1 / 0 ); // -Infinity
|
```
|
||||||
```
|
|
||||||
</li>
|
|
||||||
<li>`NaN` represents a computational error. It is a result of an incorrect or an undefined mathematical operation, for instance:
|
|
||||||
|
|
||||||
```js
|
Also we can use it directly:
|
||||||
//+ run
|
|
||||||
alert( "not a number" * 2 ); // NaN
|
```js run
|
||||||
```
|
alert( Infinity > 123456789 ); // true
|
||||||
</li>
|
```
|
||||||
</ul>
|
- `NaN` represents a computational error. It is a result of an incorrect or an undefined mathematical operation, for instance:
|
||||||
|
|
||||||
|
```js run
|
||||||
|
alert( "not a number" * 2 ); // NaN
|
||||||
|
```
|
||||||
|
|
||||||
These values formally belong to the "number" type. Of course they are not numbers in a common sense of this word.
|
These values formally belong to the "number" type. Of course they are not numbers in a common sense of this word.
|
||||||
|
|
||||||
We'll cover working with numbers in the chapter [](/number).
|
We'll see more into working with numbers in the chapter <info:number>.
|
||||||
|
|
||||||
## A string
|
## A string
|
||||||
|
|
||||||
|
@ -51,31 +51,33 @@ let phrase = `can embed ${str}`;
|
||||||
|
|
||||||
In JavaScript, there are 3 types of quotes.
|
In JavaScript, there are 3 types of quotes.
|
||||||
|
|
||||||
<ol>
|
1. Double quotes: `"Hello"`.
|
||||||
<li>Double quotes: `"Hello"`.</li>
|
2. Single quotes: `'Hello'`.
|
||||||
<li>Single quotes: `'Hello'`.</li>
|
3. Backtricks: <code>`Hello`</code>.
|
||||||
<li>Backtricks: <code>`Hello`</code>.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
Double and single quotes are essentially the same.
|
Double and single quotes are essentially the same.
|
||||||
|
|
||||||
Backtricks are "extended functionality" quotes. They allow to embed variables and expressions into a string by wrapping them in `${…}`, for example:
|
Backtricks are "extended functionality" quotes. They allow to embed variables and expressions into a string by wrapping them in `${…}`, for example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let name = "John";
|
let name = "John";
|
||||||
|
|
||||||
|
// embed variable
|
||||||
alert( `Hello, ${name}!` ); // Hello, John!
|
alert( `Hello, ${name}!` ); // Hello, John!
|
||||||
|
|
||||||
|
// embed expression
|
||||||
|
alert( `the result is ${1 + 2}` ); // the result is 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The expression inside `${…}` is evaluated and the result becomes a part of the string.
|
||||||
|
|
||||||
[smart header="There is no *character* type."]
|
```smart header="There is no *character* type."
|
||||||
In some languages, there is a special "character" type for a single character. For example, in the C language it is `char`.
|
In some languages, there is a special "character" type for a single character. For example, in the C language it is `char`.
|
||||||
|
|
||||||
In JavaScript, there is only one type: `string`.
|
In JavaScript, there is no such type. There's only one type `string` for both a single character and long texts.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
We'll cover strings more thoroughly in the chapter [](/string).
|
We'll cover strings more thoroughly in the chapter <info:string>.
|
||||||
|
|
||||||
## A boolean (logical)
|
## A boolean (logical)
|
||||||
|
|
||||||
|
@ -85,16 +87,14 @@ This type is commonly used to store the yes/no values.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
let checked = true; // the form field is checked
|
let checked = true; // the form field is checked
|
||||||
checked = false; // the form field is not checked
|
checked = false; // the form field is not checked
|
||||||
```
|
```
|
||||||
|
|
||||||
Boolean values also come as the result of comparisons:
|
Boolean values also come as the result of comparisons:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let isGreater = 4 > 1;
|
let isGreater = 4 > 1;
|
||||||
alert(isGreater); // true
|
alert(isGreater); // true
|
||||||
```
|
```
|
||||||
|
@ -125,17 +125,17 @@ The sense of `undefined` is "value is not assigned".
|
||||||
|
|
||||||
If a variable is declared, but not assigned, then its value is exactly `undefined`:
|
If a variable is declared, but not assigned, then its value is exactly `undefined`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let x;
|
let x;
|
||||||
|
|
||||||
alert( x ); // shows "undefined"
|
alert( x ); // shows "undefined"
|
||||||
```
|
```
|
||||||
|
|
||||||
Technically, it is possible to assign to `undefined`:
|
Technically, it is possible to assign to `undefined`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let x = 123;
|
let x = 123;
|
||||||
|
|
||||||
x = undefined;
|
x = undefined;
|
||||||
|
|
||||||
alert( x ); // "undefined"
|
alert( x ); // "undefined"
|
||||||
|
@ -145,15 +145,71 @@ alert( x ); // "undefined"
|
||||||
|
|
||||||
Normally, we use `null` to write an "empty" or an "unknown" value into the variable, and `undefined` is only used for checks, to see if the variable is assigned or similar.
|
Normally, we use `null` to write an "empty" or an "unknown" value into the variable, and `undefined` is only used for checks, to see if the variable is assigned or similar.
|
||||||
|
|
||||||
|
## Object type
|
||||||
|
|
||||||
|
The `object` type is special.
|
||||||
|
|
||||||
|
All other types are called "primitive", because their values can contain only a single thing (be it a string or a number or whatever).
|
||||||
|
|
||||||
|
In contrast, objects are used to store *collections* of various data and more complex entities.
|
||||||
|
|
||||||
|
An object is defined with the figure brackets `{…}`.
|
||||||
|
|
||||||
|
For instance, here we create a `user` object with the name and the age:
|
||||||
|
|
||||||
|
```js
|
||||||
|
let user = {
|
||||||
|
name: "John",
|
||||||
|
age: 30
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Now `user` is a complex entity, can be imagine of a shelf with two folders labelled "name" and "age".
|
||||||
|
|
||||||
|
We can access either via the dot notation:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// get parts of the object:
|
||||||
|
alert( user.name ); // John
|
||||||
|
alert( user.age ); // 30
|
||||||
|
```
|
||||||
|
|
||||||
|
Also we can add new information to the user and remove it any time:
|
||||||
|
|
||||||
|
```js
|
||||||
|
user.isAdmin = true;
|
||||||
|
delete user.age;
|
||||||
|
```
|
||||||
|
|
||||||
|
Objects in JavaScript are very powerful. This topic is so huge. We'll be closely working with objects since the chapter <info:object> and continue studying them in following parts of the tutorial.
|
||||||
|
|
||||||
|
## Symbol type
|
||||||
|
|
||||||
|
The `symbol` type stands apart from the others. Symbols are rarely used. Probably we won't need them any time soon, but it's the 7th and the last type of the language. So we must mention it for the sake of completeness.
|
||||||
|
|
||||||
|
Type "symbol" represents an unique identifier.
|
||||||
|
|
||||||
|
A value of this type can be created like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
let id = Symbol("id");
|
||||||
|
```
|
||||||
|
|
||||||
|
Symbols are used in advanced operations with objects. As of now, it's enough to understand that JavaScript symbols is a separate primitive type used for identifiers.
|
||||||
|
|
||||||
|
Symbols in JavaScript are different from symbols in Ruby language (if you are familiar with it, please don't get trapped by the same word). We'll get back to them after in-depth study of objects.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## The typeof operator [#type-typeof]
|
## The typeof operator [#type-typeof]
|
||||||
|
|
||||||
The `typeof` operator returns the type of the argument.
|
The `typeof` operator returns the type of the argument.
|
||||||
|
|
||||||
It allows two forms of syntax:
|
It allows two forms of syntax:
|
||||||
<ol>
|
|
||||||
<li>As an operator: `typeof x`.</li>
|
1. As an operator: `typeof x`.
|
||||||
<li>Function style: `typeof(x)`.</li>
|
2. Function style: `typeof(x)`.
|
||||||
</ol>
|
|
||||||
|
|
||||||
In other words, it works both with the brackets or without them. They result is the same.
|
In other words, it works both with the brackets or without them. They result is the same.
|
||||||
|
|
||||||
|
@ -177,16 +233,15 @@ typeof null // "object" (1)
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
typeof function(){} // "function" (2)
|
typeof alert // "function" (2)
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note the last two lines, because `typeof` behaves specially there.
|
Please note the last two lines, because `typeof` behaves specially there.
|
||||||
|
|
||||||
<ol>
|
1. The result of `typeof null` equals to `"object"`. That is an officially recognized error in `typeof` implementation, kept for compatibility. Of course, `null` is not an object. It is a special value with a separate type of its own.
|
||||||
<li>The result of `typeof null` equals to `"object"`. That is an officially recognized error in the language that is kept for compatibility. In fact, `null` is not an object, but a special value from a data type of its own.</li>
|
2. The result of `typeof alert` is `"function"`, because `alert` is a function of the language. We'll study more functions in near future. Formally, there is no special type for functions, but `typeof` makes them look different. That's very convenient in practice.
|
||||||
<li>Functions are yet to be covered. As of now let's just note that functions do not make a separate type, instead they are a special kind of objects in JavaScript. But `typeof` treats them separately returning `"function"`. That's actually just fine and very convenient in practice.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
## Type conversions
|
## Type conversions
|
||||||
|
|
||||||
|
@ -198,17 +253,15 @@ let message = "hello";
|
||||||
message = 123456;
|
message = 123456;
|
||||||
```
|
```
|
||||||
|
|
||||||
But sometimes we need to convert a value of one type to another. That is mostly useful because each type has it's own features. So we are really going to benefit from storing a number as a number, not a string with it.
|
...But sometimes we need to convert a value from one type to another. That is useful because each type has it's own features. So we are really going to benefit from storing a number as a number, not a string with it.
|
||||||
|
|
||||||
There are many type conversions in JavaScript, fully listed in [the specification](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-type-conversion).
|
There are many type conversions in JavaScript, fully listed in [the specification](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-type-conversion).
|
||||||
|
|
||||||
Three conversions that happen the most often are:
|
Three conversions that happen most often are:
|
||||||
|
|
||||||
<ol>
|
1. String conversion.
|
||||||
<li>String conversion.</li>
|
2. Numeric conversion.
|
||||||
<li>Numeric conversion.</li>
|
3. Boolean conversion.
|
||||||
<li>Boolean conversion.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
### String conversion
|
### String conversion
|
||||||
|
|
||||||
|
@ -216,8 +269,7 @@ The string conversion happens when we need a string form of a value.
|
||||||
|
|
||||||
For example, `alert` does it:
|
For example, `alert` does it:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = true;
|
let a = true;
|
||||||
|
|
||||||
alert( a ); // "true"
|
alert( a ); // "true"
|
||||||
|
@ -225,15 +277,14 @@ alert( a ); // "true"
|
||||||
|
|
||||||
We can also use a call `String(value)` function for that:
|
We can also use a call `String(value)` function for that:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = true;
|
let a = true;
|
||||||
|
|
||||||
a = String(a); // now: a = "true"
|
a = String(a); // now: a = "true"
|
||||||
alert(typeof a); // string
|
alert(typeof a); // string
|
||||||
```
|
```
|
||||||
|
|
||||||
The string conversion is the most obvious. A `false` becomes `"false"`, `null` becomes `"null"` etc.
|
The string conversion is obvious. A `false` becomes `"false"`, `null` becomes `"null"` etc.
|
||||||
|
|
||||||
### Numeric conversion
|
### Numeric conversion
|
||||||
|
|
||||||
|
@ -241,136 +292,79 @@ Numeric conversion happens in mathematical functions and expressions automatical
|
||||||
|
|
||||||
For example, a mathematical operation like division '/' can be applied to non-numbers:
|
For example, a mathematical operation like division '/' can be applied to non-numbers:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( "6" / "2" ); // 3, strings become numbers
|
alert( "6" / "2" ); // 3, strings become numbers
|
||||||
```
|
```
|
||||||
|
|
||||||
If we want to ensure that a value is a number, we can use a `Number(value)` function to do it explicitly:
|
We can use a `Number(value)` function to convert any `value` to a number:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let str = "123";
|
||||||
let n = Number("6");
|
alert(typeof str); // string
|
||||||
|
|
||||||
|
let n = Number(str); // becomes a number 123
|
||||||
|
|
||||||
alert(typeof n); // number
|
alert(typeof n); // number
|
||||||
```
|
```
|
||||||
|
|
||||||
It's handy when there is a value comes from a text form field, or another source which is string-bsed.
|
The conversion is usually applied when we have a numeric value coming from a text form field or another string-based source.
|
||||||
|
|
||||||
If the string is not a number, the result of such conversion is `NaN`, for instance:
|
If the string is not a number, the result of such conversion is `NaN`, for instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let age = Number("an arbitrary string instead of a number");
|
||||||
let age = Number("a user-supplied string");
|
|
||||||
|
|
||||||
alert(age); // NaN, conversion failed
|
alert(age); // NaN, conversion failed
|
||||||
alert(typeof age); // number, because NaN belongs to the "number" type
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The rules of transformation:
|
The numeric conversion rules:
|
||||||
|
|
||||||
<table>
|
| Value | Becomes... |
|
||||||
<thead>
|
|-------|-------------|
|
||||||
<tr><th>Value</th><th>Becomes...</th></tr>
|
|`undefined`|`NaN`|
|
||||||
</thead>
|
|`null`|`0`|
|
||||||
<tbody>
|
|<code>true / false</code> | `1 / 0` |
|
||||||
<tr><td>`undefined`</td><td>`NaN`</td></tr>
|
| A string | Whitespaces from the start and the end are cut off. Then, if the remaining string is empty, the result is `0`, otherwise – the value is "read" from the string. An error gives `NaN`. |
|
||||||
<tr><td>`null`</td><td>`0`</td></tr>
|
|
||||||
<tr style="white-space:nowrap"><td>`true / false`</td><td>`1 / 0`</td></tr>
|
|
||||||
<tr><td>A string</td><td>Whitespaces from the start and the end are cut off.<br>Then, if the remaining string is empty, the result is `0`, otherwise -- the value is "read" from the string. An error gives `NaN`.</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
Other examples:
|
Examples:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( Number(" 123 ") ); // 123
|
alert( Number(" 123 ") ); // 123
|
||||||
alert( Number("123z") ); // NaN (error reading a number at "z")
|
alert( Number("123z") ); // NaN (error reading a number at "z")
|
||||||
alert( Number(true) ); // 1
|
alert( Number(true) ); // 1
|
||||||
alert( Number(false) ); // 0
|
alert( Number(false) ); // 0
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note that `null` and `undefined` are similar in many aspects, but here they are not. A `null` becomes a zero, but `undefined` becomes `NaN`.
|
Please note that `null` and `undefined` behave differently here. A `null` becomes a zero, but `undefined` becomes `NaN`.
|
||||||
|
|
||||||
### Boolean conversion
|
### Boolean conversion
|
||||||
|
|
||||||
Boolean conversion is happens automatically in logical operations (to be covered), but also can be performed manually with the call of `Boolean(value)`.
|
Boolean conversion is happens automatically in logical operations (to be covered), but also can be performed manually with the call of `Boolean(value)`.
|
||||||
|
|
||||||
The conversion rule is simple here:
|
The conversion rules are simple here:
|
||||||
<ul>
|
|
||||||
<li>All values that are intuitively "empty" become `false`. These are: `0`, an empty string, `null`, `undefined` and `NaN`.</li>
|
|
||||||
<li>Other values become `true`.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
[warn header="Please note: a string `\"0\"` is `true`"]
|
- All values that are intuitively "empty" become `false`. These are: `0`, an empty string, `null`, `undefined` and `NaN`.
|
||||||
|
- Other values become `true`.
|
||||||
|
|
||||||
|
````warn header="Please note: a string `\"0\"` is `true`"
|
||||||
Some languages (namely PHP) treat `"0"` as `false`. But in JavaScript a non-empty string is always `false`, no matter what is in it.
|
Some languages (namely PHP) treat `"0"` as `false`. But in JavaScript a non-empty string is always `false`, no matter what is in it.
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( Boolean("0") ); // true
|
alert( Boolean("0") ); // true
|
||||||
alert( Boolean(" ") ); // any non-empty string, even whitespaces are true
|
alert( Boolean(" ") ); // any non-empty string, even whitespaces are true
|
||||||
```
|
```
|
||||||
[/warn]
|
````
|
||||||
|
|
||||||
|
|
||||||
## Object and Symbol
|
|
||||||
|
|
||||||
The `object` type is special.
|
|
||||||
|
|
||||||
All other types are called "primitive", because their values can contain only a single thing (be it a string or a number or whatever).
|
|
||||||
|
|
||||||
In contrast, objects are used to store collections of various data and more complex entities.
|
|
||||||
|
|
||||||
### Object
|
|
||||||
|
|
||||||
An object is defined with the figure brackets `{…}`.
|
|
||||||
|
|
||||||
For instance, here we create a `user` object with the name and the age:
|
|
||||||
|
|
||||||
```js
|
|
||||||
let user = {
|
|
||||||
name: "John",
|
|
||||||
age: 30
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
We can access the data form the object via the dot notation:
|
|
||||||
|
|
||||||
```js
|
|
||||||
alert( user.name ); // John
|
|
||||||
alert( user.age ); // 30
|
|
||||||
```
|
|
||||||
|
|
||||||
Objects are very capable and tunable in JavaScript. This topic is huge, we'll start working with objects in the chapter [](/object) and continue studying them in other parts of the tutorial.
|
|
||||||
|
|
||||||
### Symbol
|
|
||||||
|
|
||||||
The `symbol` type is used to create unique identifiers.
|
|
||||||
|
|
||||||
```js
|
|
||||||
let id = Symbol("id");
|
|
||||||
```
|
|
||||||
|
|
||||||
...And then we could use `id` as a special kind of identifier for object properties.
|
|
||||||
|
|
||||||
We'll see more about object properties in the following chapters. As of now, let's just say that JavaScript symbols is a separate primitive type. And they are different from symbols in Ruby language (if you are familiar with it, please don't get trapped by the same word).
|
|
||||||
|
|
||||||
We list symbols here for the sake of completeness, their in-depth study will follow after objects.
|
|
||||||
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
- There are 7 basic types in JavaScript. Six "primitive" types: `number`, `string`, `boolean`, `null`, `undefined`, `symbol` and an `object` type.
|
||||||
<li>There are 7 basic types in JavaScript. Six "primitive" types: `number`, `string`, `boolean`, `null`, `undefined`, `symbol` and `object`.</li>
|
- The `typeof` operator allows to see which type is stored in the variable, but note that it mistakingly returns `"object"` for `null`.
|
||||||
<li>The `typeof` operator allows to see which type is stored in the variable, but note that it mistakingly returns `"object"` for `null`.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Type conversions usually happen automatically, but there are also functions for the manual conversion:
|
Type conversions usually happen automatically, but there are also functions for the manual conversion:
|
||||||
<ul>
|
|
||||||
<li>String</li>
|
|
||||||
<li>Number</li>
|
|
||||||
<li>Boolean</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Further we'll cover each type in a separate chapter, devoted to this type only. But first let's move on to study operators and other language constructs. It will be more productive.
|
- String
|
||||||
|
- Number
|
||||||
|
- Boolean
|
||||||
|
|
||||||
|
Now let's study operators and other language constructs that actually form our code.
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
|
|
||||||
The answer is:
|
The answer is:
|
||||||
|
|
||||||
<ul>
|
- `a = 2`
|
||||||
<li>`a = 2`</li>
|
- `b = 2`
|
||||||
<li>`b = 2`</li>
|
- `c = 2`
|
||||||
<li>`c = 2`</li>
|
- `d = 1`
|
||||||
<li>`d = 1`</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
let a = 1, b = 1;
|
let a = 1, b = 1;
|
||||||
|
|
||||||
alert( ++a ); // 2, prefix form returns the new value
|
alert( ++a ); // 2, prefix form returns the new value
|
||||||
|
@ -18,3 +15,4 @@ alert( b++ ); // 1, postfix form returns the old value
|
||||||
alert( a ); // 2, incremented once
|
alert( a ); // 2, incremented once
|
||||||
alert( b ); // 2, incremented once
|
alert( b ); // 2, incremented once
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# The postfix and prefix forms
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# The postfix and prefix forms
|
||||||
|
|
||||||
What are the final values of all variables in the code below?
|
What are the final values of all variables in the code below?
|
||||||
|
|
||||||
|
@ -11,4 +13,3 @@ let c = ++a; // ?
|
||||||
let d = b++; // ?
|
let d = b++; // ?
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
The answer is:
|
The answer is:
|
||||||
<ul>
|
|
||||||
<li>`a = 4` (multiplied by 2)</li>
|
- `a = 4` (multiplied by 2)
|
||||||
<li>`x = 5` (calculated as 1 + 4)</li>
|
- `x = 5` (calculated as 1 + 4)
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Assignment result
|
importance: 3
|
||||||
|
|
||||||
[importance 3]
|
---
|
||||||
|
|
||||||
|
# Assignment result
|
||||||
|
|
||||||
What will be values of `a` and `x` in the example below?
|
What will be values of `a` and `x` in the example below?
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
|
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
"" + 1 + 0 = "10" // (1)
|
"" + 1 + 0 = "10" // (1)
|
||||||
"" - 1 + 0 = -1 // (2)
|
"" - 1 + 0 = -1 // (2)
|
||||||
true + false = 1
|
true + false = 1
|
||||||
6 / "3" = 2
|
6 / "3" = 2
|
||||||
"2" * "3" = 6
|
"2" * "3" = 6
|
||||||
4 + 5 + "px" = "9px"
|
4 + 5 + "px" = "9px"
|
||||||
"$" + 4 + 5
= "$45"
|
"$" + 4 + 5 = "$45"
|
||||||
"4" - 2
= 2
|
"4" - 2 = 2
|
||||||
"4px" - 2
= NaN
|
"4px" - 2 = NaN
|
||||||
7 / 0
= Infinity
|
7 / 0 = Infinity
|
||||||
" -9\n" + 5 = " -9\n5"
|
" -9\n" + 5 = " -9\n5"
|
||||||
" -9\n" - 5 = -14
|
" -9\n" - 5 = -14
|
||||||
null + 1 = 1 // (3)
|
null + 1 = 1 // (3)
|
||||||
undefined + 1 = NaN // (4)
|
undefined + 1 = NaN // (4)
|
||||||
```
|
```
|
||||||
|
|
||||||
<ol>
|
1. The plus `"+"` operator in this case first converts `1` to a string: `"" + 1 = "1"`, and then adds `0`.
|
||||||
<li>The plus `"+"` operator in this case first converts `1` to a string: `"" + 1 = "1"`, and then adds `0`.</li>
|
2. The minus `"-"` operator only works with numbers, it converts an empty string `""` to zero immediately.
|
||||||
<li>The minus `"-"` operator only works with numbers, it converts an empty string `""` to zero immediately.</li>
|
3. `null` becomes `0` after the numeric conversion.
|
||||||
<li>`null` becomes `0` after the numeric conversion.</li>
|
4. `undefined` becomes `NaN` after the numeric conversion.
|
||||||
<li>`undefined` becomes `NaN` after the numeric conversion.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
|
@ -1,23 +1,24 @@
|
||||||
# Type conversions
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Type conversions
|
||||||
|
|
||||||
Let's recap type conversions in the context of operators.
|
Let's recap type conversions in the context of operators.
|
||||||
|
|
||||||
What will be the result for these expressions?
|
What will be the result for these expressions?
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
"" + 1 + 0
|
"" + 1 + 0
|
||||||
"" - 1 + 0
|
"" - 1 + 0
|
||||||
true + false
|
true + false
|
||||||
6 / "3"
|
6 / "3"
|
||||||
"2" * "3"
|
2" * "3"
|
||||||
4 + 5 + "px"
|
4 + 5 + "px"
|
||||||
"$" + 4 + 5
|
$" + 4 + 5
|
||||||
"4" - 2
|
"4" - 2
|
||||||
"4px" - 2
|
"4px" - 2
|
||||||
7 / 0
|
7 / 0
|
||||||
" -9\n" + 5
|
" -9\n" + 5
|
||||||
" -9\n" - 5
|
" -9\n" - 5
|
||||||
null + 1
|
null + 1
|
||||||
|
|
|
@ -3,39 +3,32 @@
|
||||||
Many operators are known to us from the school program. It is an addition `+`, a multiplication `*`, a substraction `-` and so on.
|
Many operators are known to us from the school program. It is an addition `+`, a multiplication `*`, a substraction `-` and so on.
|
||||||
|
|
||||||
In this chapter we concentrate on aspects that are not covered by the school arithmetic.
|
In this chapter we concentrate on aspects that are not covered by the school arithmetic.
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## Terms: "unary", "binary", "operand"
|
## Terms: "unary", "binary", "operand"
|
||||||
|
|
||||||
Before we move on, let's make a dip in the common terminology, used in the development.
|
Before we move on, let's make a dip in the common terminology, used in the development.
|
||||||
|
|
||||||
<ul>
|
- *An operand* -- is what operators are applied to. For instance in multiplication `5 * 2` there are two operands: the left operand is `5`, and the right operand is `2`. Another word is "an argument of an operator".
|
||||||
<li>*An operand* -- is what operators are applied to. For instance in multiplication `5 * 2` there are two operands: the left operand is `5`, and the right operand is `2`. Another word is "an argument of an operator".</li>
|
- An operator is called *unary* if it has a single operand. For example, the unary minus `"-"` reverses the sign of the number:
|
||||||
<li>An operator is called *unary* if it has a single operand. For example, the unary minus `"-"` reverses the sign of the number:
|
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let x = 1;
|
||||||
let x = 1;
|
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
x = -x;
|
x = -x;
|
||||||
*/!*
|
*/!*
|
||||||
alert( x ); // -1, unary minus was applied
|
alert( x ); // -1, unary minus was applied
|
||||||
```
|
```
|
||||||
|
- An operator is called *binary* if it has two operands. The same minus exists in the binary form as well:
|
||||||
|
|
||||||
</li>
|
```js run no-beautify
|
||||||
<li>An operator is called *binary* if it has two operands. The same minus exists in the binary form as well:
|
let x = 1, y = 3;
|
||||||
|
alert( y - x ); // 2, binary minus
|
||||||
```js
|
```
|
||||||
//+ run no-beautify
|
|
||||||
let x = 1, y = 3;
|
|
||||||
alert( y - x ); // 2, binary minus
|
|
||||||
```
|
|
||||||
|
|
||||||
Formally, we're talking about the two different operators here: the unary minus (single operand, reverses the sign) and the binary minus (two operands, substracts).
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
Formally, we're talking about the two different operators here: the unary minus (single operand, reverses the sign) and the binary minus (two operands, substracts).
|
||||||
|
|
||||||
## Strings concatenation, binary +
|
## Strings concatenation, binary +
|
||||||
|
|
||||||
|
@ -52,8 +45,7 @@ If one of operands of `+` is a string, then the other one is converted to string
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( '1' + 2 ); // "12"
|
alert( '1' + 2 ); // "12"
|
||||||
alert( 2 + '1' ); // "21"
|
alert( 2 + '1' ); // "21"
|
||||||
```
|
```
|
||||||
|
@ -64,22 +56,20 @@ The string concatenation and conversion is the special feature of the binary plu
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 2 - '1' ); // 1
|
alert( 2 - '1' ); // 1
|
||||||
alert( 6 / '2' ); // 3
|
alert( 6 / '2' ); // 3
|
||||||
```
|
```
|
||||||
|
|
||||||
## Numeric conversion, unary +
|
## Numeric conversion, unary +
|
||||||
|
|
||||||
The plus `+` exist in two forms. The binary form that we've just seen above and the unary form.
|
The plus `+` exist in two forms. The binary form that we used above and the unary form.
|
||||||
|
|
||||||
The unary plus or, in other words, the plus `+` applied to a single value, doesn't do anything with numbers, but if the operand is not a number, then it is converted into it.
|
The unary plus or, in other words, the plus `+` applied to a single value, doesn't do anything with numbers, but if the operand is not a number, then it is converted into it.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
// No effect on numbers
|
// No effect on numbers
|
||||||
let x = 1;
|
let x = 1;
|
||||||
alert( +x ); // 1
|
alert( +x ); // 1
|
||||||
|
@ -92,14 +82,15 @@ alert( +true ); // 1
|
||||||
alert( +"" ); // 0
|
alert( +"" ); // 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
It actually does the same as `Number()`, but it's shorter.
|
||||||
|
|
||||||
As an example of use, let's imagine that we are getting values from HTML-form fields. Then they are usually strings.
|
As an example of use, let's imagine that we are getting values from HTML-form fields. Then they are usually strings.
|
||||||
|
|
||||||
What if we want to sum them?
|
What if we want to sum them?
|
||||||
|
|
||||||
The binary plus would add them as strings:
|
The binary plus would add them as strings:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let apples = "2";
|
let apples = "2";
|
||||||
let oranges = "3";
|
let oranges = "3";
|
||||||
|
|
||||||
|
@ -108,53 +99,48 @@ alert( apples + oranges ); // "23", the binary plus concatenates strings
|
||||||
|
|
||||||
If we want to treat them as numbers, then we can convert and then sum:
|
If we want to treat them as numbers, then we can convert and then sum:
|
||||||
|
|
||||||
|
```js run
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
let apples = "2";
|
let apples = "2";
|
||||||
let oranges = "3";
|
let oranges = "3";
|
||||||
|
|
||||||
alert( Number(apples) + Number(oranges) ); // 5
|
alert( Number(apples) + Number(oranges) ); // 5
|
||||||
|
|
||||||
|
// or the shorter variant:
|
||||||
|
*!*
|
||||||
|
alert( +apples + +oranges ); // 5
|
||||||
|
// both values converted to numbers before the binary plus
|
||||||
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
The conversion can also be done with the unary plus:
|
From a mathematician's standpoint the abundance of pluses may seem strange. But from a programmer's standpoint -- there's nothing special: unary pluses are applied first, they convert strings to numbers, and then the binary plus sums them up.
|
||||||
|
|
||||||
```js
|
Why did unary pluses are applied to values before the binary one? As we're going to see, that's because of their *higher precedence*.
|
||||||
//+ run
|
|
||||||
let apples = "2";
|
|
||||||
let oranges = "3";
|
|
||||||
|
|
||||||
alert( +apples + +oranges ); // 5, both operands converted to numbers before the binary plus
|
|
||||||
```
|
|
||||||
|
|
||||||
From a mathematician's standpoint the abundance of pluses may seem strange. But from a programmer's -- there's nothing special: unary pluses are applied first, they convert strings to numbers, and then the binary plus sums them up.
|
|
||||||
|
|
||||||
Why did unary pluses work before the binary one? As we're going to see, that's because of their *precedence*.
|
|
||||||
|
|
||||||
## Operators precedence
|
## Operators precedence
|
||||||
|
|
||||||
If an expression has more than one operator, the execution order is defined by their *precedence*.
|
If an expression has more than one operator, the execution order is defined by their *precedence*, that is an implicit order among the operators.
|
||||||
|
|
||||||
From the school we all know that the multiplication in the expression `1 + 2 * 2` should be calculated before the addition. That's exactly the precedence thing. The multiplication has *a higher precedence* than the addition.
|
From the school we all know that the multiplication in the expression `1 + 2 * 2` should be calculated before the addition. That's exactly the precedence thing. The multiplication is said to have *a higher precedence* than the addition.
|
||||||
|
|
||||||
Brackets override any precedence, so if we're not satisfied with the order, we can use them like `(1 + 2) * 2`.
|
Brackets override any precedence, so if we're not satisfied with the order, we can use them, like: `(1 + 2) * 2`.
|
||||||
|
|
||||||
There are many operators in JavaScript. For clarity and internal needs there exists a [precedence table](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence). Every operator has a corresponding precedence number. The one with the bigger number executes first. If the precedence is same -- the execution order is from left to right.
|
There are many operators in JavaScript. For clarity and internal needs there exists a [precedence table](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence). Every operator has a corresponding precedence number. The one with the bigger number executes first. If the precedence is same -- the execution order is from left to right.
|
||||||
|
|
||||||
An extract from the table:
|
An extract from the table:
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr><td>...</td><td>...</td><td>...</td></tr>
|
| Precedence | Name | Sign |
|
||||||
<tr><td>15</td><td>unary plus</td><td>`+`</td></tr>
|
|------------|------|------|
|
||||||
<tr><td>15</td><td>unary minus</td><td>`-`</td></tr>
|
| ... | ... | ... |
|
||||||
<tr><td>14</td><td>multiplication</td><td>`*`</td></tr>
|
| 15 | unary plus | `+` |
|
||||||
<tr><td>14</td><td>division</td><td>`/`</td></tr>
|
| 15 | unary minus | `-` |
|
||||||
<tr><td>13</td><td>addition</td><td>`+`</td></tr>
|
| 14 | multiplication | `*` |
|
||||||
<tr><td>13</td><td>substraction</td><td>`-`</td></tr>
|
| 14 | division | `/` |
|
||||||
<tr><td>...</td><td>...</td><td>...</td></tr>
|
| 13 | addition (binary) | `+` |
|
||||||
<tr><td>3</td><td>assignment</td><td>`=`</td></tr>
|
| 13 | substraction | `-` |
|
||||||
<tr><td>...</td><td>...</td><td>...</td></tr>
|
| ... | ... | ... |
|
||||||
</table>
|
| 3 | assignment | `=` |
|
||||||
|
| ... | ... | ... |
|
||||||
|
|
||||||
As we can see, the "unary plus" has a priority of `15`, higher than `13` for the ordinary "addition". That's why in the expression `+apples + +oranges` unary pluses worked first, and then the addition.
|
As we can see, the "unary plus" has a priority of `15`, higher than `13` for the ordinary "addition". That's why in the expression `+apples + +oranges` unary pluses worked first, and then the addition.
|
||||||
|
|
||||||
|
@ -162,7 +148,7 @@ As we can see, the "unary plus" has a priority of `15`, higher than `13` for the
|
||||||
|
|
||||||
Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `3`.
|
Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `3`.
|
||||||
|
|
||||||
That's why when we assign a variable, like `x = 2 * 2 + 1`, the maths is done first, and then the assignment is evaluated.
|
That's why when we assign a variable, like `x = 2 * 2 + 1`, then the calculations are done first, and afterwards the `=` is evaluated, storing the result in `x`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let x = 2 * 2 + 1;
|
let x = 2 * 2 + 1;
|
||||||
|
@ -172,8 +158,7 @@ alert( x ); // 5
|
||||||
|
|
||||||
It is possible to chain assignments:
|
It is possible to chain assignments:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a, b, c;
|
let a, b, c;
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
@ -187,15 +172,14 @@ alert( c ); // 4
|
||||||
|
|
||||||
The assignments chain is evaluated from right to left: the rightmost expression `2+2` is calculated first, assigned to `c`, then `b = c` works, thus assigning it to `b`, and then `a = b`. At the end, all variables share a single value.
|
The assignments chain is evaluated from right to left: the rightmost expression `2+2` is calculated first, assigned to `c`, then `b = c` works, thus assigning it to `b`, and then `a = b`. At the end, all variables share a single value.
|
||||||
|
|
||||||
[smart header="The assignment operator `\"=\"` returns a value"]
|
````smart header="The assignment operator `\"=\"` returns a value"
|
||||||
An operator always returns a value. The assignment is not an exception.
|
An operator always returns a value. That's obvious for `+` and `*`. But the assignment follows that rule too.
|
||||||
|
|
||||||
The call `x = value` writes the `value` into `x` and then returns it.
|
The call `x = value` writes the `value` into `x` *and then returns it*.
|
||||||
|
|
||||||
So it is actually possible to use an assignment as the part of a more complex expression:
|
So it is actually possible to use an assignment as the part of a more complex expression:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = 1;
|
let a = 1;
|
||||||
let b = 2;
|
let b = 2;
|
||||||
|
|
||||||
|
@ -210,7 +194,7 @@ alert( c ); // 0
|
||||||
In the example above, the result of `(a = b + 1)` is the value which is assigned to `a` (that is `3`). It is then used to substract from `3`.
|
In the example above, the result of `(a = b + 1)` is the value which is assigned to `a` (that is `3`). It is then used to substract from `3`.
|
||||||
|
|
||||||
Funny code, isn't it? We should understand how it works, but don't write anything like that ourselves. Such tricks definitely don't make the code neater and more readable.
|
Funny code, isn't it? We should understand how it works, but don't write anything like that ourselves. Such tricks definitely don't make the code neater and more readable.
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
## Remainder %
|
## Remainder %
|
||||||
|
|
||||||
|
@ -220,8 +204,7 @@ The result of `a % b` is the remainder of the integer division of `a` by `b`.
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 5 % 2 ); // 1 is a remainder of 5 divided by 2
|
alert( 5 % 2 ); // 1 is a remainder of 5 divided by 2
|
||||||
alert( 8 % 3 ); // 2 is a remainder of 8 divided by 3
|
alert( 8 % 3 ); // 2 is a remainder of 8 divided by 3
|
||||||
alert( 6 % 3 ); // 0 is a remainder of 6 divided by 3
|
alert( 6 % 3 ); // 0 is a remainder of 6 divided by 3
|
||||||
|
@ -233,36 +216,28 @@ Increasing or decreasing a number by one is among the most common numerical oper
|
||||||
|
|
||||||
So, there are special operators for that:
|
So, there are special operators for that:
|
||||||
|
|
||||||
<ul>
|
- **Increment** `++` increases a variable by 1:
|
||||||
<li>**Increment** `++` increases a variable by 1:
|
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
let counter = 2;
|
||||||
let i = 2;
|
counter++; // works same as counter = counter + 1, but shorter
|
||||||
i++; // works same as i = i + 1, but shorter
|
alert( counter ); // 3
|
||||||
alert(i); // 3
|
```
|
||||||
```
|
- **Decrement** `--` decreases a variable by 1:
|
||||||
|
|
||||||
</li>
|
```js run no-beautify
|
||||||
<li>**Decrement** `--` decreases a variable by 1:
|
let counter = 2;
|
||||||
|
counter--; // works same as counter = counter - 1, but shorter
|
||||||
|
alert( counter ); // 1
|
||||||
|
```
|
||||||
|
|
||||||
```js
|
```warn
|
||||||
//+ run no-beautify
|
|
||||||
let i = 2;
|
|
||||||
i--; // works same as i = i - 1, but shorter
|
|
||||||
alert(i); // 1
|
|
||||||
```
|
|
||||||
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
[warn]
|
|
||||||
Increment/decrement can be applied only to a variable. An attempt to use it on a value like `5++` will give an error.
|
Increment/decrement can be applied only to a variable. An attempt to use it on a value like `5++` will give an error.
|
||||||
[/warn]
|
```
|
||||||
|
|
||||||
Operators `++` and `--` can be put both after and before the variable.
|
Operators `++` and `--` can be put both after and before the variable.
|
||||||
|
|
||||||
When the operator goes after the variable, it is called a "postfix form": `i++`. The "prefix form" is when the operator stands before the variable: `++i`.
|
When the operator goes after the variable, it is called a "postfix form": `counter++`. The "prefix form" is when the operator stands before the variable: `++counter`.
|
||||||
|
|
||||||
Both of these records do the same: increase `i` by `1`.
|
Both of these records do the same: increase `i` by `1`.
|
||||||
|
|
||||||
|
@ -272,95 +247,78 @@ As we know, all operators return a value. Increment/decrement is not an exceptio
|
||||||
|
|
||||||
Let's see the examples:
|
Let's see the examples:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let counter = 1;
|
||||||
let i = 1;
|
let a = ++counter; // (*)
|
||||||
let a = ++i; // (*)
|
|
||||||
|
|
||||||
alert(a); // *!*2*/!*
|
alert(a); // *!*2*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
Here in the line `(*)` the prefix call `++i` increments `i` and returns the new value that is `2`. So the `alert` shows `2`.
|
Here in the line `(*)` the prefix call `++counter` increments `i` and returns the new value that is `2`. So the `alert` shows `2`.
|
||||||
|
|
||||||
Now let's use the postfix form:
|
Now let's use the postfix form:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let counter = 1;
|
||||||
let i = 1;
|
let a = counter++; // (*) changed ++counter to counter++
|
||||||
let a = i++; // (*) changed ++i to i++
|
|
||||||
|
|
||||||
alert(a); // *!*1*/!*
|
alert(a); // *!*1*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
In the line `(*)` the *postfix* form `i++` also increments `i`, but returns the *old* value (prior to increment). So the `alert` shows `1`.
|
In the line `(*)` the *postfix* form `counter++` also increments `i`, but returns the *old* value (prior to increment). So the `alert` shows `1`.
|
||||||
|
|
||||||
To summarize:
|
To summarize:
|
||||||
<ul>
|
|
||||||
<li>If the result of increment/decrement is not used, then there is no difference which form to use:
|
|
||||||
|
|
||||||
```js
|
- If the result of increment/decrement is not used, then there is no difference which form to use:
|
||||||
//+ run
|
|
||||||
let i = 0;
|
|
||||||
i++;
|
|
||||||
++i;
|
|
||||||
alert( i ); // 2, the lines above did the same
|
|
||||||
```
|
|
||||||
|
|
||||||
</li>
|
```js run
|
||||||
<li>If we'd like to use the result of the operator right now, then we need the prefix form:
|
let counter = 0;
|
||||||
|
counter++;
|
||||||
|
++counter;
|
||||||
|
alert( counter ); // 2, the lines above did the same
|
||||||
|
```
|
||||||
|
- If we'd like to use the result of the operator right now, then we need the prefix form:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let counter = 0;
|
||||||
let i = 0;
|
alert( ++counter ); // 1
|
||||||
alert( ++i ); // 1
|
```
|
||||||
```
|
- If we'd like to increment, but use the previous value, then we need the postfix form:
|
||||||
|
|
||||||
</li>
|
```js run
|
||||||
<li>If we'd like to increment, but use the previous value, then we need the postfix form:
|
let counter = 0;
|
||||||
|
alert( counter++ ); // 0
|
||||||
|
```
|
||||||
|
|
||||||
```js
|
````smart header="Increment/decrement among other operators"
|
||||||
//+ run
|
Operators `++/--` can be used inside an expression as well. Their priority is higher than most other arithmetical operations.
|
||||||
let i = 0;
|
|
||||||
alert( i++ ); // 0
|
|
||||||
```
|
|
||||||
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
[smart header="Increment/decrement among other operators"]
|
|
||||||
Operators `++/--` usually stand alone. But they can be used inside an expression as well.
|
|
||||||
|
|
||||||
Their priority is higher than most other arithmetical operations.
|
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let counter = 1;
|
||||||
let i = 1;
|
alert( 2 * ++counter ); // 4
|
||||||
alert( 2 * ++i ); // 4
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Compare with:
|
Compare with:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let counter = 1;
|
||||||
let i = 1;
|
alert( 2 * counter++ ); // 2, because counter++ returns the "old" value
|
||||||
alert( 2 * i++ ); // 2, because i++ returns the pre-increment value
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Though technically allowable, such notation usually makes the code less readable. One line does multiple things -- not good.
|
Though technically allowable, such notation usually makes the code less readable. One line does multiple things -- not good.
|
||||||
|
|
||||||
During a fast "vertical" eye-scanning of the code it's easy to miss such `i++`, and it would be not obvious that the variable increases.
|
While reading the code, a fast "vertical" eye-scan can easily miss such `counter++`, and it won't be obvious that the variable increases.
|
||||||
|
|
||||||
Three lines: one line -- one action is advised:
|
The "one line -- one action" style is advised:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
let counter = 1;
|
||||||
let i = 1;
|
alert( 2 * counter );
|
||||||
alert( 2 * i );
|
counter++;
|
||||||
i++;
|
|
||||||
```
|
```
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
## Bitwise operators
|
## Bitwise operators
|
||||||
|
|
||||||
|
@ -370,17 +328,15 @@ These operators are not JavaScript-specific. They are supported in most programm
|
||||||
|
|
||||||
The list of operators:
|
The list of operators:
|
||||||
|
|
||||||
<ul>
|
- AND ( `&` )
|
||||||
<li>AND ( `&` )</li>
|
- OR ( `|` )
|
||||||
<li>OR ( `|` )</li>
|
- XOR ( `^` )
|
||||||
<li>XOR ( `^` )</li>
|
- NOT ( `~` )
|
||||||
<li>NOT ( `~` )</li>
|
- LEFT SHIFT ( `<<` )
|
||||||
<li>LEFT SHIFT ( `<<` )</li>
|
- RIGHT SHIFT ( `>>` )
|
||||||
<li>RIGHT SHIFT ( `>>` )</li>
|
- ZERO-FILL RIGHT SHIFT ( `>>>` )
|
||||||
<li>ZERO-FILL RIGHT SHIFT ( `>>>` )</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
These operators are used quite rarely. Their study implies the knowledge of low-level number representation, and it would be suboptimal to delve into that now. If a reader wants to learn them right now, they are explained in the [Bitwise Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) article in MDN. But it would be more practical to return to this topic later when a need arises.
|
These operators are used very rarely. To understand them, we should delve into the low-level number representation, and it would be suboptimal to do that now. Especially because we won't need them any time soon. A curious reader may read the [Bitwise Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) article in MDN. But it would be more practical to return to this topic later when a real need arises.
|
||||||
|
|
||||||
## Modify-in-place
|
## Modify-in-place
|
||||||
|
|
||||||
|
@ -396,8 +352,7 @@ n = n * 2;
|
||||||
|
|
||||||
This notation can be shortened using operators `+=` and *=`:
|
This notation can be shortened using operators `+=` and *=`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let n = 2;
|
let n = 2;
|
||||||
n += 5; // now n=7 (same as n = n + 5)
|
n += 5; // now n=7 (same as n = n + 5)
|
||||||
n *= 2; // now n=14 (same as n = n * 2)
|
n *= 2; // now n=14 (same as n = n * 2)
|
||||||
|
@ -409,15 +364,13 @@ Short "modify-and-assign" operators exist for `+,-,*,/` and bitwise `<<,>>,>>>,&
|
||||||
|
|
||||||
The modify-and-assign call has the same precedence as a normal assignment, so it executes after most other calculations:
|
The modify-and-assign call has the same precedence as a normal assignment, so it executes after most other calculations:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let n = 2;
|
let n = 2;
|
||||||
n *= 3 + 5;
|
n *= 3 + 5;
|
||||||
|
|
||||||
alert( n ); // 16 (n = 2 * 8)
|
alert( n ); // 16 (same as n *= 8)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Comma
|
## Comma
|
||||||
|
|
||||||
The comma operator `','` is one of most rare and unusual ones. Sometimes it's used to write shorter code, so we need to know it in order understand what's going on.
|
The comma operator `','` is one of most rare and unusual ones. Sometimes it's used to write shorter code, so we need to know it in order understand what's going on.
|
||||||
|
@ -426,8 +379,7 @@ The comma operator allows to evaluate several expressions, dividing them with a
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
*!*
|
*!*
|
||||||
a = (1+2, 3+4);
|
a = (1+2, 3+4);
|
||||||
*/!*
|
*/!*
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
|
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
5 > 4 → true
|
5 > 4 → true
|
||||||
"apple" > "pineapple" → false
|
"apple" > "pineapple" → false
|
||||||
"2" > "12" → true // (1)
|
"2" > "12" → true
|
||||||
undefined == null → true // (2)
|
undefined == null → true
|
||||||
undefined === null → false // (3)
|
undefined === null → false
|
||||||
null == "\n0\n" → false // (4)
|
null == "\n0\n" → false
|
||||||
|
null === +"\n0\n" → false
|
||||||
```
|
```
|
||||||
|
|
||||||
Some of the reasons:
|
Some of the reasons:
|
||||||
|
|
||||||
<ol>
|
1. Obviously, true.
|
||||||
<li>The string `"2"` is indeed greater than `"12"`, because strings are compared character-by-character. The first character of `"2"` is greater than the first character of `"12"` (that is `"1"`).</li>
|
2. Dictionary comparison, hence true.
|
||||||
<li>Values `null` and `undefined` equal each other only.</li>
|
3. Again, dictionary comparison, first char of `"2"` is greater than the first char of `"1"`.
|
||||||
<li>Strict equality is strict. Different types from both sides lead to false.</li>
|
4. Values `null` and `undefined` equal each other only.
|
||||||
<li>See (2) for the reason.</li>
|
5. Strict equality is strict. Different types from both sides lead to false.
|
||||||
</ol>
|
6. See (4).
|
||||||
|
7. Strict equality of different types.
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# Comparisons
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Comparisons
|
||||||
|
|
||||||
What will be the result for expressions?
|
What will be the result for expressions?
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
5 > 4
|
5 > 4
|
||||||
"apple" > "pineapple"
|
"apple" > "pineapple"
|
||||||
"2" > "12"
|
"2" > "12"
|
||||||
|
|
|
@ -2,12 +2,10 @@
|
||||||
|
|
||||||
Many comparison operators we know from the maths:
|
Many comparison operators we know from the maths:
|
||||||
|
|
||||||
<ul>
|
- Greater/less than: <code>a > b</code>, <code>a < b</code>.
|
||||||
<li>Greater/less than: <code>a > b</code>, <code>a < b</code>.</li>
|
- Greater/less than or equals: <code>a >= b</code>, <code>a <= b</code>.
|
||||||
<li>Greater/less than or equals: <code>a >= b</code>, <code>a <= b</code>.</li>
|
- Equality check is written as `a == b` (please note the double equation sign `'='`. A single symbol `a = b` would mean an assignment).
|
||||||
<li>Equality check is written as `a == b` (please note the double equation sign `'='`. A single symbol `a = b` would mean an assignment).</li>
|
- Not equals. In maths the sign is <code>≠</code>, in JavaScript we use an assignment with an exclamation before it: <code>a != b</code>.
|
||||||
<li>Not equals. In maths the sign is <code>≠</code>, in JavaScript we use an assignment with an exclamation before it: <code>a != b</code>.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
|
@ -15,15 +13,12 @@ Many comparison operators we know from the maths:
|
||||||
|
|
||||||
Just as all other operators, a comparison returns a value. The value is of the boolean type.
|
Just as all other operators, a comparison returns a value. The value is of the boolean type.
|
||||||
|
|
||||||
<ul>
|
- `true` -- means "yes", "correct" or "the truth".
|
||||||
<li>`true` -- means "yes", "correct" or "the truth".</li>
|
- `false` -- means "no", "wrong" or "a lie".
|
||||||
<li>`false` -- means "no", "wrong" or "a lie".</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 2 > 1 ); // true (correct)
|
alert( 2 > 1 ); // true (correct)
|
||||||
alert( 2 == 1 ); // false (wrong)
|
alert( 2 == 1 ); // false (wrong)
|
||||||
alert( 2 != 1 ); // true (correct)
|
alert( 2 != 1 ); // true (correct)
|
||||||
|
@ -31,8 +26,7 @@ alert( 2 != 1 ); // true (correct)
|
||||||
|
|
||||||
A result of a comparison can be assigned to a variable, just like any value:
|
A result of a comparison can be assigned to a variable, just like any value:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let result = 5 > 4; // assign the result of the comparison
|
let result = 5 > 4; // assign the result of the comparison
|
||||||
alert( result ); // true
|
alert( result ); // true
|
||||||
```
|
```
|
||||||
|
@ -45,70 +39,61 @@ In other words, strings are compared letter-by-letter.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 'Z' > 'A' ); // true
|
alert( 'Z' > 'A' ); // true
|
||||||
alert( 'Glow' > 'Glee' ); // true
|
alert( 'Glow' > 'Glee' ); // true
|
||||||
alert( 'Bee' > 'Be' ); // true
|
alert( 'Bee' > 'Be' ); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
The algorithm to compare two strings is simple:
|
The algorithm to compare two strings is simple:
|
||||||
<ol>
|
|
||||||
<li>Compare the first characters of both strings.</li>
|
1. Compare the first characters of both strings.
|
||||||
<li>If the first one is greater(or less), then the first string is greater(or less) than the second and we're done.</li>
|
2. If the first one is greater(or less), then the first string is greater(or less) than the second and we're done.
|
||||||
<li>Otherwise if first characters are equal, compare the second characters the same way.</li>
|
3. Otherwise if first characters are equal, compare the second characters the same way.
|
||||||
<li>Repeat until the end of any string.</li>
|
4. Repeat until the end of any string.
|
||||||
<li>If both strings ended simultaneously, then they are equal. Otherwise the longer string is greater.</li>
|
5. If both strings ended simultaneously, then they are equal. Otherwise the longer string is greater.
|
||||||
</ol>
|
|
||||||
|
|
||||||
In the example above, the comparison `'Z' > 'A'` gets the result at the first step.
|
In the example above, the comparison `'Z' > 'A'` gets the result at the first step.
|
||||||
|
|
||||||
Strings `"Glow"` and `"Glee"` are compared character-by-character:
|
Strings `"Glow"` and `"Glee"` are compared character-by-character:
|
||||||
<ol>
|
|
||||||
<li>`G` is the same as `G`.</li>
|
|
||||||
<li>`l` is the same as `l`.</li>
|
|
||||||
<li>`o` is greater than `e`. Stop here. The first string is greater.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
[smart header="Not a real dictionary"]
|
1. `G` is the same as `G`.
|
||||||
The strings "dictionary" comparison algorithm given above is roughly equivalent to the one used in book dictionaries or phone books. But it's not exactly the same.
|
2. `l` is the same as `l`.
|
||||||
|
3. `o` is greater than `e`. Stop here. The first string is greater.
|
||||||
|
|
||||||
For instance, the case matters. A capital letter `"A"` is not equal to the lowercase `"a"`. Which one is greater? It is defined by a character's index in the internal encoding (Unicode) table. We'll get back to specific details and consequences in the chapter [](/strings).
|
```smart header="Not a real dictionary"
|
||||||
[/smart]
|
The comparison algorithm given above is roughly equivalent to the one used in book dictionaries or phone books. But it's not exactly the same.
|
||||||
|
|
||||||
|
For instance, the case matters. A capital letter `"A"` is not equal to the lowercase `"a"`. Which one is greater? Actually, the lowercase `"a"` is. Why? Because the lowercase character has a greater index in the internal encoding table (Unicode). We'll get back to specific details and consequences in the chapter <info:string>.
|
||||||
|
```
|
||||||
|
|
||||||
## Comparison of different types
|
## Comparison of different types
|
||||||
|
|
||||||
When compared values are of different types, they get autoconverted to numbers.
|
When compared values belong to different types, they get autoconverted to numbers.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( '2' > 1 ); // true, string '2' becomes a number 2
|
alert( '2' > 1 ); // true, string '2' becomes a number 2
|
||||||
alert( '01' == 1 ); // true, string '01' becomes a number 1
|
alert( '01' == 1 ); // true, string '01' becomes a number 1
|
||||||
```
|
```
|
||||||
|
|
||||||
For boolean values, `true` becomes `1` and `false` becomes `0`, that's why:
|
For boolean values, `true` becomes `1` and `false` becomes `0`, that's why:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( true == 1 ); // true
|
alert( true == 1 ); // true
|
||||||
alert( false == 0 ); // true
|
alert( false == 0 ); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
[smart header="A funny consequence"]
|
````smart header="A funny consequence"
|
||||||
|
|
||||||
It is possible that in the same time:
|
It is possible that in the same time:
|
||||||
<ul>
|
|
||||||
<li>Two values are equal.</li>
|
- Two values are equal.
|
||||||
<li>One of them is `true` as a boolean and the other one is `false` as a boolean.</li>
|
- One of them is `true` as a boolean and the other one is `false` as a boolean.
|
||||||
</ul>
|
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
let a = 0;
|
let a = 0;
|
||||||
alert( Boolean(a) ); // false
|
alert( Boolean(a) ); // false
|
||||||
|
|
||||||
|
@ -119,23 +104,19 @@ alert(a == b); // true!
|
||||||
```
|
```
|
||||||
|
|
||||||
From JavaScript standpoint that's quite normal. An equality check converts using the numeric conversion (hence `"0"` becomes `0`), while `Boolean` conversion uses another set of rules.
|
From JavaScript standpoint that's quite normal. An equality check converts using the numeric conversion (hence `"0"` becomes `0`), while `Boolean` conversion uses another set of rules.
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Strict equality
|
## Strict equality
|
||||||
|
|
||||||
A regular equality check `==` has a "problem": it cannot differ `0` from `false`:
|
A regular equality check `"=="` has a problem. It cannot differ `0` from `false`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 0 == false ); // true
|
alert( 0 == false ); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
The same thing with an empty string:
|
The same thing with an empty string:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( '' == false ); // true
|
alert( '' == false ); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -145,12 +126,11 @@ What to do if we'd like to differentiate `0` from `false`?
|
||||||
|
|
||||||
**A strict equality operator `===` checks the equality without type conversion.**
|
**A strict equality operator `===` checks the equality without type conversion.**
|
||||||
|
|
||||||
In other words, `a === b` immediately returns `false` if `a` and `b` belong to different types. Without attempting to use numeric conversion as `==` would do.
|
In other words, `a === b` immediately returns `false` if `a` and `b` belong to different types. Without attempting to convert them.
|
||||||
|
|
||||||
Let's try it:
|
Let's try it:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 0 === false ); // false, because the types are different
|
alert( 0 === false ); // false, because the types are different
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -160,41 +140,31 @@ The string equality check is a bit longer to write, but it's more obvious what's
|
||||||
|
|
||||||
## Comparison with null and undefined
|
## Comparison with null and undefined
|
||||||
|
|
||||||
|
Let's see more corner cases.
|
||||||
|
|
||||||
There's a non-intuitive behavior when `null` or `undefined` is compared with other values.
|
There's a non-intuitive behavior when `null` or `undefined` is compared with other values.
|
||||||
|
|
||||||
For a strict equality check `===` the result is simple: `null` and `undefined` belong to different types of their own. So `null === null` and no other value. The similar thing is true for `undefined`.
|
- There's a special rule when testing the equality `null == undefined`. These two are a "sweet couple. They equal (in the sense of `==`) each other, but no one else.
|
||||||
|
|
||||||
But what for `null > 0` or `null == undefined`? The trap is that `null/undefined` may feel like `false` or a zero in this case. But it is not so.
|
- For a strict equality check `===` these values are different, because each of them belong to a separate type of it's own.
|
||||||
|
|
||||||
<ol>
|
- For evaluation of other comparisons including `<`, `>`, `<=`, `>=`, these values are converted to a number. We surely remember that `null` becomes `0`, while `undefined` becomes `NaN`.
|
||||||
<li>For an equality check `==` there's a simple rule. Values `null` and `undefined` are equal `==` to each other and non-equal to any other value.</li>
|
|
||||||
<li>For other non-strict comparisons a numeric conversion is involved. After it `null` becomes `0`, while `undefined` becomes `NaN`.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
Let's see few notable examples.
|
Now let's see funny things that happen when we apply those rules.
|
||||||
|
|
||||||
### Strange result: null vs 0
|
### Strange result: null vs 0
|
||||||
|
|
||||||
Let's compare `null` with a zero:
|
Let's compare `null` with a zero:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( null > 0 ); // false
|
alert( null > 0 ); // false
|
||||||
alert( null == 0 ); // false
|
alert( null == 0 ); // false
|
||||||
|
alert( null >= 0 ); // *!*true*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
Okay, from the code above we may decide that `null` is not greater and not equal to zero.
|
Yeah, mathematically that's strange. The last result states that "`null` is equal or greater than zero", and the former comparisons contradict it.
|
||||||
|
|
||||||
But...
|
The reason is that an equality check `==` and comparisons `> < >= <=` work differently. Comparisons convert `null` to a number, hence treat it as `0`. That's why `null >= 0` is true and `null > 0` is false.
|
||||||
|
|
||||||
```js
|
|
||||||
//+ run
|
|
||||||
alert(null >= 0); // *!*true*/!*
|
|
||||||
```
|
|
||||||
|
|
||||||
How can that be possible? If `null` is "not greater than zero and not equal to zero" then how `null >= 0` can be true?
|
|
||||||
|
|
||||||
Yeah, mathematically that's strange. But the reason is that an equality check `==` and comparisons `> < >= <=` work differently. Comparisons convert `null` to a number, hence treat it as `0`. That's why `null >= 0` is true and `null > 0` is false.
|
|
||||||
|
|
||||||
From the other hand, equality has a rule that a "sweet couple" `undefined` and `null` match each other and no other value.
|
From the other hand, equality has a rule that a "sweet couple" `undefined` and `null` match each other and no other value.
|
||||||
|
|
||||||
|
@ -204,8 +174,7 @@ That's why we have a strange-looking situation above.
|
||||||
|
|
||||||
The value `undefined` shouldn't participate in comparisons at all:
|
The value `undefined` shouldn't participate in comparisons at all:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( undefined > 0 ); // false (1)
|
alert( undefined > 0 ); // false (1)
|
||||||
alert( undefined < 0 ); // false (2)
|
alert( undefined < 0 ); // false (2)
|
||||||
alert( undefined == 0 ); // false (3)
|
alert( undefined == 0 ); // false (3)
|
||||||
|
@ -214,26 +183,25 @@ alert( undefined == 0 ); // false (3)
|
||||||
Why does it dislike a zero so much? Always false!
|
Why does it dislike a zero so much? Always false!
|
||||||
|
|
||||||
We've got such result, because:
|
We've got such result, because:
|
||||||
<ul>
|
|
||||||
<li>Comparisons `(1)` and `(2)` return `false` because `undefined` gets converted to `NaN`. And `NaN` is a special numeric value which returns `false` for all comparisons.</li>
|
|
||||||
<li>The equality check `(3)` returns `false`, because `undefined` only equals `null` and no other value.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Why did we observe these examples? Should we remember these pecularities all the time? Well, they will become known and obvious over the time, but actually there's no need. Just one little conclusion is enough.
|
- Comparisons `(1)` and `(2)` return `false` because `undefined` gets converted to `NaN`. And `NaN` is a special numeric value which returns `false` for all comparisons.
|
||||||
|
- The equality check `(3)` returns `false`, because `undefined` only equals `null` and no other value.
|
||||||
|
|
||||||
**Any comparison with `undefined/null` except the strict equality `===` should be done with exceptional care.**
|
### Conclusion
|
||||||
|
|
||||||
For clarity it is preferable not to use comparisons `>= > < <=` with a variable which may be `null/undefined` at all.
|
Why did we observe these examples? Should we remember these pecularities all the time? Well,not really. Actually, these tricky things will become obvious over the time, but most of time one little conclusion is enough.
|
||||||
|
|
||||||
We can always make a separate check for `null` or add an explicit type conversion. Makes the code less bug-proof.
|
Any comparison with `undefined/null` except the strict equality `===` should be done with exceptional care.
|
||||||
|
|
||||||
|
**It is preferable not to use comparisons `>= > < <=` with a variable which may be `null/undefined`.**
|
||||||
|
|
||||||
|
We can always make a separate check for `null` or add an explicit type conversion.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<ul>
|
- Comparison operators return a logical value.
|
||||||
<li>Comparison operators return a logical value.</li>
|
- Strings are compared letter-by-letter in the "dictionary" order.
|
||||||
<li>Strings are compared letter-by-letter in the "dictionary" order.</li>
|
- When values of different types are compared, they get converted to numbers (with the exclusion of a strict equality check).
|
||||||
<li>When values of different types are compared, they get converted to numbers (with the exclusion of a strict equality check).</li>
|
- Values `null` and `undefined` equal `==` each other and do not equal any other value.
|
||||||
<li>Values `null` and `undefined` equal `==` each other and do not equal any other value.</li>
|
- Be careful when using comparisons like `>` or `<` with variables that can occasionaly be `null/undefined`. Making a separate check for `null/undefined` is a good idea.
|
||||||
<li>Be careful when using comparisons like `>` or `<` with variables that can occasionaly be `null/undefined`. Making a separate check for `null/undefined` is a good idea.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
|
@ -14,35 +14,34 @@
|
||||||
|
|
||||||
Зайдите на [страницу с примером](debugging/index.html) браузером Chrome.
|
Зайдите на [страницу с примером](debugging/index.html) браузером Chrome.
|
||||||
|
|
||||||
Откройте инструменты разработчика: [key F12] или в меню `Инструменты > Инструменты Разработчика`.
|
Откройте инструменты разработчика: `key:F12` или в меню `Инструменты > Инструменты Разработчика`.
|
||||||
|
|
||||||
Выберите сверху `Sources`.
|
Выберите сверху `Sources`.
|
||||||
|
|
||||||
<img src="chrome_sources.png">
|

|
||||||
|
|
||||||
Вы видите три зоны:
|
Вы видите три зоны:
|
||||||
|
|
||||||
<ol>
|
1. **Зона исходных файлов.** В ней находятся все подключённые к странице файлы, включая JS/CSS. Выберите `pow.js`, если он не выбран.
|
||||||
<li>**Зона исходных файлов.** В ней находятся все подключённые к странице файлы, включая JS/CSS. Выберите `pow.js`, если он не выбран.</li>
|
2. **Зона текста.** В ней находится текст файлов.
|
||||||
<li>**Зона текста.** В ней находится текст файлов.</li>
|
3. **Зона информации и контроля.** Мы поговорим о ней позже.
|
||||||
<li>**Зона информации и контроля.** Мы поговорим о ней позже.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
Обычно зона исходных файлов при отладке не нужна. Скройте её кнопкой <span class="devtools" style="background-position:-200px -76px"></span>.
|
Обычно зона исходных файлов при отладке не нужна. Скройте её кнопкой <span class="devtools" style="background-position:-200px -76px"></span>.
|
||||||
|
|
||||||
## Общие кнопки управления
|
## Общие кнопки управления
|
||||||
|
|
||||||
<img src="chrome_sources_buttons.png">
|

|
||||||
|
|
||||||
Три наиболее часто используемые кнопки управления:
|
Три наиболее часто используемые кнопки управления:
|
||||||
<dl>
|
|
||||||
<dt>Формат <span class="devtools" style="background-position:-264px 94px"></span></dt>
|
Формат <span class="devtools" style="background-position:-264px 94px"></span>
|
||||||
<dd>Нажатие форматирует текст текущего файла, расставляет отступы. Нужна, если вы хотите разобраться в чужом коде, плохо отформатированном или сжатом.</dd>
|
: Нажатие форматирует текст текущего файла, расставляет отступы. Нужна, если вы хотите разобраться в чужом коде, плохо отформатированном или сжатом.
|
||||||
<dt>Консоль <span class="devtools" style="background-position:-70px 94px"></span></dt>
|
|
||||||
<dd>Очень полезная кнопка, открывает тут же консоль для запуска команд. Можно смотреть код и тут же запускайть функции. Её нажатие можно заменить на клавишу <code class="key">Esc</code>.</dd>
|
Консоль <span class="devtools" style="background-position:-70px 94px"></span>
|
||||||
<dt>Окно <span class="devtools" style="background-position:-6px 70px"></span></dt>
|
: Очень полезная кнопка, открывает тут же консоль для запуска команд. Можно смотреть код и тут же запускайть функции. Её нажатие можно заменить на клавишу <code class="key">Esc</code>.
|
||||||
<dd>Если код очень большой, то можно вынести инструменты разработки вбок или в отдельное окно, зажав эту кнопку и выбрав соответствующий вариант из списка.</dd>
|
|
||||||
</dl>
|
Окно <span class="devtools" style="background-position:-6px 70px"></span>
|
||||||
|
: Если код очень большой, то можно вынести инструменты разработки вбок или в отдельное окно, зажав эту кнопку и выбрав соответствующий вариант из списка.
|
||||||
|
|
||||||
## Точки остановки
|
## Точки остановки
|
||||||
|
|
||||||
|
@ -52,70 +51,60 @@
|
||||||
|
|
||||||
Выглядет это должно примерно так:
|
Выглядет это должно примерно так:
|
||||||
|
|
||||||
<img src="chrome_sources_breakpoint.png">
|

|
||||||
|
|
||||||
Слово *Брейкпойнт* (breakpoint) -- часто используемый английский жаргонизм. Это то место в коде, где отладчик будет *автоматически* останавливать выполнение JavaScript, как только оно до него дойдёт.
|
Слово *Брейкпойнт* (breakpoint) -- часто используемый английский жаргонизм. Это то место в коде, где отладчик будет *автоматически* останавливать выполнение JavaScript, как только оно до него дойдёт.
|
||||||
|
|
||||||
|
|
||||||
**В остановленном коде можно посмотреть текущие значения переменных, выполнять команды и т.п., в общем -- отлаживать его.**
|
**В остановленном коде можно посмотреть текущие значения переменных, выполнять команды и т.п., в общем -- отлаживать его.**
|
||||||
|
|
||||||
Вы можете видеть, что информация о точке остановки появилась справа, в подвкладке Breakpoints.
|
Вы можете видеть, что информация о точке остановки появилась справа, в подвкладке Breakpoints.
|
||||||
|
|
||||||
Вкладка Breakpoints очень удобна, когда код большой, она позволяет:
|
Вкладка Breakpoints очень удобна, когда код большой, она позволяет:
|
||||||
|
|
||||||
<ul>
|
- Быстро перейти на место кода, где стоит брейкпойнт кликом на текст.
|
||||||
<li>Быстро перейти на место кода, где стоит брейкпойнт кликом на текст.</li>
|
- Временно выключить брейкпойнт кликом на чекбокс.
|
||||||
<li>Временно выключить брейкпойнт кликом на чекбокс.</li>
|
- Быстро удалить брейкпойнт правым кликом на текст и выбором Remove, и так далее.
|
||||||
<li>Быстро удалить брейкпойнт правым кликом на текст и выбором Remove, и так далее.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
[smart header="Дополнительные возможности"]
|
````smart header="Дополнительные возможности"
|
||||||
<ul>
|
- Остановку можно инициировать и напрямую из кода скрипта, командой `debugger`:
|
||||||
<li>Остановку можно инициировать и напрямую из кода скрипта, командой `debugger`:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function pow(x, n) {
|
function pow(x, n) {
|
||||||
...
|
...
|
||||||
debugger; // <-- отладчик остановится тут
|
debugger; // <-- отладчик остановится тут
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
- *Правый клик* на номер строки `pow.js` позволит создать условную точку остановки (conditional breakpoint), т.е. задать условие, при котором точка остановки сработает.
|
||||||
|
|
||||||
</li>
|
Это удобно, если остановка нужна только при определённом значении переменной или параметра функции.
|
||||||
<li>*Правый клик* на номер строки `pow.js` позволит создать условную точку остановки (conditional breakpoint), т.е. задать условие, при котором точка остановки сработает.
|
````
|
||||||
|
|
||||||
Это удобно, если остановка нужна только при определённом значении переменной или параметра функции.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
[/smart]
|
|
||||||
|
|
||||||
## Остановиться и осмотреться
|
## Остановиться и осмотреться
|
||||||
|
|
||||||
Наша функция выполняется сразу при загрузке страницы, так что самый простой способ активировать отладчик JavaScript -- перезагрузить её. Итак, нажимаем [key F5] (Windows, Linux) или [key Cmd+R] (Mac).
|
Наша функция выполняется сразу при загрузке страницы, так что самый простой способ активировать отладчик JavaScript -- перезагрузить её. Итак, нажимаем `key:F5` (Windows, Linux) или `key:Cmd+R` (Mac).
|
||||||
|
|
||||||
Если вы сделали всё, как описано выше, то выполнение прервётся как раз на 6й строке.
|
Если вы сделали всё, как описано выше, то выполнение прервётся как раз на 6й строке.
|
||||||
|
|
||||||
<img src="chrome_sources_break.png">
|

|
||||||
|
|
||||||
Обратите внимание на информационные вкладки справа (отмечены стрелками).
|
Обратите внимание на информационные вкладки справа (отмечены стрелками).
|
||||||
|
|
||||||
В них мы можем посмотреть текущее состояние:
|
В них мы можем посмотреть текущее состояние:
|
||||||
<ol>
|
|
||||||
<li>**`Watch Expressions` -- показывает текущие значения любых выражений.**
|
|
||||||
|
|
||||||
Можно раскрыть эту вкладку, нажать мышью `+` на ней и ввести любое выражение. Отладчик будет отображать его значение на текущий момент, автоматически перевычисляя его при проходе по коду.</li>
|
1. **`Watch Expressions` -- показывает текущие значения любых выражений.**
|
||||||
<li>**`Call Stack` -- стек вызовов, все вложенные вызовы, которые привели к текущему месту кода.**
|
|
||||||
|
|
||||||
На текущий момент видно, отладчик находится в функции `pow` (pow.js, строка 6), вызванной из анонимного кода (index.html, строка 13).</li>
|
Можно раскрыть эту вкладку, нажать мышью `+` на ней и ввести любое выражение. Отладчик будет отображать его значение на текущий момент, автоматически перевычисляя его при проходе по коду.
|
||||||
<li>**`Scope Variables` -- переменные.**
|
2. **`Call Stack` -- стек вызовов, все вложенные вызовы, которые привели к текущему месту кода.**
|
||||||
|
|
||||||
На текущий момент строка 6 ещё не выполнилась, поэтому `result` равен `undefined`.
|
На текущий момент видно, отладчик находится в функции `pow` (pow.js, строка 6), вызванной из анонимного кода (index.html, строка 13).
|
||||||
|
3. **`Scope Variables` -- переменные.**
|
||||||
|
|
||||||
В `Local` показываются переменные функции: объявленные через `var` и параметры. Вы также можете там видеть ключевое слово `this`, если вы не знаете, что это такое -- ничего страшного, мы это обсудим позже, в следующих главах учебника.
|
На текущий момент строка 6 ещё не выполнилась, поэтому `result` равен `undefined`.
|
||||||
|
|
||||||
В `Global` -- глобальные переменные и функции.
|
В `Local` показываются переменные функции: объявленные через `var` и параметры. Вы также можете там видеть ключевое слово `this`, если вы не знаете, что это такое -- ничего страшного, мы это обсудим позже, в следующих главах учебника.
|
||||||
</li>
|
|
||||||
</ol>
|
В `Global` -- глобальные переменные и функции.
|
||||||
|
|
||||||
## Управление выполнением
|
## Управление выполнением
|
||||||
|
|
||||||
|
@ -123,67 +112,61 @@ function pow(x, n) {
|
||||||
|
|
||||||
Обратим внимание на панель управления справа-сверху, в ней есть 6 кнопок:
|
Обратим внимание на панель управления справа-сверху, в ней есть 6 кнопок:
|
||||||
|
|
||||||
<dl>
|
 -- продолжить выполнение, горячая клавиша `key:F8`.
|
||||||
<dt><img style="vertical-align:middle" src="manage1.png"> -- продолжить выполнение, горячая клавиша [key F8].</dt>
|
: Продолжает выполнения скрипта с текущего момента в обычном режиме. Если скрипт не встретит новых точек остановки, то в отладчик управление больше не вернётся.
|
||||||
<dd>Продолжает выполнения скрипта с текущего момента в обычном режиме. Если скрипт не встретит новых точек остановки, то в отладчик управление больше не вернётся.
|
|
||||||
|
|
||||||
Нажмите на эту кнопку.
|
Нажмите на эту кнопку.
|
||||||
|
|
||||||
Скрипт продолжится, далее, в 6й строке находится рекурсивный вызов функции `pow`, т.е. управление перейдёт в неё опять (с другими аргументами) и сработает точка остановки, вновь включая отладчик.
|
Скрипт продолжится, далее, в 6й строке находится рекурсивный вызов функции `pow`, т.е. управление перейдёт в неё опять (с другими аргументами) и сработает точка остановки, вновь включая отладчик.
|
||||||
|
|
||||||
При этом вы увидите, что выполнение стоит на той же строке, но в `Call Stack` появился новый вызов.
|
При этом вы увидите, что выполнение стоит на той же строке, но в `Call Stack` появился новый вызов.
|
||||||
|
|
||||||
Походите по стеку вверх-вниз -- вы увидите, что действительно аргументы разные.
|
Походите по стеку вверх-вниз -- вы увидите, что действительно аргументы разные.
|
||||||
</dd>
|
|
||||||
<dt><img style="vertical-align:middle" src="manage2.png"> -- сделать шаг, не заходя внутрь функции, горячая клавиша [key F10].</dt>
|
|
||||||
<dd>Выполняет одну команду скрипта. Если в ней есть вызов функции -- то отладчик обходит его стороной, т.е. не переходит на код внутри.
|
|
||||||
|
|
||||||
Эта кнопка очень удобна, если в текущей строке вызывается функция JS-фреймворка или какая-то другая, которая нас ну совсем не интересует. Тогда выполнение продолжится дальше, без захода в эту функцию, что нам и нужно.
|
 -- сделать шаг, не заходя внутрь функции, горячая клавиша `key:F10`.
|
||||||
|
: Выполняет одну команду скрипта. Если в ней есть вызов функции -- то отладчик обходит его стороной, т.е. не переходит на код внутри.
|
||||||
|
|
||||||
Обратим внимание, в данном случае эта кнопка при нажатии всё-таки перейдёт внутрь вложенного вызова `pow`, так как внутри `pow` находится брейкпойнт, а на включённых брейкпойнтах отладчик останавливается всегда.
|
Эта кнопка очень удобна, если в текущей строке вызывается функция JS-фреймворка или какая-то другая, которая нас ну совсем не интересует. Тогда выполнение продолжится дальше, без захода в эту функцию, что нам и нужно.
|
||||||
</dd>
|
|
||||||
<dt><img style="vertical-align:middle" src="manage3.png"> -- сделать шаг, горячая клавиша [key F11].</dt>
|
|
||||||
<dd>Выполняет одну команду скрипта и переходит к следующей. Если есть вложенный вызов, то заходит внутрь функции.
|
|
||||||
|
|
||||||
Эта кнопка позволяет подробнейшим образом пройтись по очереди по командам скрипта.
|
Обратим внимание, в данном случае эта кнопка при нажатии всё-таки перейдёт внутрь вложенного вызова `pow`, так как внутри `pow` находится брейкпойнт, а на включённых брейкпойнтах отладчик останавливается всегда.
|
||||||
</dd>
|
|
||||||
<dt><img style="vertical-align:middle" src="manage4.png"> -- выполнять до выхода из текущей функции, горячая клавиша [key Shift+F11].</dt>
|
|
||||||
<dd>Выполняет команды до завершения текущей функции.
|
|
||||||
|
|
||||||
Эта кнопка очень удобна в случае, если мы нечаянно вошли во вложенный вызов, который нам не интересен -- чтобы быстро из него выйти.
|
 -- сделать шаг, горячая клавиша `key:F11`.
|
||||||
</dd>
|
: Выполняет одну команду скрипта и переходит к следующей. Если есть вложенный вызов, то заходит внутрь функции.
|
||||||
<dt><img style="vertical-align:middle" src="manage5.png"> -- отключить/включить все точки остановки.</dt>
|
|
||||||
<dd>Эта кнопка никак не двигает нас по коду, она позволяет временно отключить все точки остановки в файле.
|
|
||||||
</dd>
|
|
||||||
<dt><img style="vertical-align:middle" src="manage6.png"> -- включить/отключить автоматическую остановку при ошибке.</dt>
|
|
||||||
<dd>Эта кнопка -- одна из самых важных.
|
|
||||||
|
|
||||||
Нажмите её несколько раз. В старых версиях Chrome у неё три режима -- нужен фиолетовый, в новых -- два, тогда достаточно синего.
|
Эта кнопка позволяет подробнейшим образом пройтись по очереди по командам скрипта.
|
||||||
|
|
||||||
Когда она включена, то при ошибке в коде он автоматически остановится и мы сможем посмотреть в отладчике текущие значения переменных, при желании выполнить команды и выяснить, как так получилось.
|
 -- выполнять до выхода из текущей функции, горячая клавиша `key:Shift+F11`.
|
||||||
</dd>
|
: Выполняет команды до завершения текущей функции.
|
||||||
</dl>
|
|
||||||
|
Эта кнопка очень удобна в случае, если мы нечаянно вошли во вложенный вызов, который нам не интересен -- чтобы быстро из него выйти.
|
||||||
|
|
||||||
|
 -- отключить/включить все точки остановки.
|
||||||
|
: Эта кнопка никак не двигает нас по коду, она позволяет временно отключить все точки остановки в файле.
|
||||||
|
|
||||||
|
 -- включить/отключить автоматическую остановку при ошибке.
|
||||||
|
: Эта кнопка -- одна из самых важных.
|
||||||
|
|
||||||
|
Нажмите её несколько раз. В старых версиях Chrome у неё три режима -- нужен фиолетовый, в новых -- два, тогда достаточно синего.
|
||||||
|
|
||||||
|
Когда она включена, то при ошибке в коде он автоматически остановится и мы сможем посмотреть в отладчике текущие значения переменных, при желании выполнить команды и выяснить, как так получилось.
|
||||||
|
|
||||||
**Процесс отладки заключается в том, что мы останавливаем скрипт, смотрим, что с переменными, переходим дальше и ищем, где поведение отклоняется от правильного.**
|
**Процесс отладки заключается в том, что мы останавливаем скрипт, смотрим, что с переменными, переходим дальше и ищем, где поведение отклоняется от правильного.**
|
||||||
|
|
||||||
[smart header="Continue to here"]
|
```smart header="Continue to here"
|
||||||
Правый клик на номер строки открывает контекстное меню, в котором можно запустить выполнение кода до неё (Continue to here). Это удобно, когда хочется сразу прыгнуть вперёд и breakpoint неохота ставить.
|
Правый клик на номер строки открывает контекстное меню, в котором можно запустить выполнение кода до неё (Continue to here). Это удобно, когда хочется сразу прыгнуть вперёд и breakpoint неохота ставить.
|
||||||
[/smart]
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Консоль
|
## Консоль
|
||||||
|
|
||||||
При отладке, кроме просмотра переменных и передвижения по скрипту, бывает полезно запускать команды JavaScript. Для этого нужна консоль.
|
При отладке, кроме просмотра переменных и передвижения по скрипту, бывает полезно запускать команды JavaScript. Для этого нужна консоль.
|
||||||
|
|
||||||
В неё можно перейти, нажав кнопку "Console" вверху-справа, а можно и открыть в дополнение к отладчику, нажав на кнопку <span class="devtools" style="background-position:-72px -28px"></span> или клавишей [key ESC].
|
В неё можно перейти, нажав кнопку "Console" вверху-справа, а можно и открыть в дополнение к отладчику, нажав на кнопку <span class="devtools" style="background-position:-72px -28px"></span> или клавишей `key:ESC`.
|
||||||
|
|
||||||
**Самая любимая команда разработчиков: `console.log(...)`.**
|
**Самая любимая команда разработчиков: `console.log(...)`.**
|
||||||
|
|
||||||
Она пишет переданные ей аргументы в консоль, например:
|
Она пишет переданные ей аргументы в консоль, например:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
// результат будет виден в консоли
|
// результат будет виден в консоли
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
console.log("значение", i);
|
console.log("значение", i);
|
||||||
|
@ -200,10 +183,10 @@ for (var i = 0; i < 5; i++) {
|
||||||
|
|
||||||
Например, прервите отладку -- для этого достаточно закрыть инструменты разрабтчика -- и откройте [страницу с ошибкой](error/index.html).
|
Например, прервите отладку -- для этого достаточно закрыть инструменты разрабтчика -- и откройте [страницу с ошибкой](error/index.html).
|
||||||
|
|
||||||
Перейдите во вкладку Console инструментов разработчика ([key Ctrl+Shift+J] / [key Cmd+Shift+J]).
|
Перейдите во вкладку Console инструментов разработчика (`key:Ctrl+Shift+J` / `key:Cmd+Shift+J`).
|
||||||
|
|
||||||
В консоли вы увидите что-то подобное:
|
В консоли вы увидите что-то подобное:
|
||||||
<img src="console_error.png">
|

|
||||||
|
|
||||||
Красная строка -- это сообщение об ошибке.
|
Красная строка -- это сообщение об ошибке.
|
||||||
|
|
||||||
|
@ -214,46 +197,32 @@ for (var i = 0; i < 5; i++) {
|
||||||
Более подробно прояснить произошедшее нам поможет отладчик. Он может "заморозить" выполнение скрипта на момент ошибки и дать нам возможность посмотреть значения переменных и стека на тот момент.
|
Более подробно прояснить произошедшее нам поможет отладчик. Он может "заморозить" выполнение скрипта на момент ошибки и дать нам возможность посмотреть значения переменных и стека на тот момент.
|
||||||
|
|
||||||
Для этого:
|
Для этого:
|
||||||
<ol>
|
|
||||||
<li>Перейдите на вкладку Sources.</li>
|
1. Перейдите на вкладку Sources.
|
||||||
<li>Включите остановку при ошибке, кликнув на кнопку <img style="vertical-align:middle" src="manage6.png"></li>
|
2. Включите остановку при ошибке, кликнув на кнопку 
|
||||||
<li>Перезагрузите страницу.</li>
|
3. Перезагрузите страницу.
|
||||||
</ol>
|
|
||||||
|
|
||||||
После перезагрузки страницы JavaScript-код запустится снова и отладчик остановит выполнение на строке с ошибкой:
|
После перезагрузки страницы JavaScript-код запустится снова и отладчик остановит выполнение на строке с ошибкой:
|
||||||
|
|
||||||
<img src="chrome_break_error.png">
|

|
||||||
|
|
||||||
Можно посмотреть значения переменных. Открыть консоль и попробовать запустить что-то в ней. Поставить брейкпойнты раньше по коду и посмотреть, что привело к такой печальной картине, и так далее.
|
Можно посмотреть значения переменных. Открыть консоль и попробовать запустить что-то в ней. Поставить брейкпойнты раньше по коду и посмотреть, что привело к такой печальной картине, и так далее.
|
||||||
|
|
||||||
|
|
||||||
## Итого
|
## Итого
|
||||||
|
|
||||||
Отладчик позволяет:
|
Отладчик позволяет:
|
||||||
<ul>
|
|
||||||
<li>Останавливаться на отмеченном месте (breakpoint) или по команде `debugger`.</li>
|
- Останавливаться на отмеченном месте (breakpoint) или по команде `debugger`.
|
||||||
<li>Выполнять код -- по одной строке или до определённого места.</li>
|
- Выполнять код -- по одной строке или до определённого места.
|
||||||
<li>Смотреть переменные, выполнять команды в консоли и т.п.</li>
|
- Смотреть переменные, выполнять команды в консоли и т.п.
|
||||||
</ul>
|
|
||||||
|
|
||||||
В этой главе кратко описаны возможности отладчика Google Chrome, относящиеся именно к работе с кодом.
|
В этой главе кратко описаны возможности отладчика Google Chrome, относящиеся именно к работе с кодом.
|
||||||
|
|
||||||
Пока что это всё, что нам надо, но, конечно, инструменты разработчика умеют много чего ещё. В частности, вкладка Elements -- позволяет работать со страницей (понадобится позже), Timeline -- смотреть, что именно делает браузер и сколько это у него занимает и т.п.
|
Пока что это всё, что нам надо, но, конечно, инструменты разработчика умеют много чего ещё. В частности, вкладка Elements -- позволяет работать со страницей (понадобится позже), Timeline -- смотреть, что именно делает браузер и сколько это у него занимает и т.п.
|
||||||
|
|
||||||
Осваивать можно двумя путями:
|
Осваивать можно двумя путями:
|
||||||
<ol>
|
|
||||||
<li>[Официальная документация](https://developer.chrome.com/devtools) (на англ.)</li>
|
1. [Официальная документация](https://developer.chrome.com/devtools) (на англ.)
|
||||||
<li>Кликать в разных местах и смотреть, что получается. Не забывать о клике правой кнопкой мыши.</li>
|
2. Кликать в разных местах и смотреть, что получается. Не забывать о клике правой кнопкой мыши.
|
||||||
</ol>
|
|
||||||
|
|
||||||
Мы ещё вернёмся к отладчику позже, когда будем работать с HTML.
|
Мы ещё вернёмся к отладчику позже, когда будем работать с HTML.
|
||||||
[head]
|
|
||||||
<style>
|
|
||||||
span.devtools {
|
|
||||||
display: inline-block;
|
|
||||||
background-image: url(/article/debugging-chrome/statusbarButtonGlyphs.svg);
|
|
||||||
height:16px;
|
|
||||||
width:16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
[/head]
|
|
|
@ -1,11 +1,10 @@
|
||||||
# Как писать неподдерживаемый код?
|
# Как писать неподдерживаемый код?
|
||||||
|
|
||||||
[warn header="Познай свой код"]
|
```warn header="Познай свой код"
|
||||||
Эта статья представляет собой мой вольный перевод [How To Write Unmaintainable Code](http://mindprod.com/jgloss/unmain.html) ("как писать неподдерживаемый код") с дополнениями, актуальными для JavaScript.
|
Эта статья представляет собой мой вольный перевод [How To Write Unmaintainable Code](http://mindprod.com/jgloss/unmain.html) ("как писать неподдерживаемый код") с дополнениями, актуальными для JavaScript.
|
||||||
|
|
||||||
Возможно, в каких-то из этих советов вам даже удастся узнать "этого парня в зеркале".
|
Возможно, в каких-то из этих советов вам даже удастся узнать "этого парня в зеркале".
|
||||||
[/warn]
|
```
|
||||||
|
|
||||||
|
|
||||||
Предлагаю вашему вниманию советы мастеров древности, следование которым создаст дополнительные рабочие места для JavaScript-разработчиков.
|
Предлагаю вашему вниманию советы мастеров древности, следование которым создаст дополнительные рабочие места для JavaScript-разработчиков.
|
||||||
|
|
||||||
|
@ -17,17 +16,16 @@
|
||||||
|
|
||||||
Явно кривой код может написать любой дурак. Это заметят, и вас уволят, а код будет переписан с нуля. Вы не можете такого допустить. Эти советы учитывают такую возможность. Да здравствует дзен.
|
Явно кривой код может написать любой дурак. Это заметят, и вас уволят, а код будет переписан с нуля. Вы не можете такого допустить. Эти советы учитывают такую возможность. Да здравствует дзен.
|
||||||
|
|
||||||
|
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## Соглашения -- по настроению
|
## Соглашения -- по настроению
|
||||||
|
|
||||||
[quote author="Сериал \"Симпсоны\", серия Helter Shelter"]
|
```quote author="Сериал \"Симпсоны\", серия Helter Shelter"
|
||||||
Рабочий-чистильщик осматривает дом:<br>
|
Рабочий-чистильщик осматривает дом:<br>
|
||||||
"...Вот только жук у вас необычный...<br>
|
"...Вот только жук у вас необычный...<br>
|
||||||
И чтобы с ним справиться, я должен жить как жук, стать жуком, думать как жук."<br>
|
И чтобы с ним справиться, я должен жить как жук, стать жуком, думать как жук."<br>
|
||||||
(грызёт стол Симпсонов)
|
(грызёт стол Симпсонов)
|
||||||
[/quote]
|
```
|
||||||
|
|
||||||
Чтобы помешать другому программисту исправить ваш код, вы должны понять путь его мыслей.
|
Чтобы помешать другому программисту исправить ваш код, вы должны понять путь его мыслей.
|
||||||
|
|
||||||
|
@ -45,9 +43,10 @@
|
||||||
|
|
||||||
### Пример из jQuery
|
### Пример из jQuery
|
||||||
|
|
||||||
[warn header="jQuery / DOM"]
|
```warn header="jQuery / DOM"
|
||||||
Этот пример требует знаний jQuery/DOM, если пока их у вас нет -- пропустите его, ничего страшного, но обязательно вернитесь к нему позже. Подобное стоит многих часов отладки.
|
Этот пример требует знаний jQuery/DOM, если пока их у вас нет -- пропустите его, ничего страшного, но обязательно вернитесь к нему позже. Подобное стоит многих часов отладки.
|
||||||
[/warn]
|
```
|
||||||
|
|
||||||
Во фреймворке jQuery есть метод [wrap](http://api.jquery.com/wrap/), который обёртывает один элемент вокруг другого:
|
Во фреймворке jQuery есть метод [wrap](http://api.jquery.com/wrap/), который обёртывает один элемент вокруг другого:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -131,29 +130,27 @@ i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
|
||||||
|
|
||||||
### Будьте абстрактны при выборе имени
|
### Будьте абстрактны при выборе имени
|
||||||
|
|
||||||
[quote author="Лао-цзы"]Лучший кувшин лепят всю жизнь.<br>
|
```quote author="Лао-цзы"
|
||||||
|
Лучший кувшин лепят всю жизнь.<br>
|
||||||
Высокая музыка неподвластна слуху.<br>
|
Высокая музыка неподвластна слуху.<br>
|
||||||
Великий образ не имеет формы.[/quote]
|
Великий образ не имеет формы.
|
||||||
|
```
|
||||||
|
|
||||||
При выборе имени старайтесь применить максимально абстрактное слово, например `obj`, `data`, `value`, `item`, `elem` и т.п.
|
При выборе имени старайтесь применить максимально абстрактное слово, например `obj`, `data`, `value`, `item`, `elem` и т.п.
|
||||||
|
|
||||||
<ul>
|
- **Идеальное имя для переменной: `data`.** Используйте это имя везде, где можно. В конце концов, каждая переменная содержит *данные*, не правда ли?
|
||||||
<li>**Идеальное имя для переменной: `data`.** Используйте это имя везде, где можно. В конце концов, каждая переменная содержит *данные*, не правда ли?
|
|
||||||
|
|
||||||
Но что делать, если имя `data` уже занято? Попробуйте `value`, оно не менее универсально. Ведь каждая переменная содержит *значение*.
|
Но что делать, если имя `data` уже занято? Попробуйте `value`, оно не менее универсально. Ведь каждая переменная содержит *значение*.
|
||||||
|
|
||||||
Занято и это? Есть и другой вариант.
|
Занято и это? Есть и другой вариант.
|
||||||
</li>
|
- **Называйте переменную по типу данных, которые она хранит: `obj`, `num`, `arr`...**
|
||||||
<li>**Называйте переменную по типу данных, которые она хранит: `obj`, `num`, `arr`...**
|
|
||||||
|
|
||||||
Насколько это усложнит разработку? Как ни странно, намного!
|
Насколько это усложнит разработку? Как ни странно, намного!
|
||||||
|
|
||||||
Казалось бы, название переменной содержит информацию, говорит о том, что в переменной -- число, объект или массив... С другой стороны, **когда непосвящённый будет разбирать этот код -- он с удивлением обнаружит, что информации нет!**
|
Казалось бы, название переменной содержит информацию, говорит о том, что в переменной -- число, объект или массив... С другой стороны, **когда непосвящённый будет разбирать этот код -- он с удивлением обнаружит, что информации нет!**
|
||||||
|
|
||||||
Ведь как раз тип легко понять, запустив отладчик и посмотрев, что внутри. Но в чём смысл этой переменной? Что за массив/объект/число в ней хранится? Без долгой медитации над кодом тут не обойтись!
|
Ведь как раз тип легко понять, запустив отладчик и посмотрев, что внутри. Но в чём смысл этой переменной? Что за массив/объект/число в ней хранится? Без долгой медитации над кодом тут не обойтись!
|
||||||
</li>
|
- **Что делать, если и эти имена кончились? Просто добавьте цифру:** `item1, item2, elem5, data1`...
|
||||||
<li>**Что делать, если и эти имена кончились? Просто добавьте цифру:** `item1, item2, elem5, data1`...</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
### Похожие имена
|
### Похожие имена
|
||||||
|
|
||||||
|
@ -169,7 +166,9 @@ i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
|
||||||
|
|
||||||
### Хитрые синонимы
|
### Хитрые синонимы
|
||||||
|
|
||||||
[quote author="Конфуций"]Очень трудно найти чёрную кошку в тёмной комнате, особенно когда её там нет.[/quote]
|
```quote author="Конфуций"
|
||||||
|
Очень трудно найти чёрную кошку в тёмной комнате, особенно когда её там нет.
|
||||||
|
```
|
||||||
|
|
||||||
**Чтобы было не скучно -- используйте *похожие названия* для обозначения *одинаковых действий*.**
|
**Чтобы было не скучно -- используйте *похожие названия* для обозначения *одинаковых действий*.**
|
||||||
|
|
||||||
|
@ -237,10 +236,10 @@ function ninjaFunction(elem) {
|
||||||
|
|
||||||
### Перекрывайте внешние переменные
|
### Перекрывайте внешние переменные
|
||||||
|
|
||||||
[quote author="Гуань Инь-цзы"]
|
```quote author="Гуань Инь-цзы"
|
||||||
Находясь на свету, нельзя ничего увидеть в темноте.<br>
|
Находясь на свету, нельзя ничего увидеть в темноте.<br>
|
||||||
Пребывая же в темноте, увидишь все, что находится на свету.
|
Пребывая же в темноте, увидишь все, что находится на свету.
|
||||||
[/quote]
|
```
|
||||||
|
|
||||||
Почему бы не использовать одинаковые переменные внутри и снаружи функции? Это просто и не требует придумывать новых имён.
|
Почему бы не использовать одинаковые переменные внутри и снаружи функции? Это просто и не требует придумывать новых имён.
|
||||||
|
|
||||||
|
@ -273,7 +272,6 @@ function render() {
|
||||||
|
|
||||||
Представьте, что другому разработчику нужно только проверить адрес, а сообщение -- не выводить. Ваша функция `validateEmail(email)`, которая делает и то и другое, ему не подойдёт. Работодатель будет вынужден оплатить создание новой.
|
Представьте, что другому разработчику нужно только проверить адрес, а сообщение -- не выводить. Ваша функция `validateEmail(email)`, которая делает и то и другое, ему не подойдёт. Работодатель будет вынужден оплатить создание новой.
|
||||||
|
|
||||||
|
|
||||||
## Внимание.. Сюр-при-из!
|
## Внимание.. Сюр-при-из!
|
||||||
|
|
||||||
Есть функции, название которых говорит о том, что они ничего не меняют. Например, `isReady`, `checkPermission`, `findTags`... Предполагается, что при вызове они произведут некие вычисления, или найдут и возвратят полезные данные, но при этом их не изменят. В трактатах это называется "отсутствие сторонних эффектов".
|
Есть функции, название которых говорит о том, что они ничего не меняют. Например, `isReady`, `checkPermission`, `findTags`... Предполагается, что при вызове они произведут некие вычисления, или найдут и возвратят полезные данные, но при этом их не изменят. В трактатах это называется "отсутствие сторонних эффектов".
|
||||||
|
@ -294,8 +292,6 @@ function render() {
|
||||||
|
|
||||||
Возможно, даже больше вашего, так что не судите опрометчиво ;)
|
Возможно, даже больше вашего, так что не судите опрометчиво ;)
|
||||||
|
|
||||||
<ul>
|
- Следуйте нескольким из них -- и ваш код станет полон сюрпризов.
|
||||||
<li>Следуйте нескольким из них -- и ваш код станет полон сюрпризов.</li>
|
- Следуйте многим -- и ваш код станет истинно вашим, никто не захочет изменять его.
|
||||||
<li>Следуйте многим -- и ваш код станет истинно вашим, никто не захочет изменять его.</li>
|
- Следуйте всем -- и ваш код станет ценным уроком для молодых разработчиков, ищущих просветления.
|
||||||
<li>Следуйте всем -- и ваш код станет ценным уроком для молодых разработчиков, ищущих просветления.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
# Сделать pow по спецификации
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Сделать pow по спецификации
|
||||||
|
|
||||||
Исправьте код функции `pow`, чтобы тесты проходили.
|
Исправьте код функции `pow`, чтобы тесты проходили.
|
||||||
|
|
||||||
Для этого ниже в задаче вы найдёте ссылку на песочницу.
|
Для этого ниже в задаче вы найдёте ссылку на песочницу.
|
||||||
|
|
||||||
Она содержит HTML с тестами. Обратите внимание, что HTML-страница в ней короче той, что обсуждалась в статье [](/testing). Это потому что библиотеки Chai, Mocha и Sinon объединены в один файл:
|
Она содержит HTML с тестами. Обратите внимание, что HTML-страница в ней короче той, что обсуждалась в статье <info:testing>. Это потому что библиотеки Chai, Mocha и Sinon объединены в один файл:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://js.cx/test/libs.js"></script>
|
<script src="https://js.cx/test/libs.js"></script>
|
||||||
|
|
|
@ -28,8 +28,7 @@ describe("любое число, кроме нуля, в степени 0 рав
|
||||||
|
|
||||||
И не забудем добавить отдельный тест для нуля:
|
И не забудем добавить отдельный тест для нуля:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
...
|
...
|
||||||
it("ноль в нулевой степени даёт NaN", function() {
|
it("ноль в нулевой степени даёт NaN", function() {
|
||||||
assert( isNaN(pow(0, 0)), "0 в степени 0 не NaN");
|
assert( isNaN(pow(0, 0)), "0 в степени 0 не NaN");
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Добавьте тест к задаче
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Добавьте тест к задаче
|
||||||
|
|
||||||
Добавьте к [предыдущей задаче](/task/pow-nan-spec) тесты, которые будут проверять, что любое число, кроме нуля, в нулевой степени равно `1`, а ноль в нулевой степени даёт `NaN` (это математически корректно, результат 0<sup>0</sup> не определён).
|
Добавьте к [предыдущей задаче](/task/pow-nan-spec) тесты, которые будут проверять, что любое число, кроме нуля, в нулевой степени равно `1`, а ноль в нулевой степени даёт `NaN` (это математически корректно, результат 0<sup>0</sup> не определён).
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Что не так в тесте?
|
importance: 5
|
||||||
|
|
||||||
[importance 5]
|
---
|
||||||
|
|
||||||
|
# Что не так в тесте?
|
||||||
|
|
||||||
Что не так в этом тесте функции `pow`?
|
Что не так в этом тесте функции `pow`?
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ BDD -- это не просто тесты. Это гораздо больше.
|
||||||
|
|
||||||
Допустим, мы хотим разработать функцию `pow(x, n)`, которая возводит `x` в целую степень `n`, для простоты `n≥0`.
|
Допустим, мы хотим разработать функцию `pow(x, n)`, которая возводит `x` в целую степень `n`, для простоты `n≥0`.
|
||||||
|
|
||||||
|
|
||||||
Ещё до разработки мы можем представить себе, что эта функция будет делать и описать это по методике BDD.
|
Ещё до разработки мы можем представить себе, что эта функция будет делать и описать это по методике BDD.
|
||||||
|
|
||||||
Это описание называется *спецификация* (или, как говорят в обиходе, "спека") и выглядит так:
|
Это описание называется *спецификация* (или, как говорят в обиходе, "спека") и выглядит так:
|
||||||
|
@ -50,31 +49,29 @@ describe("pow", function() {
|
||||||
```
|
```
|
||||||
|
|
||||||
У спецификации есть три основных строительных блока, которые вы видите в примере выше:
|
У спецификации есть три основных строительных блока, которые вы видите в примере выше:
|
||||||
<dl>
|
|
||||||
<dt>`describe(название, function() { ... })`</dt>
|
|
||||||
<dd>Задаёт, что именно мы описываем, используется для группировки "рабочих лошадок" -- блоков `it`. В данном случае мы описываем функцию `pow`.</dd>
|
|
||||||
<dt>`it(название, function() { ... })`</dt>
|
|
||||||
<dd>В названии блока `it` *человеческим языком* описывается, что должна делать функция, далее следует *тест*, который проверяет это.</dd>
|
|
||||||
<dt>`assert.equal(value1, value2)`</dt>
|
|
||||||
<dd>Код внутри `it`, если реализация верна, должен выполняться без ошибок.
|
|
||||||
|
|
||||||
Различные функции вида `assert.*` используются, чтобы проверить, делает ли `pow` то, что задумано. Пока что нас интересует только одна из них -- `assert.equal`, она сравнивает свой первый аргумент со вторым и выдаёт ошибку в случае, когда они не равны. В данном случае она проверяет, что результат `pow(2, 3)` равен `8`.
|
`describe(название, function() { ... })`
|
||||||
|
: Задаёт, что именно мы описываем, используется для группировки "рабочих лошадок" -- блоков `it`. В данном случае мы описываем функцию `pow`.
|
||||||
|
|
||||||
|
`it(название, function() { ... })`
|
||||||
|
: В названии блока `it` *человеческим языком* описывается, что должна делать функция, далее следует *тест*, который проверяет это.
|
||||||
|
|
||||||
Есть и другие виды сравнений и проверок, которые мы увидим далее.</dd>
|
`assert.equal(value1, value2)`
|
||||||
</dl>
|
: Код внутри `it`, если реализация верна, должен выполняться без ошибок.
|
||||||
|
|
||||||
|
Различные функции вида `assert.*` используются, чтобы проверить, делает ли `pow` то, что задумано. Пока что нас интересует только одна из них -- `assert.equal`, она сравнивает свой первый аргумент со вторым и выдаёт ошибку в случае, когда они не равны. В данном случае она проверяет, что результат `pow(2, 3)` равен `8`.
|
||||||
|
|
||||||
|
Есть и другие виды сравнений и проверок, которые мы увидим далее.
|
||||||
|
|
||||||
## Поток разработки
|
## Поток разработки
|
||||||
|
|
||||||
Как правило, поток разработки таков:
|
Как правило, поток разработки таков:
|
||||||
<ol>
|
|
||||||
<li>Пишется спецификация, которая описывает самый базовый функционал.</li>
|
1. Пишется спецификация, которая описывает самый базовый функционал.
|
||||||
<li>Делается начальная реализация.</li>
|
2. Делается начальная реализация.
|
||||||
<li>Для проверки соответствия спецификации мы задействуем одновременно фреймворк, в нашем случае [Mocha](http://mochajs.org/) вместе со спецификацией и реализацией. Фреймворк запускает все тесты `it` и выводит ошибки, если они возникнут. При ошибках вносятся исправления.</li>
|
3. Для проверки соответствия спецификации мы задействуем одновременно фреймворк, в нашем случае [Mocha](http://mochajs.org/) вместе со спецификацией и реализацией. Фреймворк запускает все тесты `it` и выводит ошибки, если они возникнут. При ошибках вносятся исправления.
|
||||||
<li>Спецификация расширяется, в неё добавляются возможности, которые пока, возможно, не поддерживаются реализацией.</li>
|
4. Спецификация расширяется, в неё добавляются возможности, которые пока, возможно, не поддерживаются реализацией.
|
||||||
<li>Идём на пункт 3, делаем реализацию, и так далее, до победного конца.</li>
|
5. Идём на пункт 3, делаем реализацию, и так далее, до победного конца.
|
||||||
</ol>
|
|
||||||
|
|
||||||
Разработка ведётся *итеративно*, один проход за другим, пока спецификация и реализация не будут завершены.
|
Разработка ведётся *итеративно*, один проход за другим, пока спецификация и реализация не будут завершены.
|
||||||
|
|
||||||
|
@ -85,27 +82,23 @@ describe("pow", function() {
|
||||||
Для запуска тестов нужны соответствующие JavaScript-библиотеки.
|
Для запуска тестов нужны соответствующие JavaScript-библиотеки.
|
||||||
|
|
||||||
Мы будем использовать:
|
Мы будем использовать:
|
||||||
<ul>
|
|
||||||
<li>[Mocha](http://mochajs.org/) -- эта библиотека содержит общие функции для тестирования, включая `describe` и `it`.</li>
|
- [Mocha](http://mochajs.org/) -- эта библиотека содержит общие функции для тестирования, включая `describe` и `it`.
|
||||||
<li>[Chai](http://chaijs.com) -- библиотека поддерживает разнообразные функции для проверок. Есть разные "стили" проверки результатов, с которыми мы познакомимся позже, на текущий момент мы будем использовать лишь `assert.equal`.</li>
|
- [Chai](http://chaijs.com) -- библиотека поддерживает разнообразные функции для проверок. Есть разные "стили" проверки результатов, с которыми мы познакомимся позже, на текущий момент мы будем использовать лишь `assert.equal`.
|
||||||
<li>[Sinon](http://sinonjs.org/) -- для эмуляции и хитрой подмены функций "заглушками", понадобится позднее.</li>
|
- [Sinon](http://sinonjs.org/) -- для эмуляции и хитрой подмены функций "заглушками", понадобится позднее.
|
||||||
</ul>
|
|
||||||
|
|
||||||
Эти библиотеки позволяют тестировать JS не только в браузере, но и на сервере Node.JS. Здесь мы рассмотрим браузерный вариант, серверный использует те же функции.
|
Эти библиотеки позволяют тестировать JS не только в браузере, но и на сервере Node.JS. Здесь мы рассмотрим браузерный вариант, серверный использует те же функции.
|
||||||
|
|
||||||
Пример HTML-страницы для тестов:
|
Пример HTML-страницы для тестов:
|
||||||
|
|
||||||
```html
|
[html src="index.html"]
|
||||||
<!--+ src="index.html" -->
|
|
||||||
```
|
|
||||||
|
|
||||||
Эту страницу можно условно разделить на четыре части:
|
Эту страницу можно условно разделить на четыре части:
|
||||||
<ol>
|
|
||||||
<li>Блок `<head>` -- в нём мы подключаем библиотеки и стили для тестирования, нашего кода там нет.</li>
|
1. Блок `<head>` -- в нём мы подключаем библиотеки и стили для тестирования, нашего кода там нет.
|
||||||
<li>Блок `<script>` с реализацией спецификации, в нашем случае -- с кодом для `pow`.</li>
|
2. Блок `<script>` с реализацией спецификации, в нашем случае -- с кодом для `pow`.
|
||||||
<li>Далее подключаются тесты, файл `test.js` содержит `describe("pow", ...)`, который был описан выше. Методы `describe` и `it` принадлежат библиотеке Mocha, так что важно, что она была подключена выше.</li>
|
3. Далее подключаются тесты, файл `test.js` содержит `describe("pow", ...)`, который был описан выше. Методы `describe` и `it` принадлежат библиотеке Mocha, так что важно, что она была подключена выше.
|
||||||
<li>Элемент `<div id="mocha">` будет использоваться библиотекой Mocha для вывода результатов. Запуск тестов инициируется командой `mocha.run()`.</li>
|
4. Элемент `<div id="mocha">` будет использоваться библиотекой Mocha для вывода результатов. Запуск тестов инициируется командой `mocha.run()`.
|
||||||
</ol>
|
|
||||||
|
|
||||||
Результат срабатывания:
|
Результат срабатывания:
|
||||||
|
|
||||||
|
@ -143,27 +136,24 @@ function pow() {
|
||||||
|
|
||||||
Здесь есть два варианта организации кода:
|
Здесь есть два варианта организации кода:
|
||||||
|
|
||||||
<ol>
|
1. Первый вариант -- добавить `assert` в тот же `it`:
|
||||||
<li>Первый вариант -- добавить `assert` в тот же `it`:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
describe("pow", function() {
|
describe("pow", function() {
|
||||||
|
|
||||||
it("возводит в n-ю степень", function() {
|
it("возводит в n-ю степень", function() {
|
||||||
assert.equal(pow(2, 3), 8);
|
assert.equal(pow(2, 3), 8);
|
||||||
*!*
|
*!*
|
||||||
assert.equal(pow(3, 4), 81);
|
assert.equal(pow(3, 4), 81);
|
||||||
*/!*
|
*/!*
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
2. Второй вариант -- сделать два теста:
|
||||||
|
|
||||||
</li>
|
```js
|
||||||
<li>Второй вариант -- сделать два теста:
|
describe("pow", function() {
|
||||||
|
|
||||||
```js
|
|
||||||
describe("pow", function() {
|
|
||||||
|
|
||||||
it("при возведении 2 в 3ю степень результат 8", function() {
|
it("при возведении 2 в 3ю степень результат 8", function() {
|
||||||
assert.equal(pow(2, 3), 8);
|
assert.equal(pow(2, 3), 8);
|
||||||
|
@ -173,11 +163,8 @@ describe("pow", function() {
|
||||||
assert.equal(pow(3, 4), 81);
|
assert.equal(pow(3, 4), 81);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
Их принципиальное различие в том, что если `assert` обнаруживает ошибку, то он тут же прекращает выполнение блоки `it`. Поэтому в первом варианте, если вдруг первый `assert` "провалился", то про результат второго мы никогда не узнаем.
|
Их принципиальное различие в том, что если `assert` обнаруживает ошибку, то он тут же прекращает выполнение блоки `it`. Поэтому в первом варианте, если вдруг первый `assert` "провалился", то про результат второго мы никогда не узнаем.
|
||||||
|
|
||||||
|
@ -192,6 +179,7 @@ describe("pow", function() {
|
||||||
По этим причинам второй вариант здесь предпочтительнее.
|
По этим причинам второй вариант здесь предпочтительнее.
|
||||||
|
|
||||||
Результат:
|
Результат:
|
||||||
|
|
||||||
[iframe height=250 src="pow-2" edit border="1"]
|
[iframe height=250 src="pow-2" edit border="1"]
|
||||||
|
|
||||||
Как и следовало ожидать, второй тест не проходит. Ещё бы, ведь функция всё время возвращает `8`.
|
Как и следовало ожидать, второй тест не проходит. Ещё бы, ведь функция всё время возвращает `8`.
|
||||||
|
@ -232,8 +220,8 @@ describe("pow", function() {
|
||||||
```
|
```
|
||||||
|
|
||||||
Результат:
|
Результат:
|
||||||
[iframe height=250 src="pow-3" edit border="1"]
|
|
||||||
|
|
||||||
|
[iframe height=250 src="pow-3" edit border="1"]
|
||||||
|
|
||||||
## Вложенный describe
|
## Вложенный describe
|
||||||
|
|
||||||
|
@ -273,13 +261,12 @@ describe("pow", function() {
|
||||||
|
|
||||||
В будущем мы сможем в добавить другие тесты `it` и блоки `describe` со своими вспомогательными функциями.
|
В будущем мы сможем в добавить другие тесты `it` и блоки `describe` со своими вспомогательными функциями.
|
||||||
|
|
||||||
[smart header="before/after и beforeEach/afterEach"]
|
````smart header="before/after и beforeEach/afterEach"
|
||||||
В каждом блоке `describe` можно также задать функции `before/after`, которые будут выполнены до/после запуска тестов, а также `beforeEach/afterEach`, которые выполняются до/после каждого `it`.
|
В каждом блоке `describe` можно также задать функции `before/after`, которые будут выполнены до/после запуска тестов, а также `beforeEach/afterEach`, которые выполняются до/после каждого `it`.
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
```js
|
```js no-beautify
|
||||||
//+ no-beautify
|
|
||||||
describe("Тест", function() {
|
describe("Тест", function() {
|
||||||
|
|
||||||
before(function() { alert("Начало тестов"); });
|
before(function() { alert("Начало тестов"); });
|
||||||
|
@ -307,10 +294,10 @@ describe("Тест", function() {
|
||||||
Конец тестов
|
Конец тестов
|
||||||
```
|
```
|
||||||
|
|
||||||
[edit src="beforeafter"]Открыть пример с тестами в песочнице[/edit]
|
[edit src="beforeafter" title="Открыть пример с тестами в песочнице"]
|
||||||
|
|
||||||
Как правило, `beforeEach/afterEach` (`before/each`) используют, если необходимо произвести инициализацию, обнулить счётчики или сделать что-то ещё в таком духе между тестами (или их группами).
|
Как правило, `beforeEach/afterEach` (`before/each`) используют, если необходимо произвести инициализацию, обнулить счётчики или сделать что-то ещё в таком духе между тестами (или их группами).
|
||||||
[/smart]
|
````
|
||||||
|
|
||||||
## Расширение спецификации
|
## Расширение спецификации
|
||||||
|
|
||||||
|
@ -343,6 +330,7 @@ describe("pow", function() {
|
||||||
```
|
```
|
||||||
|
|
||||||
Результат с новыми тестами:
|
Результат с новыми тестами:
|
||||||
|
|
||||||
[iframe height=450 src="pow-nan" edit border="1"]
|
[iframe height=450 src="pow-nan" edit border="1"]
|
||||||
|
|
||||||
Конечно, новые тесты не проходят, так как наша реализация ещё не поддерживает их. Так и задумано: сначала написали заведомо не работающие тесты, а затем пишем реализацию под них.
|
Конечно, новые тесты не проходят, так как наша реализация ещё не поддерживает их. Так и задумано: сначала написали заведомо не работающие тесты, а затем пишем реализацию под них.
|
||||||
|
@ -363,15 +351,13 @@ describe("pow", function() {
|
||||||
|
|
||||||
Вот самые востребованные `assert`-проверки, встроенные в Chai:
|
Вот самые востребованные `assert`-проверки, встроенные в Chai:
|
||||||
|
|
||||||
<ul>
|
- `assert(value)` -- проверяет что `value` является `true` в логическом контексте.
|
||||||
<li>`assert(value)` -- проверяет что `value` является `true` в логическом контексте.</li>
|
- `assert.equal(value1, value2)` -- проверяет равенство `value1 == value2`.
|
||||||
<li>`assert.equal(value1, value2)` -- проверяет равенство `value1 == value2`.</li>
|
- `assert.strictEqual(value1, value2)` -- проверяет строгое равенство `value1 === value2`.
|
||||||
<li>`assert.strictEqual(value1, value2)` -- проверяет строгое равенство `value1 === value2`.</li>
|
- `assert.notEqual`, `assert.notStrictEqual` -- проверки, обратные двум предыдущим.
|
||||||
<li>`assert.notEqual`, `assert.notStrictEqual` -- проверки, обратные двум предыдущим.</li>
|
- `assert.isTrue(value)` -- проверяет, что `value === true`
|
||||||
<li>`assert.isTrue(value)` -- проверяет, что `value === true`</li>
|
- `assert.isFalse(value)` -- проверяет, что `value === false`
|
||||||
<li>`assert.isFalse(value)` -- проверяет, что `value === false`</li>
|
- ...более полный список -- в [документации](http://chaijs.com/api/assert/)
|
||||||
<li>...более полный список -- в [документации](http://chaijs.com/api/assert/)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
В нашем случае хорошо бы иметь проверку `assert.isNaN`, но, увы, такого метода нет, поэтому приходится использовать самый общий `assert(...)`. В этом случае для того, чтобы сделать сообщение об ошибке понятнее, желательно добавить к `assert` описание.
|
В нашем случае хорошо бы иметь проверку `assert.isNaN`, но, увы, такого метода нет, поэтому приходится использовать самый общий `assert(...)`. В этом случае для того, чтобы сделать сообщение об ошибке понятнее, желательно добавить к `assert` описание.
|
||||||
|
|
||||||
|
@ -405,25 +391,21 @@ describe("pow", function() {
|
||||||
|
|
||||||
В коде тестов выше можно было бы добавить описание и к `assert.equal`, указав в конце: `assert.equal(value1, value2, "описание")`, но с равенством обычно и так всё понятно, поэтому мы так делать не будем.
|
В коде тестов выше можно было бы добавить описание и к `assert.equal`, указав в конце: `assert.equal(value1, value2, "описание")`, но с равенством обычно и так всё понятно, поэтому мы так делать не будем.
|
||||||
|
|
||||||
|
|
||||||
## Итого
|
## Итого
|
||||||
|
|
||||||
Итак, разработка завершена, мы получили полноценную спецификацию и код, который её реализует.
|
Итак, разработка завершена, мы получили полноценную спецификацию и код, который её реализует.
|
||||||
|
|
||||||
Задачи выше позволяют дополнить её, и в результате может получиться что-то в таком духе:
|
Задачи выше позволяют дополнить её, и в результате может получиться что-то в таком духе:
|
||||||
|
|
||||||
```js
|
[js src="pow-full/test.js"]
|
||||||
//+ src="pow-full/test.js"
|
|
||||||
```
|
|
||||||
|
|
||||||
[edit src="pow-full"]Открыть полный пример с реализацией в песочнице[/edit]
|
[edit src="pow-full" title="Открыть полный пример с реализацией в песочнице"]
|
||||||
|
|
||||||
Эту спецификацию можно использовать как:
|
Эту спецификацию можно использовать как:
|
||||||
<ol>
|
|
||||||
<li>**Тесты**, которые гарантируют правильность работы кода.</li>
|
1. **Тесты**, которые гарантируют правильность работы кода.
|
||||||
<li>**Документацию** по функции, что она конкретно делает.</li>
|
2. **Документацию** по функции, что она конкретно делает.
|
||||||
<li>**Примеры** использования функции, которые демонстрируют её работу внутри `it`.</li>
|
3. **Примеры** использования функции, которые демонстрируют её работу внутри `it`.
|
||||||
</ol>
|
|
||||||
|
|
||||||
Имея спецификацию, мы можем улучшать, менять, переписывать функцию и легко контролировать её работу, просматривая тесты.
|
Имея спецификацию, мы можем улучшать, менять, переписывать функцию и легко контролировать её работу, просматривая тесты.
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,13 @@
|
||||||
|
|
||||||
У строки есть *свойство* `length`, содержащее длину:
|
У строки есть *свойство* `length`, содержащее длину:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( "Привет, мир!".length ); // 12
|
alert( "Привет, мир!".length ); // 12
|
||||||
```
|
```
|
||||||
|
|
||||||
Можно и записать строку в переменную, а потом запросить её свойство:
|
Можно и записать строку в переменную, а потом запросить её свойство:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
var str = "Привет, мир!";
|
var str = "Привет, мир!";
|
||||||
alert( str.length ); // 12
|
alert( str.length ); // 12
|
||||||
```
|
```
|
||||||
|
@ -27,8 +25,7 @@ alert( str.length ); // 12
|
||||||
|
|
||||||
Также у строк есть *метод* `toUpperCase()`, который возвращает строку в верхнем регистре:
|
Также у строк есть *метод* `toUpperCase()`, который возвращает строку в верхнем регистре:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
var hello = "Привет, мир!";
|
var hello = "Привет, мир!";
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
@ -36,14 +33,12 @@ alert( hello.toUpperCase() ); // "ПРИВЕТ, МИР!"
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
[warn header="Вызов метода -- через круглые скобки!"]
|
````warn header="Вызов метода -- через круглые скобки!"
|
||||||
|
|
||||||
Обратите внимание, для вызова метода обязательно нужны круглые скобки.
|
Обратите внимание, для вызова метода обязательно нужны круглые скобки.
|
||||||
|
|
||||||
Посмотрите, например, результат обращения к `toUpperCase` без скобок:
|
Посмотрите, например, результат обращения к `toUpperCase` без скобок:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
var hello = "Привет";
|
var hello = "Привет";
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
@ -55,25 +50,22 @@ alert( hello.toUpperCase ); // function...
|
||||||
|
|
||||||
А чтобы получить результат -- нужно произвести её вызов, добавив скобки:
|
А чтобы получить результат -- нужно произвести её вызов, добавив скобки:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
var hello = "Привет";
|
var hello = "Привет";
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
alert( hello.toUpperCase() ); // ПРИВЕТ
|
alert( hello.toUpperCase() ); // ПРИВЕТ
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
````
|
||||||
|
|
||||||
[/warn]
|
Более подробно с различными свойствами и методами строк мы познакомимся в главе <info:string>.
|
||||||
|
|
||||||
Более подробно с различными свойствами и методами строк мы познакомимся в главе [](/string).
|
|
||||||
|
|
||||||
## Метод num.toFixed(n)
|
## Метод num.toFixed(n)
|
||||||
|
|
||||||
Есть методы и у чисел, например `num.toFixed(n)`. Он округляет число `num` до `n` знаков после запятой, при необходимости добивает нулями до данной длины и возвращает в виде строки (удобно для форматированного вывода):
|
Есть методы и у чисел, например `num.toFixed(n)`. Он округляет число `num` до `n` знаков после запятой, при необходимости добивает нулями до данной длины и возвращает в виде строки (удобно для форматированного вывода):
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
var n = 12.345;
|
var n = 12.345;
|
||||||
|
|
||||||
alert( n.toFixed(2) ); // "12.35"
|
alert( n.toFixed(2) ); // "12.35"
|
||||||
|
@ -81,20 +73,18 @@ alert( n.toFixed(0) ); // "12"
|
||||||
alert( n.toFixed(5) ); // "12.34500"
|
alert( n.toFixed(5) ); // "12.34500"
|
||||||
```
|
```
|
||||||
|
|
||||||
Детали работы `toFixed` разобраны в главе [](/number).
|
Детали работы `toFixed` разобраны в главе <info:number>.
|
||||||
|
|
||||||
[warn header="Обращение к методам чисел"]
|
````warn header="Обращение к методам чисел"
|
||||||
К методу числа можно обратиться и напрямую:
|
К методу числа можно обратиться и напрямую:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 12.34.toFixed(1) ); // 12.3
|
alert( 12.34.toFixed(1) ); // 12.3
|
||||||
```
|
```
|
||||||
|
|
||||||
...Но если число целое, то будет проблема:
|
...Но если число целое, то будет проблема:
|
||||||
|
|
||||||
```js
|
```js run no-beautify
|
||||||
//+ run no-beautify
|
|
||||||
alert(12.toFixed(1)); // ошибка!
|
alert(12.toFixed(1)); // ошибка!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -102,12 +92,10 @@ alert(12.toFixed(1)); // ошибка!
|
||||||
|
|
||||||
Это -- особенность синтаксиса JavaScript. Вот так -- будет работать:
|
Это -- особенность синтаксиса JavaScript. Вот так -- будет работать:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
alert( 12..toFixed(1) ); // 12.0
|
alert( 12..toFixed(1) ); // 12.0
|
||||||
```
|
```
|
||||||
|
````
|
||||||
[/warn]
|
|
||||||
|
|
||||||
## Итого
|
## Итого
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
Узнать количество реально переданных аргументов можно по значению `arguments.length`:
|
Узнать количество реально переданных аргументов можно по значению `arguments.length`:
|
||||||
|
|
||||||
```js
|
```js run
|
||||||
//+ run
|
|
||||||
function f(x) {
|
function f(x) {
|
||||||
alert( arguments.length ? 1 : 0 );
|
alert( arguments.length ? 1 : 0 );
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue