work
|
@ -18,51 +18,44 @@ When JavaScript was created, it initially had another name: "LiveScript". But Ja
|
|||
But as it evolved, JavaScript became a fully independent language, with its own specification called [ECMAScript](http://en.wikipedia.org/wiki/ECMAScript), and now it has no relation to Java at all.
|
||||
```
|
||||
|
||||
At present, JavaScript can execute not only in the browser, but also on the server, or actually on any device where 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 exists a special program called [the JavaScript engine](https://en.wikipedia.org/wiki/JavaScript_engine).
|
||||
|
||||
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 engine, sometimes it's also called a "JavaScript virtual machine".
|
||||
|
||||
Different engines have different "codenames", for example:
|
||||
|
||||
- [V8 engine]("https://en.wikipedia.org/wiki/V8_(JavaScript_engine)") -- in Chrome and Opera.
|
||||
- [V8]("https://en.wikipedia.org/wiki/V8_(JavaScript_engine)") -- in Chrome and Opera.
|
||||
- [Gecko]("https://en.wikipedia.org/wiki/Gecko_(software)") -- in Firefox.
|
||||
- ...There are other codenames like "Trident", "Chakra" for different versions of IE, "Nitro" and "SquirrelFish" for Safari etc.
|
||||
|
||||
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.
|
||||
These terms above are good to remember, because they are used in developer articles in the internet. We'll use them too. For instance, if "a feature X is supported by V8", then it probably works in Chrome and Opera.
|
||||
|
||||
```smart header="Compilation and interpretation"
|
||||
There are two general approaches to execute programs: "compilation" and "interpretation".
|
||||
```smart header="How the engines work?"
|
||||
|
||||
- *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.
|
||||
- *Interpreters*, and in particular the one embedded in the browser -- get the source code and execute it "as is".
|
||||
|
||||
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:
|
||||
Engines are complicated. But the basics are easy.
|
||||
|
||||
1. The script is written and distributed as a plain text (can be compressed/optimized by so-called "javascript minifiers").
|
||||
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.
|
||||
2. The engine (embedded if it's a browser) reads the script ("parses") and converts ("compiles") it to the machine language.
|
||||
3. And then it runs, pretty 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.
|
||||
The engine applies optimizations on every stage of the process. It even watches the script as it runs, analyzes the data which flows through it and applies optimizations to the machine-code basing on that knowledge.
|
||||
```
|
||||
|
||||
## What in-browser JavaScript can do?
|
||||
|
||||
The modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or CPU, because it was initially created for browsers which do not require it.
|
||||
|
||||
Other capabilities depend on the environment which runs JavaScript. For instance, Node.JS has functionality that allows JavaScript to read/write arbitrary files, perform network requests etc.
|
||||
The capabilities greatly depend on the environment which runs JavaScript. For instance, [Node.JS](https://wikipedia.org/wiki/Node.js) supports functions that allows JavaScript to read/write arbitrary files, perform network requests etc.
|
||||
|
||||
In the browser JavaScript can do everything related to webpage manipulation, interaction with the user and the webserver.
|
||||
In-browser JavaScript can do everything related to webpage manipulation, interaction with the user and the webserver.
|
||||
|
||||
For instance, in-browser JavaScript is able to:
|
||||
|
||||
- Add new HTML to the page, change the existing content, modify styles.
|
||||
- React on user actions, run on mouse clicks, pointer movements, key presses.
|
||||
- Send requests over the network to remote servers, download and upload data without reloading the page (a so-called "AJAX" technology).
|
||||
- Get and set cookies, prompt user for the data, show messages.
|
||||
- Store data in-browser ("localStorage").
|
||||
- Send requests over the network to remote servers, download and upload files (so-called [AJAX](https://en.wikipedia.org/wiki/Ajax_(programming)) and [COMET](https://en.wikipedia.org/wiki/Comet_(programming)) technologies).
|
||||
- Get and set cookies, ask questions to the visitor, show messages.
|
||||
- Remember the data on the browser side ("local storage").
|
||||
|
||||
## What in-browser JavaScript can NOT do?
|
||||
|
||||
|
@ -74,7 +67,7 @@ The examples of such restrictions are:
|
|||
|
||||
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](https://en.wikipedia.org/wiki/National_Security_Agency).
|
||||
- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. 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.
|
||||
|
@ -102,53 +95,16 @@ That's what makes JavaScript unique. That's why it is the most widespread way of
|
|||
|
||||
While planning to learn a new technology, it's beneficial to check it's perspectives. So let's move on to the modern trends that include new languages and browser abilities.
|
||||
|
||||
## HTML 5
|
||||
|
||||
*HTML 5* is an evolution of HTML which adds new tags and what's more important -- new browser abilities, accessable from JavaScript.
|
||||
|
||||
Few examples:
|
||||
|
||||
- Write files on disk (in a "sandbox", not to any folder).
|
||||
- A database embedded in the browser, to keep data on a user's computer and effeciently operate on it.
|
||||
- Multitasking with the usage of many CPU cores in one time.
|
||||
- Audio/video playback.
|
||||
- 2d and 3d-drawing with hardware acceleration support, just like in modern games.
|
||||
|
||||
Many new abilities are still in progress, but browsers gradually improve the support for them.
|
||||
|
||||
```summary
|
||||
The trend: browser can do more and more, it is becoming more like an all-purpose desktop application.
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
...As the time goes, the specification matures and changes, and browsers must adapt it. That may lead to errors in the older code which was too eager to use the early version. So one should think twice before relying on things that are in draft yet.
|
||||
|
||||
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
|
||||
The trend: browsers, though eager for new features, tend to be compatible with the standard.
|
||||
```
|
||||
|
||||
## New ECMAScript
|
||||
|
||||
JavaScript evolves. The upcoming ECMAScript-2016 standard adds more language-level features which make the syntax more capable and expressive.
|
||||
|
||||
Modern browsers improve their engines to raise JavaScript execution script, fix bugs and try to follow the standards.
|
||||
|
||||
```summary
|
||||
The trend: JavaScript is becoming faster, gets new syntax and language features.
|
||||
```
|
||||
|
||||
## Languages "over" JavaScript
|
||||
|
||||
The syntax of JavaScript does not suit everyone's needs: some people think that it's too flexible, the others consider it too limited, the third ones want to add new features absent in the standard...
|
||||
The syntax of JavaScript does not suit everyone's needs. Different people want different features.
|
||||
|
||||
That's normal, because projects and requirements are different for everyone.
|
||||
|
||||
So recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run.
|
||||
So recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run in the browser.
|
||||
|
||||
The transpilation happens automatically, modern tools make the process very fast and transparent, actually allowing developers to code in another language. But they still should know JavaScript, to better understand what they are doing.
|
||||
The modern tools make the transpilation very fast and transparent, actually allowing developers to code in another language, autoconverting it "under the hood".
|
||||
|
||||
Examples of such languages:
|
||||
|
||||
|
@ -156,6 +112,8 @@ Examples of such languages:
|
|||
- [TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing", to simplify development and support of complex systems. Developed by Microsoft.
|
||||
- [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.
|
||||
|
||||
There are more. Of course even if we use one of those languages, we should also know JavaScript, to really understand what we're doing.
|
||||
|
||||
## Summary
|
||||
|
||||
- JavaScript was initially created as a browser-only language, but now used in many other environments as well.
|
||||
|
|
|
@ -1,82 +1,55 @@
|
|||
|
||||
# Using the latest features now
|
||||
# Embrace the future!
|
||||
|
||||
The [latest standard](http://www.ecma-international.org/publications/standards/Ecma-262.htm) was approved in June 2015.
|
||||
The JavaScript language steadily evolves. The new proposals get analyzed and, if they look worthy, are appended to the list at <https://tc39.github.io/ecma262/> and then progress to the [specification](http://www.ecma-international.org/publications/standards/Ecma-262.htm).
|
||||
|
||||
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/>.
|
||||
It's quite common for the engine to implement only the part of the standard. Different engines have their own ideas about what's to implement first. They may implement proposals that are not approved yet and fail to implement things that are in the spec, because they are less interesting or just harder. A good page to see the current state of support is <https://kangax.github.io/compat-table/es6/> (that's for the future when you know the language).
|
||||
|
||||
## Single-engine app
|
||||
|
||||
If a project is developed for a single JavaScript engine, like V8 (Node.JS, Chrome), then we can use V8-supported features. That's a lot.
|
||||
|
||||
Most notably, V8 supports many of the new features only if the code is running in the "strict mode" (modern mode), which should be enabled explicitly using a directive `'use strict';` at the start.
|
||||
|
||||
You will find most code in this tutorial using this directive and, because of that, runnable in Chrome.
|
||||
|
||||
But what if we're writing a cross-browser application? Different browsers support different subsets of ES-2015.
|
||||
|
||||
Here comes Babel.JS.
|
||||
We are going to learn the most up-to-date JavaScript.
|
||||
|
||||
## Babel.JS
|
||||
|
||||
...But when we use all the modern features of the language, some engines may fail to support such code.
|
||||
|
||||
Here comes Babel.JS.
|
||||
|
||||
[Babel.JS](https://babeljs.io) is a [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler). It rewrites the modern JavaScript code into the previous standard.
|
||||
|
||||
Actually, there are two parts in Babel:
|
||||
|
||||
1. 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.
|
||||
2. JavaScript library.
|
||||
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.
|
||||
|
||||
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.
|
||||
2. The polyfill.
|
||||
|
||||
There is a special "play" mode of Babel.JS which merges both parts in a single in-browser script.
|
||||
For some functions we also need add a special script that should run before our scripts and introduce modern functions that the engine may not support by itself. There's a term "polyfill" for such scripts.
|
||||
|
||||
The usage looks like this:
|
||||
The two interesting variants are [babel polyfill](https://babeljs.io/docs/usage/polyfill/) that supports a lot, but is big and the [polyfill.io](http://polyfill.io) service that allows to load/construct polyfills on-demand, depending on the features we need.
|
||||
|
||||
```html run
|
||||
*!*
|
||||
<!-- browser.js is on my server please don't hotlink -->
|
||||
<script src="https://en.js.cx/babel-core/browser.min.js"></script>
|
||||
*/!*
|
||||
The transpiler and/or polyfill may be not needed if we orient towards more-or-less modern engines and don't use rarely supported features.
|
||||
|
||||
<script type="text/babel">
|
||||
let arr = ["hello", 2];
|
||||
|
||||
let [str, times] = arr;
|
||||
|
||||
alert( str.repeat(times) ); // hellohello
|
||||
</script>
|
||||
```
|
||||
|
||||
Script `browser.min.js` is attached to the top of the page. It automatically transpiles and runs the scripts with `type="text/babel"`.
|
||||
|
||||
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:
|
||||
|
||||
- There is a "try it" page on <https://babeljs.io/repl/> which allows to run snippets of code.
|
||||
- [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.
|
||||
|
||||
# Examples on this site
|
||||
## Examples in the tutorial
|
||||
|
||||
```warn header="Browser support is required"
|
||||
Examples that use ES-2015 will work only if your browser supports it.
|
||||
Examples that use modern JS will work only if your browser supports it.
|
||||
```
|
||||
|
||||
Sometimes it means that when running an example in a non-supporting browser, an error is shown.
|
||||
````online
|
||||
Most examples are runnable at-place, like here:
|
||||
|
||||
```js run
|
||||
alert('Press the "Play" button in the upper-right corner to run');
|
||||
```
|
||||
|
||||
...But if it uses a feature that your browser does not support, an error is shown.
|
||||
|
||||
That doesn't mean that the example is wrong! It's just the browser lacking the support for certain features yet.
|
||||
````
|
||||
|
||||
[Chrome Canary](https://www.google.com/chrome/browser/canary.html) is recommended, most examples work in it.
|
||||
[Chrome Canary](https://www.google.com/chrome/browser/canary.html) is good for more examples.
|
||||
|
||||
[Firefox Developer Edition](https://www.mozilla.org/en-US/firefox/channel/#developer) is fine too, but it has certain glitches. Like: [let](/let-const) variables working only with when the script type contains `version=1.7` or `1.8`: `<script type="application/javascript;version=1.7">`. Most other browsers do not understand such script type. This site uses a special trick to workaround that, so that the scripts work in both Firefox and other browsers.
|
||||
Note that on production we can use Babel to translate the code into suitable for less recent browsers, so there will be no such limitation, the code will run everywhere.
|
||||
|
||||
And even if your browser does not support some code, you can run it through Babel.JS, on the page [Babel: try it out](https://babeljs.io/repl/)!
|
||||
|
||||
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/>.
|
||||
|
||||
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, so let's choose a good code editor.
|
||||
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
# Code editors
|
||||
|
||||
For the comfortable development we need a good code editor.
|
||||
The code editor is the place where a programmer spends most his time.
|
||||
|
||||
It should support at least:
|
||||
|
||||
1. Syntax highlight.
|
||||
2. Autocompletion.
|
||||
3. Folding -- collapsing/opening blocks of code.
|
||||
4. ...the more features -- the better.
|
||||
There are two archetypes: IDE and lightweight editors. Many people feel comfortable choosing one tool of each type.
|
||||
|
||||
[cut]
|
||||
|
||||
## IDE
|
||||
|
||||
The term "IDE" (Integrated Development Environment) -- denotes an advanced editor which can integrate with additional systems, such as bugtrackering, version control etc.
|
||||
The term [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) (Integrated Development Environment) is a powerful editor with many additional features that usually operates on a "whole project".
|
||||
|
||||
An IDE operates on a "whole project": loads it and then can navigate between files, provide autocompletion based on the whole project, do other "project-level" stuff.
|
||||
An IDE loads the project (can be many files), and then allows navigate between files, provides autocompletion based on the whole project, does other "project-level" stuff.
|
||||
|
||||
If you haven't considered selecting an IDE, pleae look at the following variants:
|
||||
|
||||
|
@ -27,23 +22,23 @@ If you haven't considered selecting an IDE, pleae look at the following variants
|
|||
|
||||
All of them with the exception of Visual Studio are cross-platform.
|
||||
|
||||
Most IDEs are paid, but have a trial period. Their cost is usually negligible compared to a qualified developer's salary, so just choose the best for you.
|
||||
Most IDEs are paid, but have a trial period. Their cost is usually negligible compared to a qualified developer's salary, so just choose the best one for you.
|
||||
|
||||
## Lightweight editors
|
||||
|
||||
"Lightweight editors" are not as powerful as IDEs, but they're fast and simple.
|
||||
"Lightweight editors" are not as powerful as IDEs, but they're fast, elegant and simple.
|
||||
|
||||
They are mainly used to instantly open and edit a file.
|
||||
|
||||
The main difference between a "lightweight editor" and an "IDE" is that the latter works on a project-level, meaning it has to load a lot of data to start, and the former one opens just the files. That's much faster.
|
||||
|
||||
In practice, "lightweight" editors may have a lot of plugins including directory-level syntax analyzers and autocompleters, so there's no strict border between a lightweight editor and an IDE. There's no point in arguing what is what.
|
||||
In practice, "lightweight" editors may have a lot of plugins including directory-level syntax analyzers and autocompleters, so there's no strict border between a lightweight editor and an IDE.
|
||||
|
||||
The following options deserve your attention:
|
||||
|
||||
- <a href="http://www.sublimetext.com">Sublime Text</a> (cross-platform, shareware).
|
||||
- <a href="https://atom.io/">Atom</a> (cross-platform, free).
|
||||
- <a href="http://sourceforge.net/projects/notepad-plus/">Notepad++</a> (Windows, free).
|
||||
- [Sublime Text](http://www.sublimetext.com) (cross-platform, shareware).
|
||||
- [Atom](https://atom.io/) (cross-platform, free).
|
||||
- [Notepad++](http://sourceforge.net/projects/notepad-plus/) (Windows, free).
|
||||
- Vim, Emacs are cool. If you know how to use them.
|
||||
|
||||
## My favorites
|
||||
|
@ -53,7 +48,7 @@ I believe one should have both an IDE for projects and a lightweight editor for
|
|||
I'm using:
|
||||
|
||||
- [WebStorm](http://www.jetbrains.com/webstorm/) for JS, and if there is one more language in the project, then I switch to 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.
|
||||
- As a lightweight editor -- <a href="http://www.sublimetext.com">Sublime Text</a>.
|
||||
- As a lightweight editor -- [Sublime Text](http://www.sublimetext.com).
|
||||
|
||||
If you don't know what to choose -- you can consider these ones.
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
# Developer console
|
||||
|
||||
And the last step before we start developing...
|
||||
And the one more thing before we get down to coding.
|
||||
|
||||
A code is error-prone. You are quite likely to have errors... Oh what I'm talking? You are *absolutely* going to make errors, if you're a human, not a [robot]("https://en.wikipedia.org/wiki/Bender_(Futurama)").
|
||||
A code is error-prone. You are quite likely to have errors... Oh what I'm talking? You are *absolutely* going to make errors, at least if you're a human, not a [robot]("https://en.wikipedia.org/wiki/Bender_(Futurama)").
|
||||
|
||||
So let's grasp the basics of developer console.
|
||||
|
||||
In browser, a user doesn't see the errors by default. So, if something goes wrong in the script, we won't see what's broken and can't fix it.
|
||||
But in the browser, a user doesn't see the errors by default. So, if something goes wrong in the script, we won't see what's broken and can't fix it.
|
||||
|
||||
To see errors and get a lot of other useful information about scripts, browsers have embedded "developer tools".
|
||||
|
||||
|
@ -16,7 +14,7 @@ Other browsers also provide developer tools, but are usually in a "catching-up"
|
|||
|
||||
If there is an error in the certain browser only, then we can use it's developer tools, but usually -- Chrome/Firefox.
|
||||
|
||||
Developer tools are really powerful, there are many features, but on this stage let's just look how to open them, look at errors and run JavaScript commands.
|
||||
Developer tools are really powerful, there are many features. On this stage let's just look how to open them, look at errors and run JavaScript commands.
|
||||
|
||||
[cut]
|
||||
|
||||
|
@ -24,7 +22,7 @@ Developer tools are really powerful, there are many features, but on this stage
|
|||
|
||||
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. It's hidden from a regular visitor's eyes, so let's open developer tools to see it.
|
||||
|
||||
Press the key `key:F12` or, if you're on Mac, then `key:Cmd+Opt+J`.
|
||||
|
||||
|
@ -32,7 +30,7 @@ The developer tools will open on the Console tab by default.
|
|||
|
||||
It looks somewhat like this:
|
||||
|
||||

|
||||

|
||||
|
||||
The exact look depends on your Chrome version. It changes from time to time, but should be similar.
|
||||
|
||||
|
@ -43,22 +41,23 @@ Below the error message there is a blue `>` symbol. It marks a "command line" wh
|
|||
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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
|
||||
## Firefox, Edge and others
|
||||
|
||||
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.
|
||||
|
||||
## Safari
|
||||
|
||||
Safari (if you use Mac, not Windows/Linux) is a little bit special here. We need to enable the "Develop menu" first.
|
||||
|
||||
There's a checkbox for that at the bottom of the "Advanced" pane of the preferences:
|
||||
|
||||

|
||||
|
||||
Now `key:Cmd+Opt+C` can toggle the console. Also note that the new top menu item has appeared with many useful options.
|
||||
|
||||
## Summary
|
||||
|
||||
- Developer tools allow us to see errors, run commands, examine variables and much more.
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
|
||||
<script>
|
||||
alert( "I'm JavaScript!" );
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,12 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Show an alert
|
||||
|
||||
Create a page that shows a message "I'm JavaScript!".
|
||||
|
||||
Do it in a sandbox, or on your hard drive, doesn't matter, just ensure that it works.
|
||||
|
||||
[demo src="solution"]
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
# Hello, world!
|
||||
|
||||
In this chapter we'll create a simple script and see it working.
|
||||
|
||||
[cut]
|
||||
|
||||
## The "script" tag
|
||||
|
||||
```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 <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 :)
|
||||
```
|
||||
|
||||
JavaScript programs can be inserted in any place of HTML with the help of the `<script>` tag.
|
||||
|
||||
For instance:
|
||||
|
||||
```html run height=100
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
|
||||
<p>Document start...</p>
|
||||
|
||||
*!*
|
||||
<script>
|
||||
alert( 'Hello, world!' );
|
||||
</script>
|
||||
*/!*
|
||||
|
||||
<p>...Document end.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
```online
|
||||
You can run the example clicking on a "Play" button in it's right-top corner.
|
||||
```
|
||||
|
||||
The `<script>` tag contains JavaScript code which is automatically executed when the browser meets the tag.
|
||||
|
||||
Please note the execution sequence:
|
||||
|
||||
1. Browser starts to parse the document and display the page.
|
||||
2. When the browser meets `<script>`, it switches to the JavaScript execution mode. In this mode it executes the script.
|
||||
3. The `alert` command shows a message and pauses the execution.
|
||||
4. *Note that a part of the page before the script is shown already at this moment.*
|
||||
5. When the script is finished, it gets back to the HTML-mode, and *only then* it shows the rest of the document.
|
||||
|
||||
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
|
||||
|
||||
In the past, `<script>` had a few necessary attributes.
|
||||
|
||||
We can find the following in the old code:
|
||||
|
||||
The `type` attribute: <code><script <u>type</u>=...></code>
|
||||
|
||||
: 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 `language` attribute: <code><script <u>language</u>=...></code>
|
||||
: This attribute was meant to show the language of the script. As of now, this attribute makes no sense, the language is JavaScript by default. No need to use it.
|
||||
|
||||
Comments before and after scripts.
|
||||
: In really ancient books and guides, one may find comments inside `<script>`, like this:
|
||||
|
||||
```html no-beautify
|
||||
<script type="text/javascript"><!--
|
||||
...
|
||||
//--></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.
|
||||
|
||||
## Summary
|
||||
|
||||
- We can use a `<script>` tag without attributes to add JavaScript code to the page.
|
||||
- A `<script>` tag blocks page rendering. Can be bad. Later we'll see how to evade that.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
**Yes, it will.**
|
||||
|
||||
Any string except an empty one (and `"0"` is not empty) becomes `true` in the logical context.
|
||||
|
||||
We can run and check:
|
||||
|
||||
```js run
|
||||
if ("0") {
|
||||
alert( 'Hello' );
|
||||
}
|
||||
```
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# if (a string with zero)
|
||||
|
||||
Will `alert` be shown?
|
||||
|
||||
```js
|
||||
if ("0") {
|
||||
alert( 'Hello' );
|
||||
}
|
||||
```
|
||||
|
Before Width: | Height: | Size: 23 KiB |
|
@ -1,20 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
let value = prompt('What is the "official" name of JavaScript?', '');
|
||||
|
||||
if (value == 'ECMAScript') {
|
||||
alert('Right!');
|
||||
} else {
|
||||
alert("Didn't know? ECMAScript!");
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
Before Width: | Height: | Size: 54 KiB |
|
@ -1,4 +0,0 @@
|
|||
|
||||
|
||||
[html run src="ifelse_task2/index.html"]
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
importance: 2
|
||||
|
||||
---
|
||||
|
||||
# The 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!"
|
||||
|
||||

|
||||
|
||||
[demo src="ifelse_task2"]
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
let value = prompt('Type a number', 0);
|
||||
|
||||
if (value > 0) {
|
||||
alert(1);
|
||||
} else if (value < 0) {
|
||||
alert(-1);
|
||||
} else {
|
||||
alert(0);
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
|
||||
```js run
|
||||
let value = prompt('Type a number', 0);
|
||||
|
||||
if (value > 0) {
|
||||
alert( 1 );
|
||||
} else if (value < 0) {
|
||||
alert( -1 );
|
||||
} else {
|
||||
alert( 0 );
|
||||
}
|
||||
```
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
importance: 2
|
||||
|
||||
---
|
||||
|
||||
# Show the sign
|
||||
|
||||
Using `if..else`, write the code which gets a number via `prompt` and then shows in `alert`:
|
||||
|
||||
- `1`, if the value is greater than zero,
|
||||
- `-1`, if less than zero,
|
||||
- `0`, if equals zero.
|
||||
|
||||
In this task we assume that the input is always a number.
|
||||
|
||||
[demo src="if_sign"]
|
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 92 KiB |
|
@ -1,31 +0,0 @@
|
|||
|
||||
|
||||
```js run demo
|
||||
let userName = prompt('Who's there?', '');
|
||||
|
||||
if (userName == 'Admin') {
|
||||
|
||||
let pass = prompt('Password?', '');
|
||||
|
||||
if (pass == 'TheMaster') {
|
||||
alert( 'Welcome!' );
|
||||
} else if (pass == null || pass == '') { // (*)
|
||||
alert( 'Canceled.' );
|
||||
} else {
|
||||
alert( 'Wrong password' );
|
||||
}
|
||||
|
||||
} else if (userName == null || userName == '') { // (**)
|
||||
|
||||
alert( 'Canceled' );
|
||||
|
||||
} else {
|
||||
|
||||
alert( "I don't know you" );
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Please note the `if` check in lines `(*)` and `(**)`. Every browser except Safari returns `null` when the input is canceled, and Safari returns an empty string. So we must treat them same for compatibility.
|
||||
|
||||
Also note the vertical indents inside the `if` blocks. They are technically not required, but make the code more readable.
|
|
@ -1,23 +0,0 @@
|
|||
importance: 3
|
||||
|
||||
---
|
||||
|
||||
# Check the login
|
||||
|
||||
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".
|
||||
|
||||
The password is checked as follows:
|
||||
|
||||
- If it equals "TheMaster", then show "Welcome!",
|
||||
- Another string -- show "Wrong password",
|
||||
- For an empty string or cancelled input, show "Canceled."
|
||||
|
||||
The schema:
|
||||
|
||||

|
||||
|
||||
Please use nested `if` blocks. Mind the overall readability of the code.
|
||||
|
||||
[demo]
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
|
||||
```js
|
||||
result = (a + b < 4) ? 'Below' : 'Over';
|
||||
```
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Rewrite 'if' into '?'
|
||||
|
||||
Rewrite this `if` using the ternary operator `'?'`:
|
||||
|
||||
```js
|
||||
if (a + b < 4) {
|
||||
result = 'Below';
|
||||
} else {
|
||||
result = 'Over';
|
||||
}
|
||||
```
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
|
||||
|
||||
```js
|
||||
let message = (login == 'Employee') ? 'Hello' :
|
||||
(login == 'Director') ? 'Greetings' :
|
||||
(login == '') ? 'No login' :
|
||||
'';
|
||||
```
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Rewrite 'if..else' into '?'
|
||||
|
||||
Rewrite `if..else` using multiple ternary operators `'?'`.
|
||||
|
||||
For readability, it's recommended to split the code span over lines.
|
||||
|
||||
```js
|
||||
let message;
|
||||
|
||||
if (login == 'Employee') {
|
||||
message = 'Hello';
|
||||
} else if (login == 'Director') {
|
||||
message = 'Greetings';
|
||||
} else if (login == '') {
|
||||
message = 'No login';
|
||||
} else {
|
||||
message = '';
|
||||
}
|
||||
```
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
# 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.
|
||||
|
||||
[cut]
|
||||
|
||||
## The "if" operator
|
||||
|
||||
The "if" operator gets a condition, evaluates it and -- if the result is `true` -- executes the code.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
||||
|
||||
*!*
|
||||
if (year == 2015) alert( 'You are right!' );
|
||||
*/!*
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```js
|
||||
if (year == 2015) {
|
||||
alert( "That's correct!" );
|
||||
alert( "You're so smart!" );
|
||||
}
|
||||
```
|
||||
|
||||
It is recommended to use figure brackets every time with `if`, even if there's only one command. That improves readability.
|
||||
|
||||
## Boolean conversion
|
||||
|
||||
The `if (…)` operator evaluates the condition in brackets and converts it to boolean type.
|
||||
|
||||
Let's recall the rules. In the logical context:
|
||||
|
||||
- A number `0`, an empty string `""`, `null`, `undefined` and `NaN` are `false`,
|
||||
- Other values -- `true`.
|
||||
|
||||
So, the code under this condition would never execute:
|
||||
|
||||
```js
|
||||
if (0) { // 0 is falsy
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
...And inside this condition -- always works:
|
||||
|
||||
```js
|
||||
if (1) { // 1 is truthy
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
We can also pass a pre-evaluated logical value to `if`, like here:
|
||||
|
||||
```js
|
||||
let cond = (year == 2015); // equality evaluates to true or false
|
||||
|
||||
if (cond) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## The "else" clause
|
||||
|
||||
The `if` operator may contain an optional "else" block. It executes when the condition is wrong.
|
||||
|
||||
For example:
|
||||
```js run
|
||||
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
||||
|
||||
if (year == 2015) {
|
||||
alert( 'You guessed it right!' );
|
||||
} else {
|
||||
alert( 'How can you be so wrong?' ); // any value except 2015
|
||||
}
|
||||
```
|
||||
|
||||
## Several conditions: "else if"
|
||||
|
||||
Sometimes we'd like to test several variants of a condition. There's an `else if` clause for that.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
|
||||
|
||||
if (year < 2015) {
|
||||
alert( 'Too early...' );
|
||||
} else if (year > 2015) {
|
||||
alert( 'Too late' );
|
||||
} else {
|
||||
alert( 'Exactly!' );
|
||||
}
|
||||
```
|
||||
|
||||
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 '?'
|
||||
|
||||
Sometimes we need to assign a variable depending on a condition.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run no-beautify
|
||||
let hasAccess;
|
||||
let age = prompt('How old are you?', '');
|
||||
|
||||
*!*
|
||||
if (age > 18) {
|
||||
hasAccess = true;
|
||||
} else {
|
||||
hasAccess = false;
|
||||
}
|
||||
*/!*
|
||||
|
||||
alert(hasAccess);
|
||||
```
|
||||
|
||||
The so called "ternary" or "question mark" operator allows to do that shorter and simpler.
|
||||
|
||||
The operator is represented by a question mark `"?"`. The formal term "ternary" means that the operator has 3 operands. It is actually the one and only operator in JavaScript which has that many.
|
||||
|
||||
The syntax is:
|
||||
```js
|
||||
let result = condition ? value1 : value2
|
||||
```
|
||||
|
||||
The `condition` is evaluated, if it's truthy then `value1` is returned, otherwise -- `value2`.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
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:
|
||||
|
||||
```js
|
||||
// the same
|
||||
let hasAccess = age > 18 ? true : false;
|
||||
```
|
||||
|
||||
...But brackets make the code more readable. So it's recommended to put them.
|
||||
|
||||
````smart
|
||||
In the described case it is possible to evade the question mark operator, because the comparison by itself returns `true/false`:
|
||||
|
||||
```js
|
||||
// the same
|
||||
let hasAccess = age > 18;
|
||||
```
|
||||
````
|
||||
|
||||
## Multiple '?'
|
||||
|
||||
A sequence of question mark `"?"` operators allows to return a value depending on more than one condition.
|
||||
|
||||
For instance:
|
||||
```js run
|
||||
let age = prompt('age?', 18);
|
||||
|
||||
let message = (age < 3) ? 'Hi, baby!' :
|
||||
(age < 18) ? 'Hello!' :
|
||||
(age < 100) ? 'Greetings!' :
|
||||
'What an unusual age!';
|
||||
|
||||
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.
|
||||
|
||||
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 logic using `if..else`:
|
||||
|
||||
```js
|
||||
if (age < 3) {
|
||||
message = 'Hi, baby!';
|
||||
} else if (a < 18) {
|
||||
message = 'Hello!';
|
||||
} else if (age < 100) {
|
||||
message = 'Greetings!';
|
||||
} else {
|
||||
message = 'What an unusual age!';
|
||||
}
|
||||
```
|
||||
|
||||
## Non-traditional use of '?'
|
||||
|
||||
Sometimes the question mark `'?'` is used as a replacement for `if`:
|
||||
|
||||
```js run no-beautify
|
||||
let company = prompt('Which company created JavaScript?', '');
|
||||
|
||||
*!*
|
||||
(company == 'Netscape') ?
|
||||
alert('Right!') : alert('Wrong.');
|
||||
*/!*
|
||||
```
|
||||
|
||||
Depending on the condition `company == 'Netscape'`, either the first or the second part after `"?"` gets executed and shows the alert.
|
||||
|
||||
We don't assign a result to a variable here, cause the `alert` doesn't return anything anyway, our purpose is only to execute it.
|
||||
|
||||
**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. But it is less readable.
|
||||
|
||||
Here's the same with `if` for comparison:
|
||||
|
||||
```js run no-beautify
|
||||
let company = prompt('Which company created JavaScript?', '');
|
||||
|
||||
*!*
|
||||
if (company == 'Netscape') {
|
||||
alert('Right!');
|
||||
} else {
|
||||
alert('Wrong.');
|
||||
}
|
||||
*/!*
|
||||
```
|
||||
|
||||
Our eyes scan the code vertically. The constructs which span several lines are easier to understand than a long horizontal instruction set.
|
||||
|
||||
The idea of a question mark `'?'` is to return one or another value depending on the condition. Please use it for exactly that. There's `if` to execute different branches of the code.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
The answer is `2`, that's the first truthy value.
|
||||
|
||||
```js run
|
||||
alert( null || 2 || undefined );
|
||||
```
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# What's the result of OR?
|
||||
|
||||
What the code below is going to output?
|
||||
|
||||
```js
|
||||
alert( null || 2 || undefined );
|
||||
```
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
The answer: first `1`, then `2`.
|
||||
|
||||
```js run
|
||||
alert( alert(1) || 2 || alert(3) );
|
||||
```
|
||||
|
||||
The call to `alert` does not return a value. Or, in other words, it returns `undefined`.
|
||||
|
||||
1. The first OR `||` evaluates it's left operand `alert(1)`. That shows the first message with `1`.
|
||||
2. The `alert` returns `undefined`, so OR goes on to the second operand in it's search of a truthy value.
|
||||
3. The second operand `2` is truthy, so the execution is halted, `2` is returned and then shown by the outer alert.
|
||||
|
||||
There will be no `3`, because the evaluation does not reach `alert(3)`.
|
|
@ -1,12 +0,0 @@
|
|||
importance: 3
|
||||
|
||||
---
|
||||
|
||||
# What's the result of OR'ed alerts?
|
||||
|
||||
What the code below will output?
|
||||
|
||||
```js
|
||||
alert( alert(1) || 2 || alert(3) );
|
||||
```
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
The answer: `null`, because it's the first falsy value from the list.
|
||||
|
||||
```js run
|
||||
alert( 1 && null && 2 );
|
||||
```
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# What is the result of AND?
|
||||
|
||||
What this code is going to show?
|
||||
|
||||
```js
|
||||
alert( 1 && null && 2 );
|
||||
```
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
The answer: `1`, and then `undefined`.
|
||||
|
||||
```js run
|
||||
alert( alert(1) && alert(2) );
|
||||
```
|
||||
|
||||
The call to `alert` returns `undefined` (it just shows a message, so there's no meaningful return).
|
||||
|
||||
Because of that, `&&` evaluates the left operand (outputs `1`), and immediately stops, because `undefined` is a falsy value. And `&&` looks for a falsy value and returns it, so it's done.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
importance: 3
|
||||
|
||||
---
|
||||
|
||||
# What is the result of AND'ed alerts?
|
||||
|
||||
What will this code show?
|
||||
|
||||
```js
|
||||
alert( alert(1) && alert(2) );
|
||||
```
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
The answer: `3`.
|
||||
|
||||
```js run
|
||||
alert( null || 2 && 3 || 4 );
|
||||
```
|
||||
|
||||
The precedence of AND `&&` is higher than `||`, so it executes first.
|
||||
|
||||
The result of `2 && 3 = 3`, so the expression becomes:
|
||||
|
||||
```
|
||||
null || 3 || 4
|
||||
```
|
||||
|
||||
Now the result if the first truthy value: `3`.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# The result of OR AND OR
|
||||
|
||||
What will be the result?
|
||||
|
||||
```js
|
||||
alert( null || 2 && 3 || 4 );
|
||||
```
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
|
||||
```js
|
||||
if (age >= 14 && age <= 90)
|
||||
```
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
importance: 3
|
||||
|
||||
---
|
||||
|
||||
# Check the range between
|
||||
|
||||
Write an "if" condition to check that `age` is between `14` and `90` inclusively.
|
||||
|
||||
"Inclusively" means that `age` can reach the edges `14` or `90`.
|
|
@ -1,12 +0,0 @@
|
|||
The first variant:
|
||||
|
||||
```js
|
||||
if (!(age >= 14 && age <= 90))
|
||||
```
|
||||
|
||||
The second variant:
|
||||
|
||||
```js
|
||||
if (age < 14 || age > 90)
|
||||
```
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
importance: 3
|
||||
|
||||
---
|
||||
|
||||
# Check the range outside
|
||||
|
||||
Write an `if` condition to check that `age` is NOT between 14 and 90 inclusively.
|
||||
|
||||
Create two variants: the first one using NOT `!`, the second one -- without it.
|
|
@ -1,20 +0,0 @@
|
|||
The answer: the first and the third will execute.
|
||||
|
||||
Details:
|
||||
|
||||
```js run
|
||||
// Runs.
|
||||
// The result of -1 || 0 = -1, truthy
|
||||
if (-1 || 0) alert( 'first' );
|
||||
|
||||
// Doesn't run
|
||||
// -1 && 0 = 0, falsy
|
||||
if (-1 && 0) alert( 'second' );
|
||||
|
||||
// Executes
|
||||
// Operator && has a higher precedence than ||
|
||||
// so -1 && 1 executes first, giving us the chain:
|
||||
// null || -1 && 1 -> null || 1 -> 1
|
||||
if (null || -1 && 1) alert( 'third' );
|
||||
```
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# A question about "if"
|
||||
|
||||
Which of these `alert`s are going to execute?
|
||||
|
||||
What will be the results of the expressions inside `if(...)`?
|
||||
|
||||
```js
|
||||
if (-1 || 0) alert( 'first' );
|
||||
if (-1 && 0) alert( 'second' );
|
||||
if (null || -1 && 1) alert( 'third' );
|
||||
```
|
||||
|
|
@ -1,308 +0,0 @@
|
|||
# Logical operators
|
||||
|
||||
There are three logical operators in JavaScript: `||` (OR), `&&` (AND), `!` (NOT).
|
||||
|
||||
Although they are called "logical", they can be applied to values of any type, not only boolean. The result can also be of any type.
|
||||
|
||||
Let's see the details.
|
||||
|
||||
[cut]
|
||||
|
||||
## || (OR)
|
||||
|
||||
The "OR" operator is represented with two vertical line symbols:
|
||||
|
||||
```js
|
||||
result = a || b;
|
||||
```
|
||||
|
||||
In classical programming, logical OR is meant to manipulate boolean values. If any of it's arguments is `true`, then it returns `true`, otherwise -- returns `false`.
|
||||
|
||||
In JavaScript the operator is a little bit more tricky and powerful. But first let's see what happens with logical values.
|
||||
|
||||
A table of possible logical combinations:
|
||||
|
||||
```js run
|
||||
alert( true || true ); // true
|
||||
alert( false || true ); // true
|
||||
alert( true || false ); // true
|
||||
alert( false || false ); // false
|
||||
```
|
||||
|
||||
As we can see, the result is always `true` except for the case when both operands are `false`.
|
||||
|
||||
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`:
|
||||
|
||||
```js run
|
||||
if (1 || 0) { // works just like if( true || false )
|
||||
alert( 'truthy!' );
|
||||
}
|
||||
```
|
||||
|
||||
Most of time, OR `||` is used in the `if` expression to test if *any* of given conditions is correct.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
let hour = 9;
|
||||
|
||||
*!*
|
||||
if (hour < 10 || hour > 18) {
|
||||
*/!*
|
||||
alert( 'The office is closed.' );
|
||||
}
|
||||
```
|
||||
|
||||
We can pass more conditions:
|
||||
|
||||
```js run
|
||||
let hour = 12;
|
||||
let isWeekend = true;
|
||||
|
||||
if (hour < 10 || hour > 18 || isWeekend) {
|
||||
alert( 'The office is closed.' ); // it is weekend
|
||||
}
|
||||
```
|
||||
|
||||
## OR seeks the first truthy value
|
||||
|
||||
The logic described above is somewhat classical. Now let's bring in the "extra" features of JavaScipt.
|
||||
|
||||
The extended algorithm works as follows.
|
||||
|
||||
Given multiple OR'ed values:
|
||||
|
||||
```js
|
||||
result = value1 || value2 || value3;
|
||||
```
|
||||
|
||||
The OR `"||"` operator is doing the following:
|
||||
|
||||
- Evalutes operands from left to right.
|
||||
- For each value converts it to boolean and stops immediately returning it if it's true.
|
||||
- The value is returned in it's original form, without the conversion.
|
||||
|
||||
In other words, it returns the first truthy value or the last one if no such value found.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
alert( 1 || 0 ); // 1 (is truthy)
|
||||
alert( true || 'no matter what' ); // (true is truthy)
|
||||
|
||||
alert( null || 1 ); // 1 (1 is the first truthy)
|
||||
alert( null || 0 || 1 ); // 1 (the first truthy)
|
||||
alert( undefined || null || 0 ); // 0 (all falsy, returns the last value)
|
||||
```
|
||||
|
||||
This logic does not contradict to what was spoken above. If you check this behavior with the boolean table, you see that it still works the same.
|
||||
|
||||
But there leads to some interesting usages compared to a "pure, classical, boolean-only OR".
|
||||
|
||||
1. **Getting the first truthy value from the list of variables or expressions.**
|
||||
|
||||
Imagine we have several variables, which can either contain the data or be `null/undefined`. And we need to choose the first one with data.
|
||||
|
||||
Using OR `||` for that:
|
||||
|
||||
```js run
|
||||
let currentUser = null;
|
||||
let defaultUser = "John";
|
||||
|
||||
*!*
|
||||
let name = currentUser || defaultUser || "unnamed";
|
||||
*/!*
|
||||
|
||||
alert( name ); // selects "John" – the first truthy value
|
||||
```
|
||||
|
||||
If both `currentUser` and `defaultUser` were falsy then `"unnamed"` would be the result.
|
||||
2. **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.
|
||||
|
||||
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` would not get assigned:
|
||||
|
||||
```js run no-beautify
|
||||
let x;
|
||||
|
||||
*!*true*/!* || (x = 1);
|
||||
|
||||
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:
|
||||
|
||||
```js run no-beautify
|
||||
let x;
|
||||
|
||||
*!*false*/!* || (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 do `if`". The first operand is converted to boolean and if it's false then the second one is evaluated.
|
||||
|
||||
Most of time it's better to use `if` for that for code clarity.
|
||||
|
||||
## && (AND)
|
||||
|
||||
The AND operator is represented with two ampersands `&&`:
|
||||
|
||||
```js
|
||||
result = a && b;
|
||||
```
|
||||
|
||||
In classic programming AND returns `true` if both operands are truthy and `false` -- otherwise:
|
||||
|
||||
```js run
|
||||
alert( true && true ); // true
|
||||
alert( false && true ); // false
|
||||
alert( true && false ); // false
|
||||
alert( false && false ); // false
|
||||
```
|
||||
|
||||
An example with `if`:
|
||||
|
||||
```js run
|
||||
let hour = 12;
|
||||
let minute = 30;
|
||||
|
||||
if (hour == 12 && minute == 30) {
|
||||
alert( 'Time is 12:30' );
|
||||
}
|
||||
```
|
||||
|
||||
Just as for OR, any value is allowed as an operand of AND and gets converted to a boolean in the process:
|
||||
|
||||
```js run
|
||||
if (1 && 0) { // evaluated as true && false
|
||||
alert( "won't work, because the result is falsy" );
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## AND seeks the first falsy value
|
||||
|
||||
Given multiple AND'ed values:
|
||||
|
||||
```js
|
||||
result = value1 && value2 && value3;
|
||||
```
|
||||
|
||||
The AND `"&&"` operator is doing the following:
|
||||
|
||||
- Evalutes operands from left to right.
|
||||
- For each value converts it to a boolean. If the result is `false`, stops and returns it without conversion.
|
||||
- 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.
|
||||
|
||||
Examples:
|
||||
|
||||
```js run
|
||||
// if the first operand is truthy,
|
||||
// && returns the second one.
|
||||
alert( 1 && 0 ); // 0
|
||||
alert( 1 && 5 ); // 5
|
||||
|
||||
// now the first operand is falsy,
|
||||
// it is returned, and the second one is ignored
|
||||
alert( null && 5 ); // null
|
||||
alert( 0 && "no matter what" ); // 0
|
||||
```
|
||||
|
||||
We can also pass several values in a row. See how the first falsy one is returned:
|
||||
|
||||
```js run
|
||||
alert( 1 && 2 && null && 3 ); // null
|
||||
```
|
||||
|
||||
...And now when all of them are truthy:
|
||||
|
||||
```js run
|
||||
alert( 1 && 2 && 3 ); // 3, the last one
|
||||
```
|
||||
|
||||
````smart header="AND `&&` 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:
|
||||
|
||||
```js run
|
||||
alert( 5 || 1 && 0 ); // 5
|
||||
```
|
||||
````
|
||||
|
||||
Just like OR, the AND `&&` operator can sometimes replace `if`.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
let x = 1;
|
||||
|
||||
(x > 0) && alert( 'Greater than zero!' );
|
||||
```
|
||||
|
||||
The action in the right part of `&&` would execute only if the evaluation reaches it. That is: only if `(x > 0)` is true.
|
||||
|
||||
So we basically have an analogue for:
|
||||
|
||||
```js run
|
||||
let x = 1;
|
||||
|
||||
if (x > 0) {
|
||||
alert( 'Greater than zero!' );
|
||||
}
|
||||
```
|
||||
|
||||
The variant with `&&` appears to be shorter. But `if` is more obvious and tends to be a little bit more readable.
|
||||
|
||||
So it is recommended to use every construct for it's purpose. Use `if` if we want if. And use `&&` if we want AND.
|
||||
|
||||
## ! (NOT)
|
||||
|
||||
The boolean NOT operator is represented with an exclamation sign `"!"`.
|
||||
|
||||
The syntax is one of the simplest:
|
||||
|
||||
```js
|
||||
result = !value;
|
||||
```
|
||||
|
||||
The operator accepts a single argument and does the following:
|
||||
|
||||
1. Converts the operand to boolean type: `true/false`.
|
||||
2. Returns an inverse value.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
alert( !true ); // false
|
||||
alert( !0 ); // true
|
||||
```
|
||||
|
||||
A double NOT is sometimes used for converting a value to boolean type:
|
||||
|
||||
```js run
|
||||
alert( !!"non-empty string" ); // true
|
||||
alert( !!null ); // false
|
||||
```
|
||||
|
||||
That is: the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again, so we have a plain value-to-boolean conversion.
|
||||
|
||||
There's a little more verbose to do the same -- a built-in `Boolean` function:
|
||||
|
||||
```js run
|
||||
alert( Boolean("non-empty string") ); // true
|
||||
alert( Boolean(null) ); // false
|
||||
```
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
The answer: `1`.
|
||||
|
||||
```js run
|
||||
let i = 3;
|
||||
|
||||
while (i) {
|
||||
alert( i-- );
|
||||
}
|
||||
```
|
||||
|
||||
Every loop iteration decreases `i` by `1`. The check `while(i)` stops the loop when `i = 0`.
|
||||
|
||||
Hence, the steps of the loop make the following sequence ("loop unrolled"):
|
||||
|
||||
```js
|
||||
let i = 3;
|
||||
|
||||
alert(i--); // shows 3, decreases i to 2
|
||||
|
||||
alert(i--) // shows 2, decreases i to 1
|
||||
|
||||
alert(i--) // shows 1, decreases i to 0
|
||||
|
||||
// done, while(i) check stops the loop
|
||||
```
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
importance: 3
|
||||
|
||||
---
|
||||
|
||||
# Last loop value
|
||||
|
||||
What is be the last value alerted by this code? Why?
|
||||
|
||||
```js
|
||||
let i = 3;
|
||||
|
||||
while (i) {
|
||||
alert( i-- );
|
||||
}
|
||||
```
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
The task demonstrates how postfix/prefix forms can lead to different results when used in comparisons.
|
||||
|
||||
1. **From 1 to 4**
|
||||
|
||||
```js run
|
||||
let i = 0;
|
||||
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`.
|
||||
|
||||
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.
|
||||
2. **From 1 to 5**
|
||||
|
||||
```js run
|
||||
let i = 0;
|
||||
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`).
|
||||
|
||||
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…`
|
||||
|
||||
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.
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
importance: 4
|
||||
|
||||
---
|
||||
|
||||
# Which values shows the while?
|
||||
|
||||
For every loop, scribe down which values it shows, in your opinion.
|
||||
|
||||
And then compare with the answer.
|
||||
|
||||
1. The prefix form `++i`:
|
||||
|
||||
```js
|
||||
let i = 0;
|
||||
while (++i < 5) alert( i );
|
||||
```
|
||||
2. The postfix form `i++`
|
||||
|
||||
```js
|
||||
let i = 0;
|
||||
while (i++ < 5) alert( i );
|
||||
```
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
**The answer: from `0` to `4` in both cases.**
|
||||
|
||||
```js run
|
||||
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`:
|
||||
|
||||
1. Execute once `i=0` before everything.
|
||||
2. Check the condition `i<5`
|
||||
3. If `true` -- execute the loop body `alert(i)`, and then `i++`
|
||||
|
||||
The increment `i++` is separated from the condition check (2). That's just another statement.
|
||||
|
||||
The value returned by the increment is not used here, so there's no difference between `i++` and `++i`.
|
|
@ -1,21 +0,0 @@
|
|||
importance: 4
|
||||
|
||||
---
|
||||
|
||||
# Which values get shown by the "for" loop?
|
||||
|
||||
For each loop scribe down which values it is going to show.
|
||||
|
||||
Then compare with the answer.
|
||||
|
||||
1. The postfix form:
|
||||
|
||||
```js
|
||||
for (let i = 0; i < 5; i++) alert( i );
|
||||
```
|
||||
2. The prefix form:
|
||||
|
||||
```js
|
||||
for (let i = 0; i < 5; ++i) alert( i );
|
||||
```
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
|
||||
```js run demo
|
||||
for (let i = 2; i <= 10; i++) {
|
||||
if (i % 2 == 0) {
|
||||
alert( i );
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We use the "modulo" operator `%` to get the remainder and check for the evenness here.
|
|
@ -1,9 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Output even numbers in the loop
|
||||
|
||||
Use the `for` loop to output even numbers from `2` to `10`.
|
||||
|
||||
[demo]
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
|
||||
```js run
|
||||
let i = 0;
|
||||
while (i < 3) {
|
||||
alert( `number ${i}!` );
|
||||
i++;
|
||||
}
|
||||
```
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
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).
|
||||
|
||||
```js run
|
||||
for (let i = 0; i < 3; i++) {
|
||||
alert( `number ${i}!` );
|
||||
}
|
||||
```
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
```js run demo
|
||||
let num;
|
||||
|
||||
do {
|
||||
num = prompt("Enter a number greater than 100?", 0);
|
||||
} while (num <= 100 && num);
|
||||
```
|
||||
|
||||
The loop `do..while` repeats while both checks are truthy:
|
||||
|
||||
1. The check for `num <= 100` -- that is, the entered value is still not greater than `100`.
|
||||
2. The check for a truthiness of `num` checks that `num != null` and `num != ""` simultaneously.
|
||||
|
||||
P.S. By the way, if `num` is `null` then `num <= 100` would return `false`, not `true`!
|
|
@ -1,14 +0,0 @@
|
|||
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.
|
||||
|
||||
The loop must ask for a number until either the visitor enters a number greater than `100` or cancels the input/enters an empty line.
|
||||
|
||||
Here we can assume that the visitor only inputs numbers. There's no need to implement the special handling for a non-numeric input in this task.
|
||||
|
||||
[demo]
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
There are many algorithms for this task.
|
||||
|
||||
Let's use a nested loop:
|
||||
|
||||
```js
|
||||
For each i in the interval {
|
||||
check if i has a divisor from 1..i
|
||||
if yes => the value is not a prime
|
||||
if no => the value is a prime, show it
|
||||
}
|
||||
```
|
||||
|
||||
The code using a label:
|
||||
|
||||
```js run
|
||||
nextPrime:
|
||||
for (let i = 2; i < 10; i++) { // for each i...
|
||||
|
||||
for (let j = 2; j < i; j++) { // look for a divisor..
|
||||
if (i % j == 0) continue nextPrime; // not a prime, go next i
|
||||
}
|
||||
|
||||
alert( i ); // a prime
|
||||
}
|
||||
```
|
||||
|
||||
Surely, there's a lot of space to opimize it. Like, we could look for the divisors from `2` to square root of `i`. But anyway, if we want to be really efficient for large intervals, we need change the approach and rely heavily on advanced maths and algorithms like [Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve) etc.
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
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.
|
||||
|
||||
In other words, `n>1` is a prime if the result of it's division by anything except `1` and `n` is not integer.
|
||||
|
||||
For example, `5` is a prime, because it cannot be divided without a remainder by `2`, `3` and `4`.
|
||||
|
||||
**Write the code which outputs prime numbers in the interval from `2` to `10`.**
|
||||
|
||||
The result will be `2,3,5,7`.
|
||||
|
||||
P.S. The code should be easily modifiable for other intervals.
|
||||
|
|
@ -1,371 +0,0 @@
|
|||
# Loops: while and for
|
||||
|
||||
We often have a need to perform similar actions many times in a row.
|
||||
|
||||
For example, when we need to output goods from the list one after another. Or just run the same code for each number from 1 to 10.
|
||||
|
||||
*Loops* are a way to repeat the same part of code multiple times.
|
||||
|
||||
[cut]
|
||||
|
||||
## The "while" loop
|
||||
|
||||
The `while` loop has the following syntax:
|
||||
|
||||
```js
|
||||
while (condition) {
|
||||
// code ("loop body")
|
||||
}
|
||||
```
|
||||
|
||||
While the `condition` is `true` -- the `code` from the loop body is executed.
|
||||
|
||||
For instance, the loop below outputs `i` while `i<3`:
|
||||
|
||||
```js run
|
||||
let i = 0;
|
||||
while (i < 3) { // shows 0, then 1, then 2
|
||||
alert( i );
|
||||
i++;
|
||||
}
|
||||
```
|
||||
|
||||
There's a special term *iteration* for each loop run. The loop in the example above makes 3 iterations.
|
||||
|
||||
If there were no `i++` in the example above, the loop would repeat (in theory) forever, eating 100% CPU. In practice, the browser would show a message about a "hanging" script and let the user stop it.
|
||||
|
||||
The `while` converts `condition` to a logical value. It can be any expression, not just a comparison.
|
||||
|
||||
For instance, the shorter way to write `while (i!=0)` could be `while (i)`:
|
||||
|
||||
```js run
|
||||
let i = 3;
|
||||
*!*
|
||||
while (i) { // when i becomes 0, the condition is falsy and the loop stops
|
||||
*/!*
|
||||
alert( i );
|
||||
i--;
|
||||
}
|
||||
```
|
||||
|
||||
````smart header="Brackes are not required for a single-line body"
|
||||
If the loop body has a single statement, we can omit the brackets `{…}`:
|
||||
|
||||
```js run
|
||||
let i = 3;
|
||||
*!*
|
||||
while (i) alert(i--);
|
||||
*/!*
|
||||
```
|
||||
````
|
||||
|
||||
## The "do..while" loop
|
||||
|
||||
The condition check can be moved *below* the loop body using the `do..while` syntax:
|
||||
|
||||
```js
|
||||
do {
|
||||
// loop body
|
||||
} while (condition);
|
||||
```
|
||||
|
||||
The loop will first execute the body and then check the condition.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
let i = 0;
|
||||
do {
|
||||
alert( i );
|
||||
i++;
|
||||
} while (i < 3);
|
||||
```
|
||||
|
||||
This form of syntax is rarely used, because the ordinary `while` is more obvious. We don't need to scroll down the code looking for the condition.
|
||||
|
||||
## The "for" loop
|
||||
|
||||
The `for` loop is actually the most often used one.
|
||||
|
||||
It looks like this:
|
||||
|
||||
```js
|
||||
for (begin; condition; step) {
|
||||
// ... loop body ...
|
||||
}
|
||||
```
|
||||
|
||||
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 run
|
||||
let i;
|
||||
|
||||
for (i = 0; i < 3; i++) { // shows 0, then 1, then 2
|
||||
alert( i );
|
||||
}
|
||||
```
|
||||
|
||||
Let's split the last example into parts:
|
||||
|
||||
begin: `i=0`
|
||||
: Executes once upon entering the loop.
|
||||
|
||||
condition: `i<3`
|
||||
: Checked before every loop iteration, if fails the loop stops.
|
||||
|
||||
body: `alert(i)`
|
||||
: Runs again and again while the condition is truthy
|
||||
|
||||
step: `i++`
|
||||
: Executes after the body on each iteration, but before the condition check.
|
||||
|
||||
The execution flow is:
|
||||
```
|
||||
Begin
|
||||
→ (if condition → run body and run step)
|
||||
→ (if condition → run body and run step)
|
||||
→ ... repeat until the condition is falsy.
|
||||
```
|
||||
|
||||
````smart header="Inline variable declaration"
|
||||
We can declare a "counter" variable right in the beginning of the loop.
|
||||
|
||||
```js run no-beautify
|
||||
for (*!*let*/!* i = 0; i < 3; i++) {
|
||||
alert(i); // 0, 1, 2
|
||||
}
|
||||
```
|
||||
|
||||
The variable will be visible only inside the loop.
|
||||
````
|
||||
|
||||
## Skipping parts
|
||||
|
||||
Any part of the `for` can be skipped.
|
||||
|
||||
For example, we can omit `begin` if we don't need to do anything at the loop start.
|
||||
|
||||
Like here:
|
||||
|
||||
```js run
|
||||
let i = 0;
|
||||
|
||||
for (; i < 3; i++) {
|
||||
alert( i ); // 0, 1, 2
|
||||
}
|
||||
```
|
||||
|
||||
It would work same as `for(let i=0; ...)`.
|
||||
|
||||
We can also remove the `step` part:
|
||||
|
||||
```js run
|
||||
let i = 0;
|
||||
|
||||
for (; i < 3;) {
|
||||
alert( i );
|
||||
// the loop became identical to while (i<3)
|
||||
}
|
||||
```
|
||||
|
||||
We can actually remove everything, thus creating an infinite loop:
|
||||
|
||||
```js
|
||||
for (;;) {
|
||||
// repeats without limits
|
||||
}
|
||||
```
|
||||
|
||||
Please note that the semicolons `;` must present, otherwise it would be a syntax error.
|
||||
|
||||
```smart header="`for..in` and `for..of`"
|
||||
There are special constructs: `for..in` and `for..of` for more advanced iterations over objects.
|
||||
|
||||
We'll get to them later, in chapters about objects.
|
||||
```
|
||||
|
||||
## Breaking the loop
|
||||
|
||||
Normally the loop exists when the condition becomes falsy.
|
||||
|
||||
But we can force the exit at any moment. There's a special `break` directive for that.
|
||||
|
||||
For example, this code below asks user for numbers and breaks if no number entered:
|
||||
|
||||
```js
|
||||
let sum = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
let value = +prompt("Enter a number", '');
|
||||
|
||||
*!*
|
||||
if (!value) break; // (*)
|
||||
*/!*
|
||||
|
||||
sum += value;
|
||||
|
||||
}
|
||||
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 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]
|
||||
|
||||
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.
|
||||
|
||||
The loop above uses `continue` to output only odd values:
|
||||
|
||||
```js run no-beautify
|
||||
for (let i = 0; i < 10; i++) {
|
||||
|
||||
// if true, skip the remaining part of the body
|
||||
*!*if (i % 2 == 0) continue;*/!*
|
||||
|
||||
alert(i); // 1, then 3, 5, 7, 9
|
||||
}
|
||||
```
|
||||
|
||||
For even values of `i` the `continue` directive stops body execution, passing the control to the next iteration of `for` (with the next number). So the `alert` is only called for odd values.
|
||||
|
||||
````smart header="The directive `continue` helps to decrease nesting level"
|
||||
A loop for odd-only values could look like this:
|
||||
|
||||
```js
|
||||
for (let i = 0; i < 10; i++) {
|
||||
|
||||
if (i % 2) {
|
||||
alert( i );
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
````
|
||||
|
||||
````warn header="No `break/continue` to the right side of '?'"
|
||||
Please note that syntax constructs that are not expressions cannot be used in `'?'`. In particular, directives `break/continue` are disallowed there.
|
||||
|
||||
For example, if one we took this code:
|
||||
|
||||
```js
|
||||
if (i > 5) {
|
||||
alert(i);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
```
|
||||
|
||||
...And rewrote it using a question mark:
|
||||
|
||||
|
||||
```js no-beautify
|
||||
(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`.
|
||||
````
|
||||
|
||||
## Labels for break/continue
|
||||
|
||||
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)`:
|
||||
|
||||
```js run no-beautify
|
||||
for (let i = 0; i < 3; i++) {
|
||||
|
||||
for (let j = 0; j < 3; j++) {
|
||||
|
||||
let input = prompt(`Value at coords (${i},${j})`, '');
|
||||
|
||||
// what if I want to exit from here?
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
alert('Done!');
|
||||
```
|
||||
|
||||
Let's say we need a way to stop the process. Like if we user decides to cancel the input.
|
||||
|
||||
The ordinary `break` after `input` would only break the inner loop. That's not sufficient. Labels come to the rescue.
|
||||
|
||||
A *label* is an identifier with a colon before a loop:
|
||||
```js
|
||||
labelName: for(...) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
We can put the `labelName` after a break statement, and it will break out of the labelled loop.
|
||||
|
||||
Like here:
|
||||
|
||||
```js run no-beautify
|
||||
*!*outer:*/!* for (let i = 0; i < 3; i++) {
|
||||
|
||||
for (let j = 0; j < 3; j++) {
|
||||
|
||||
let input = prompt(`Value at coords (${i},${j})`, '');
|
||||
|
||||
// if an empty string or canceled, then break out of both loops
|
||||
if (!input) *!*break outer*/!*; // (*)
|
||||
|
||||
// do something with the value...
|
||||
}
|
||||
}
|
||||
alert('Done!');
|
||||
```
|
||||
|
||||
In the code above `break outer` looks upwards for the label named `outer` and breaks out of that loop.
|
||||
|
||||
So the control goes straight from `(*)` to `alert('Done!')`.
|
||||
|
||||
We can also move a label into the separate string:
|
||||
|
||||
```js no-beautify
|
||||
outer:
|
||||
for (let i = 0; i < 3; i++) { ... }
|
||||
```
|
||||
|
||||
The `continue` directive can also be used with a label. In this case the execution would jump onto the next iteration of the labelled loop.
|
||||
|
||||
````warn header="Labels are not a \"goto\""
|
||||
Labels do not allow to jump into an arbitrary place of code.
|
||||
|
||||
For example, it is impossible to do like this:
|
||||
```js
|
||||
break label; // jumps to label? No.
|
||||
|
||||
label: for(...)
|
||||
```
|
||||
|
||||
The call to a `break/continue` is only possible from inside the loop, and the label must be somewhere upwards from the directive.
|
||||
````
|
||||
|
||||
## Summary
|
||||
|
||||
There are 3 types of loops in JavaScript:
|
||||
|
||||
- `while` -- the condition is checked before each iteration.
|
||||
- `do..while` -- the condition is checked after each iteration.
|
||||
- `for` -- the condition is checked before each iteration, additional settings available.
|
||||
|
||||
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.
|
||||
|
||||
If we don't want to do anything more on this iteration and would like to forward on to the next one -- the `continue` directive does it.
|
||||
|
||||
`Break/continue` support labels before the loop. A label is the only way for `break/continue` to escape the nesting and go to the outer loop.
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
To be precise, the `if` must use a strict comparison `'==='`.
|
||||
|
||||
In reality though, probably a simple `'=='` would do.
|
||||
|
||||
```js no-beautify
|
||||
if(browser == 'Edge') {
|
||||
alert("You've got the Edge!");
|
||||
} else if (browser == 'Chrome'
|
||||
|| browser == 'Firefox'
|
||||
|| browser == 'Safari'
|
||||
|| browser == 'Opera') {
|
||||
alert( 'Okay we support these browsers too' );
|
||||
} else {
|
||||
alert( 'We hope that this page looks ok!' );
|
||||
}
|
||||
```
|
||||
|
||||
Please note: the construct `browser == 'Chrome' || browser == 'Firefox' …` is split into multiple lines for better readability.
|
||||
|
||||
But the `switch` is still neater and more descriptive.
|
|
@ -1,26 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Rewrite the "switch" into an "if"
|
||||
|
||||
Write the code using `if..else` which would correspond to the following `switch`:
|
||||
|
||||
```js
|
||||
switch (browser) {
|
||||
case 'Edge':
|
||||
alert( "You've got the Edge!" );
|
||||
break;
|
||||
|
||||
case 'Chrome':
|
||||
case 'Firefox':
|
||||
case 'Safari':
|
||||
case 'Opera':
|
||||
alert( 'Okay we support these browsers too' );
|
||||
break;
|
||||
|
||||
default:
|
||||
alert( 'We hope that this page looks ok!' );
|
||||
}
|
||||
```
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
The first two checks are a usual `case`. The third one is split into two cases:
|
||||
|
||||
```js run
|
||||
let a = +prompt('a?', '');
|
||||
|
||||
switch (a) {
|
||||
case 0:
|
||||
alert( 0 );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
alert( 1 );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
alert( '2,3' );
|
||||
*!*
|
||||
break;
|
||||
*/!*
|
||||
}
|
||||
```
|
||||
|
||||
Please note: the `break` at the bottom is not required. But we put it to make the code future-proof.
|
||||
|
||||
In the future, there is a chance that we'd want to add one more `case`, for example `case 4`. And if we forget to add a break before it, at the end of `case 3`, there will be an error. So that's a kind of self-insurance.
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
importance: 4
|
||||
|
||||
---
|
||||
|
||||
# Rewrite "if" into "switch"
|
||||
|
||||
Rewrite the code below using a single `switch` statement:
|
||||
|
||||
```js run
|
||||
let a = +prompt('a?', '');
|
||||
|
||||
if (a == 0) {
|
||||
alert( 0 );
|
||||
}
|
||||
if (a == 1) {
|
||||
alert( 1 );
|
||||
}
|
||||
|
||||
if (a == 2 || a == 3) {
|
||||
alert( '2,3' );
|
||||
}
|
||||
```
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
# The "switch" statement
|
||||
|
||||
A `switch` statement can replace multiple `if` checks.
|
||||
|
||||
It gives a more descriptive way to compare a value with multiple variants.
|
||||
|
||||
[cut]
|
||||
|
||||
## The syntax
|
||||
|
||||
It looks like this:
|
||||
|
||||
```js no-beautify
|
||||
switch(x) {
|
||||
case 'value1': // if (x === 'value1')
|
||||
...
|
||||
[break]
|
||||
|
||||
case 'value2': // if (x === 'value2')
|
||||
...
|
||||
[break]
|
||||
|
||||
default:
|
||||
...
|
||||
[break]
|
||||
}
|
||||
```
|
||||
|
||||
- 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`).
|
||||
- If no case matched then the `default` code is executed (if exists).
|
||||
|
||||
## An example
|
||||
|
||||
An example of `switch` (the executed code is highlighted):
|
||||
|
||||
```js run
|
||||
let a = 2 + 2;
|
||||
|
||||
switch (a) {
|
||||
case 3:
|
||||
alert( 'Too small' );
|
||||
break;
|
||||
*!*
|
||||
case 4:
|
||||
alert( 'Exactly!' );
|
||||
break;
|
||||
*/!*
|
||||
case 5:
|
||||
alert( 'Too large' );
|
||||
break;
|
||||
default:
|
||||
alert( "I don't know such values" );
|
||||
}
|
||||
```
|
||||
|
||||
Here the `switch` starts to compare `a` from the first `case` variant that is `3`. The match fails.
|
||||
|
||||
Then `4`. That's the match, so the execution starts from `case 4` and till the nearest `break`.
|
||||
|
||||
**If there is no `break` then the execution continues with the next `case` without any checks.**
|
||||
|
||||
An example without `break`:
|
||||
|
||||
```js run
|
||||
let a = 2 + 2;
|
||||
|
||||
switch (a) {
|
||||
case 3:
|
||||
alert( 'Too small' );
|
||||
*!*
|
||||
case 4:
|
||||
alert( 'Exactly!' );
|
||||
case 5:
|
||||
alert( 'Too big' );
|
||||
default:
|
||||
alert( "I don't know such values" );
|
||||
*/!*
|
||||
}
|
||||
```
|
||||
|
||||
In the example above we'll see sequential execution of three `alert`s:
|
||||
|
||||
```js
|
||||
alert( 'Exactly!' );
|
||||
alert( 'Too big' );
|
||||
alert( "I don't know such values" );
|
||||
```
|
||||
|
||||
````smart header="Any expresion can be a `switch/case` argument"
|
||||
Both `switch` and case allow arbitrary expresions.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
let a = "1";
|
||||
let b = 0;
|
||||
|
||||
switch (+a) {
|
||||
*!*
|
||||
case b + 1:
|
||||
alert( 1 );
|
||||
break;
|
||||
*/!*
|
||||
|
||||
default:
|
||||
alert('no-no, see the code above, it executes');
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
## Grouping of "case"
|
||||
|
||||
Several variants of `case` can be grouped.
|
||||
|
||||
For example, if we want the same code for `case 3` and `case 5`:
|
||||
|
||||
```js run no-beautify
|
||||
let a = 2 + 2;
|
||||
|
||||
switch (a) {
|
||||
case 4:
|
||||
alert('Right!');
|
||||
break;
|
||||
|
||||
*!*
|
||||
case 3: // (*)
|
||||
case 5:
|
||||
alert('Wrong!');
|
||||
alert('How about to take maths classes?');
|
||||
break;
|
||||
*/!*
|
||||
|
||||
default:
|
||||
alert('The result is strange. Really.');
|
||||
}
|
||||
```
|
||||
|
||||
The grouping is just a side-effect of how `switch/case` works without `break`. Here the execution of `case 3` starts from the line `(*)` and goes through `case 5`, because there's no `break`.
|
||||
|
||||
## The type matters
|
||||
|
||||
Let's emphase that the equality check is always strict. The values must be of the same type to match.
|
||||
|
||||
For example, let's consider the code:
|
||||
|
||||
```js run
|
||||
let arg = prompt("Enter a value?")
|
||||
switch (arg) {
|
||||
case '0':
|
||||
case '1':
|
||||
alert( 'One or zero' );
|
||||
|
||||
case '2':
|
||||
alert( 'Two' );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
alert( 'Never executes!' );
|
||||
|
||||
default:
|
||||
alert( 'An unknown value' )
|
||||
}
|
||||
```
|
||||
|
||||
1. For `0`, `1`, the first `alert` runs.
|
||||
2. For `2` the second `alert` runs.
|
||||
3. But for `3`, the result of the `prompt` is a string `"3"`, which is not strictly equal `===` to the number `3`. So we've got a dead code in `case 3`! The `default` variant will execite.
|
||||
|
|
@ -1 +0,0 @@
|
|||
alert("I'm JavaScript!");
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
|
||||
<script src="alert.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,8 +0,0 @@
|
|||
The HTML code:
|
||||
|
||||
[html src="index.html"]
|
||||
|
||||
For the file `alert.js` in the same folder:
|
||||
|
||||
[js src="alert.js"]
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Show an alert with an external script
|
||||
|
||||
Take the solution of the previous task <info:task/hello-alert>. Modify it by extracting the script content into an external file `alert.js`, residing in the same folder.
|
||||
|
||||
Open the page, ensures that the alert works.
|
|
@ -1,5 +0,0 @@
|
|||
Answers:
|
||||
|
||||
1. The first is `big.js`, that's a normal sequence for external `<script>` tags.
|
||||
2. The first is `small.js`, because `async` makes script behave independently of each other and the page. The first to loads runs first.
|
||||
3. The first is `big.js`, because "deferred" scripts keep relative execution order.
|
|
@ -1,29 +0,0 @@
|
|||
importance: 4
|
||||
|
||||
---
|
||||
|
||||
# Which script executes first?
|
||||
|
||||
In the questions below, there are two scripts: `small.js` and `big.js`.
|
||||
|
||||
If we assume that `small.js` loads much faster compared to `big.js` -- which script executes first?
|
||||
|
||||
```html
|
||||
<script src="big.js"></script>
|
||||
<script src="small.js"></script>
|
||||
```
|
||||
|
||||
What if we add `async`?
|
||||
|
||||
```html
|
||||
<script async src="big.js"></script>
|
||||
<script async src="small.js"></script>
|
||||
```
|
||||
|
||||
What if we switch to `defer`?
|
||||
|
||||
```html
|
||||
<script defer src="big.js"></script>
|
||||
<script defer src="small.js"></script>
|
||||
```
|
||||
|
|
@ -1,270 +0,0 @@
|
|||
# External scripts
|
||||
|
||||
If we have a lot of JavaScript code, we can it put it into a separate file.
|
||||
|
||||
The script file is attached to HTML like this:
|
||||
|
||||
```html
|
||||
<script src="/path/to/script.js"></script>
|
||||
```
|
||||
|
||||
Here `/path/to/script.js` is an absolute path to the file with the script (from the site root).
|
||||
|
||||
It is also possible to provide a path relative to the current page. For instance, `src="script.js"` would mean a file `"script.js"` from the current folder.
|
||||
|
||||
We can give a full URL al well, for instance:
|
||||
|
||||
```html
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||
```
|
||||
|
||||
To attach several scripts, use multiple tags:
|
||||
|
||||
```html
|
||||
<script src="/js/script1.js"></script>
|
||||
<script src="/js/script2.js"></script>
|
||||
…
|
||||
```
|
||||
|
||||
```smart
|
||||
As a rule, only 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).
|
||||
|
||||
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.
|
||||
```
|
||||
|
||||
````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.
|
||||
|
||||
This won't work:
|
||||
|
||||
```html
|
||||
<script *!*src*/!*="file.js">
|
||||
alert(1); // the content is ignored, because src is set
|
||||
</script>
|
||||
```
|
||||
|
||||
We must choose: either it's an external `<script src="…">` or a regular `<script>` with code.
|
||||
|
||||
The example above can be split into two scripts to work:
|
||||
|
||||
```html
|
||||
<script src="file.js"></script>
|
||||
<script>
|
||||
alert(1);
|
||||
</script>
|
||||
```
|
||||
````
|
||||
|
||||
## Asynchronous scripts: defer/async
|
||||
|
||||
Browser loads and shows HTML gradually as it comes. That's clearly noticeable on the slow internet connection. The browser doesn't wait for the page to load fully. It shows the part that has been loaded already, and then adds content to it as it loads.
|
||||
|
||||
As we noted before, when the browser meets a `<script>` tag, it must execute it first and after that show the rest of the page.
|
||||
|
||||
For example, in the code below -- until all rabbits are counted, the bottom `<p>` is not shown:
|
||||
|
||||
```html run height=100
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<p>Let's count:</p>
|
||||
|
||||
*!*
|
||||
<script>
|
||||
alert( 'The 1st rabbit!' );
|
||||
alert( 'The 2nd rabbit!' );
|
||||
alert( 'The 3rd rabbit!' );
|
||||
</script>
|
||||
*/!*
|
||||
|
||||
<p>Rabbits counted!</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
The behavior is called "synchronous". Usually it causes no problems, but there's an important consequence.
|
||||
|
||||
**If the script is external, then until the browser executes it, it can't show the page below.**
|
||||
|
||||
So, in this document, until `big.js` loads and executes, the `<body>` content is hidden:
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
*!*
|
||||
<script src="big.js"></script>
|
||||
*/!*
|
||||
</head>
|
||||
<body>
|
||||
This text is not shown until the browser executes big.js.
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
The question is -- do we really want to hide the body until the script finishes?
|
||||
|
||||
Most of time, we don't.
|
||||
|
||||
Sometimes, a script may contain a very important code that really must be loaded before the rest of the page is parsed (and the scripts below executed). But that's an exception.
|
||||
|
||||
Usually it's ok that a visitor can see the page content while the script is loading.
|
||||
|
||||
````warn header="Blocking is 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.
|
||||
|
||||
Like this:
|
||||
|
||||
```html
|
||||
Information below is not shown until the script loads and executes.
|
||||
|
||||
<script src="https://ad.service/path/to/banner"></script>
|
||||
|
||||
<p>…Important information!</p>
|
||||
```
|
||||
|
||||
It's just wrong that the rest of the page is not shown until the banner is loaded. The banner is not that important.
|
||||
|
||||
And what if their server is overloaded and responds slowly? Our visitors will wait even more.
|
||||
|
||||
Here's an example of such "slow" script (the delay is artificial here):
|
||||
|
||||
```html run height=100
|
||||
Wait. The text belown will shown up only after the script executes.
|
||||
|
||||
<script src="/article/external-script/banner.js?speed=0"></script>
|
||||
|
||||
<p>…Important information!</p>
|
||||
```
|
||||
````
|
||||
|
||||
So, how to "fix" the blocking behavior?
|
||||
|
||||
Our first attempt could be to put all such scripts to the bottom of the `<body>`, after all content. Then the browser will show the content first and then load the script. Problem gone.
|
||||
|
||||
But the solution is not perfect:
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
And here come the attributes `async` and `defer`.
|
||||
|
||||
The `async` attribute.
|
||||
: 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.
|
||||
|
||||
The `defer` attribute.
|
||||
<dd>The script with `defer` also executes asynchronously, like async. But there are two essential differences:
|
||||
|
||||
1. The browser guarantees to keep the relative order of "deferred" scripts.
|
||||
2. A "deferred" script always executes after HTML-document is fully loaded.
|
||||
|
||||
We'll discuss them more in-depth further in this chapter.
|
||||
|
||||
```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.
|
||||
```
|
||||
|
||||
```warn header="Attributes `async/defer` -- only for external scripts"
|
||||
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.
|
||||
```
|
||||
|
||||
Let's modify the "blocking script" example that we've seen before, adding `async`:
|
||||
|
||||
```html run height=100
|
||||
Wait. The text belown will shown up only after the script executes.
|
||||
|
||||
<script *!*async*/!* src="/article/external-script/banner.js?speed=0"></script>
|
||||
|
||||
<p>…Important information!</p>
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
Let's discuss these differences in more detail.
|
||||
|
||||
For example, in the code below (with `async`) there are two scripts. The one which loads first will run first.
|
||||
|
||||
```html
|
||||
<script src="1.js" async></script>
|
||||
<script src="2.js" async></script>
|
||||
```
|
||||
|
||||
If `2.js` is bigger than `1.js`, it may happen that `2.js` will run before `1.js`. That's normal. Async scripts are totally independent.
|
||||
|
||||
And in the code below `defer` is used, which forces browser to keeps execution order. Even if `2.js` loads first, it waits and executes after `1.js`:
|
||||
|
||||
```html
|
||||
<script src="1.js" defer></script>
|
||||
<script src="2.js" defer></script>
|
||||
```
|
||||
|
||||
This feature of "deferred" scripts is important when `2.js` relies on the result of `1.js` and we must be sure that the order is determined.
|
||||
|
||||
## Defer vs Async: page
|
||||
|
||||
A script with `defer` always works when the HTML-document is fully processed by the browser.
|
||||
|
||||
That feature comes into play when the document is large, like:
|
||||
|
||||
```html
|
||||
<script src="async.js" async></script>
|
||||
<script src="defer.js" defer></script>
|
||||
|
||||
Too long text. Didn't read. Many words.
|
||||
...
|
||||
```
|
||||
|
||||
...Here `async.js` executes when it loads -- possibly, before the document is fully loaded.
|
||||
|
||||
In contrast, `defer.js` always waits for the full document to be ready.
|
||||
|
||||
The choice between `defer` and `async` here depends on our intentions. Sometimes a script doesn't need the document at all (like a counter), it should execute ASAP. In this case `async` is superb.
|
||||
|
||||
And in another case a script may need the whole document to do some work with it. Then `defer` is preferable.
|
||||
|
||||
## Summary
|
||||
|
||||
- Scripts in an external file can be inserted on the page via `<script src="path"></script>`.
|
||||
- Normally, the browser doesn't show the document after the script until it executes. Unless the script has `async` or `defer` attributes.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
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..."
|
||||
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.
|
||||
|
||||
We can ensure that dynamic `<script>` tags run in the order of insertion by setting `script.async` to `false`.
|
||||
|
||||
The code example:
|
||||
```js
|
||||
function addScript(src){
|
||||
let script = document.createElement('script');
|
||||
script.src = src;
|
||||
*!*
|
||||
script.async = false;
|
||||
*/!*
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
addScript('1.js'); // all these scripts will start loading immediately
|
||||
addScript('2.js'); // but execute in the order of insertion
|
||||
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.
|
||||
````
|
||||
|
|
@ -1 +0,0 @@
|
|||
alert("Banner loaded!");
|
|
@ -1,166 +0,0 @@
|
|||
# Code structure
|
||||
|
||||
In this section we explore the code structure and statements.
|
||||
|
||||
[cut]
|
||||
|
||||
## Statements
|
||||
|
||||
We've already seen a statement: `alert('Hello, world!')`, which shows the message.
|
||||
|
||||
Another statement can be separated with a semicolon.
|
||||
|
||||
For example, here we split the message into two:
|
||||
|
||||
```js run no-beautify
|
||||
alert( 'Hello' ); alert( 'World' );
|
||||
```
|
||||
|
||||
Usually each statement is written on a separate line -- thus the code becomes more readable:
|
||||
|
||||
```js run no-beautify
|
||||
alert( 'Hello' );
|
||||
alert( 'World' );
|
||||
```
|
||||
|
||||
## The semicolon [#semicolon]
|
||||
|
||||
The semicolon may be omitted in most cases when a line break exists.
|
||||
|
||||
This would also work:
|
||||
|
||||
```js run no-beautify
|
||||
alert( 'Hello' )
|
||||
alert( 'World' )
|
||||
```
|
||||
|
||||
In this case JavaScript interprets the line break as a splitter and automatically assumes a "virtual" semicolon between them.
|
||||
|
||||
**But it's important that "in most cases" does not mean "always" here!**
|
||||
|
||||
Consider this code as an example:
|
||||
|
||||
```js run no-beautify
|
||||
alert(3 +
|
||||
1
|
||||
+ 2);
|
||||
```
|
||||
|
||||
It outputs `6`.
|
||||
|
||||
JavaScript does not insert semicolons here. It is intuitively obvious that the first lines are an "uncomplete expression". JavaScript notes that and awaits the rest of the expression on the next line. And in this case that's actually fine and comfortable.
|
||||
|
||||
**But there are situations where JavaScript "fails" to assume a semicolon where it is really needed.**
|
||||
|
||||
Errors which come appear in such cases are quite hard to find and fix.
|
||||
|
||||
````smart header="An example of the error"
|
||||
For a curious reader who might be interested in a concrete example, check this code out:
|
||||
|
||||
```js run
|
||||
[1, 2].forEach(alert)
|
||||
```
|
||||
|
||||
It shows `1` then `2`.
|
||||
|
||||
Please don't think about the meaning of `[...].forEach` just for now -- it does not matter here (we'll get it later).
|
||||
|
||||
Now let's prepend an `alert` *without a semicolon* before it:
|
||||
|
||||
```js run no-beautify
|
||||
alert( "..." ) // works
|
||||
[1, 2].forEach(alert) // doesn't work!
|
||||
```
|
||||
|
||||
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:
|
||||
```js run
|
||||
alert( "With the semicolon everything works" ); // printed
|
||||
[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:
|
||||
|
||||
```js run no-beautify
|
||||
// without semicolon after alert it becomes
|
||||
alert( "..." )[1, 2].forEach(alert) // doesn't work!
|
||||
```
|
||||
````
|
||||
|
||||
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.
|
||||
|
||||
## Comments
|
||||
|
||||
As the time goes, the program becomes more and more complex. It becomes necessary to add *comments* which describe what happens and why.
|
||||
|
||||
Comments can be put into any place of the script. They don't affect it's execution. The JavaScript engine simply ignores them.
|
||||
|
||||
*One-line comments* start with a double slash `//`. The text after them till the end of line is considered a comment.
|
||||
|
||||
It may occupy a full line of it's own or follow a statement.
|
||||
|
||||
Like this:
|
||||
```js run
|
||||
// This says "Hello" (the comment occupies a line of it's own)
|
||||
alert( 'Hello' );
|
||||
|
||||
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:
|
||||
|
||||
```js run
|
||||
/* An example with two messages.
|
||||
This is a multiline comment.
|
||||
*/
|
||||
alert( 'Hello' );
|
||||
alert( 'World' );
|
||||
```
|
||||
|
||||
The content of comments is ignored, so if we put a code inside <code>/* ... */</code> or after `//` it won't execute.
|
||||
|
||||
Sometimes it's used to temporarily disable a part of the code.
|
||||
|
||||
```js run
|
||||
/* Commenting out the code
|
||||
alert( 'Hello' );
|
||||
*/
|
||||
alert( 'World' );
|
||||
```
|
||||
|
||||
```smart header="Use hotkeys!"
|
||||
In most editors a line of code can be commented out by `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a code and press the hotkey).
|
||||
```
|
||||
|
||||
````warn header="Nested comments are not supported!"
|
||||
There may not be comments inside comments.
|
||||
|
||||
This code will die with an error:
|
||||
|
||||
```js run no-beautify
|
||||
/*
|
||||
/* nested comment ?!? */
|
||||
*/
|
||||
alert( 'World' );
|
||||
```
|
||||
````
|
||||
|
||||
Don't hesitate to comment.
|
||||
|
||||
Comments increase the overall code footprint, but that's not a problem at all, because there are many tools which minify the code before publishing to production server and remove comments in the process.
|
||||
|
||||
There are various types of comments, answering different questions:
|
||||
|
||||
- What the code does?
|
||||
- Why the code is written like that?
|
||||
- Which counter-intuitive or implicit connections it has with other parts of the script?
|
||||
|
||||
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"
|
||||
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.
|
||||
```
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
# The modern mode, "use strict"
|
||||
|
||||
For a long time JavaScript was evolving without compatibility issues. New features were added to the language, but the old functionality did not change.
|
||||
|
||||
That had the benefit of never breaking the existing code. But the back side is that any mistake or an imprefect decision made by JavaScript creators got stuck in the language forever.
|
||||
|
||||
It had been so before ECMAScript 5 (ES5) appeared which added new features to the language and modified some of the existing ones.
|
||||
|
||||
To keep the old code working, most modifications of the pre-existing features are off by default. One need to enable them explicitly with a special directive `"use strict"`.
|
||||
|
||||
[cut]
|
||||
|
||||
## "use strict"
|
||||
|
||||
The directive looks like a string: `"use strict"` or `'use strict'`. When it is located on the top of the script, then the whole script works the "modern" way.
|
||||
|
||||
For example
|
||||
|
||||
```js
|
||||
"use strict";
|
||||
|
||||
// this code works the modern way
|
||||
...
|
||||
```
|
||||
|
||||
```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.
|
||||
|
||||
Once we enter the strict mode, there's no return.
|
||||
```
|
||||
|
||||
````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.
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Do I really need "use strict"?
|
||||
|
||||
Technically, we can `"use strict"`, the code will work in the "old mode". But it is suggested that you use it all the time.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Here in the tutorial all code works correctly in `"use strict"`.
|
||||
|
||||
## Summary
|
||||
|
||||
- JavaScript without `"use strict"` may execute differently in some cases. Further in the tutorial we'll see what's different. Thankfully, not so much.
|
||||
- Several modern features of the language enable `"use strict"` implicitly, so there's just no way to evade it.
|
||||
- It is strongly advised to `"use strict"` everywhere, but keep in mind compability if we are to support old IE.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
In the code below, each line corresponds to the item in the task list.
|
||||
|
||||
```js run
|
||||
let admin, name; // can declare two variables at once
|
||||
|
||||
name = "John";
|
||||
|
||||
admin = name;
|
||||
|
||||
alert( admin ); // "John"
|
||||
```
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
importance: 2
|
||||
|
||||
---
|
||||
|
||||
# Working with variables
|
||||
|
||||
1. Declare two variables: `admin` and `name`.
|
||||
2. Assign the value `"John"` to `name`.
|
||||
3. Copy the value from `name` to `admin`.
|
||||
4. Show the value of `admin` using `alert` (must output "John").
|
|
@ -1,21 +0,0 @@
|
|||
First, the variable for the name of our planet.
|
||||
|
||||
That's simple:
|
||||
|
||||
```js
|
||||
let ourPlanetName = "Earth";
|
||||
```
|
||||
|
||||
Note, we could use a shorter name `planet`, but it might be not obvious what planet it refers to. It's nice to be more verbose. At least until the variable isNotTooLong.
|
||||
|
||||
Second, the name of the current visitor:
|
||||
|
||||
```js
|
||||
let currentUserName = "John";
|
||||
```
|
||||
|
||||
Again, we could shorten that to `userName` if we know beyound the reasonable doubt that the user is current.
|
||||
|
||||
Modern editors and autocomplete make long variable names easy to write. Don't save on them. Say, a name with 3 words in it is fine.
|
||||
|
||||
And if your editor does not have proper autocompletion, get [a new one](/editor).
|
|
@ -1,8 +0,0 @@
|
|||
importance: 3
|
||||
|
||||
---
|
||||
|
||||
# Giving the right name
|
||||
|
||||
1. Create the variable to store the name of our planet. Assign the value `"Earth"` to it. What should be its name?
|
||||
2. Create the variable to store the name of the current visitor. What about its name?
|
|
@ -1,315 +0,0 @@
|
|||
# Variables
|
||||
|
||||
Most of the time, script needs to work with the information.
|
||||
|
||||
If it's an online-shop -- that's going to be the goods and a shopping cart. If it's a chat -- visitors, messages and so on.
|
||||
|
||||
Variables are used to store the information.
|
||||
|
||||
[cut]
|
||||
|
||||
## A variable
|
||||
|
||||
A [variable]("https://en.wikipedia.org/wiki/Variable_(computer_science)") is defined as a "named storage" for the information. We can use variables to store the goods, visitors etc.
|
||||
|
||||
To create a variable in JavaScript, we need to use the `let` keyword.
|
||||
|
||||
The statement below creates (in other words: *declares* or *defines*) the variable with the name "message":
|
||||
|
||||
```js
|
||||
let message;
|
||||
```
|
||||
|
||||
Now we can put some data into it:
|
||||
|
||||
```js
|
||||
let message;
|
||||
|
||||
*!*
|
||||
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:
|
||||
|
||||
```js run
|
||||
let message;
|
||||
message = 'Hello!';
|
||||
|
||||
*!*
|
||||
alert( message ); // shows the variable content
|
||||
*/!*
|
||||
```
|
||||
|
||||
To be concise we can merge the variable declaration and assignment into a single line:
|
||||
|
||||
```js run
|
||||
let message = 'Hello!';
|
||||
alert( message ); // same as above
|
||||
```
|
||||
|
||||
We can also declare multiple variables in one line:
|
||||
|
||||
```js no-beautify
|
||||
let user = 'John', age = 25, message = 'Hello';
|
||||
```
|
||||
|
||||
That might seem shorter, but it's recommended, for the sake of beter readability, to use a single line per variable.
|
||||
|
||||
The rewritten code is a bit longer, but easier to read:
|
||||
|
||||
```js no-beautify
|
||||
let user = 'John';
|
||||
let age = 25;
|
||||
let message = 'Hello';
|
||||
```
|
||||
|
||||
````smart header="`var` instead of `let`"
|
||||
In older scripts you may also find another keyword: `var` instead of `let`:
|
||||
|
||||
```js
|
||||
*!*var*/!* message = 'Hello';
|
||||
```
|
||||
|
||||
The `var` keyword is *almost* the same as `let`. It also declares a variable, but in a slightly different, "old-school" fashion.
|
||||
|
||||
The subtle differences does not matter for us yet. We'll cover them in detail later.
|
||||
````
|
||||
|
||||
## Real-life analogy
|
||||
|
||||
We can easily grasp the concept of a "variable" if we imagine it as a "box" for the data, with the unique-named sticker on it.
|
||||
|
||||
For instance, the variable `message` is a box with the value `"Hello!"` labelled `"message"`:
|
||||
|
||||

|
||||
|
||||
We can put any value into the box (variable).
|
||||
|
||||
Also we can change it. The value can be changed as many times as we need:
|
||||
|
||||
```js run
|
||||
let message;
|
||||
|
||||
message = 'Hello!';
|
||||
|
||||
message = 'World!'; // value changed
|
||||
|
||||
alert( message );
|
||||
```
|
||||
|
||||
When the value is changed, the old data is removed from the variable:
|
||||
|
||||

|
||||
|
||||
We can also declare two variables and copy the data from one into the other.
|
||||
|
||||
```js run
|
||||
let hello = 'Hello world!';
|
||||
|
||||
let message;
|
||||
|
||||
*!*
|
||||
// copy 'Hello world' into message
|
||||
message = hello;
|
||||
*/!*
|
||||
|
||||
// now two variables have the same data
|
||||
alert( hello ); // Hello world!
|
||||
alert( message ); // Hello world!
|
||||
```
|
||||
|
||||
```smart header="Functional languages"
|
||||
It may be interesting to know that there also exist [functional](http://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) programming languages that forbid to change a variable value. For example, [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/).
|
||||
|
||||
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 one's mind.
|
||||
```
|
||||
|
||||
## Variable naming [#variable-naming]
|
||||
|
||||
There are two limitations for the variable name in JavaScript:
|
||||
|
||||
1. The name must contain only letters, digits, symbols `$` and `_`.
|
||||
2. The first character must not be a digit.
|
||||
|
||||
Valid names, for instance:
|
||||
|
||||
```js
|
||||
let userName;
|
||||
let test123;
|
||||
```
|
||||
|
||||
When the name contains multiple words, [camelCase](https://en.wikipedia.org/wiki/CamelCase) is commonly used. That is: words go one after another, each word starts with a capital letter: `myVeryLongName`.
|
||||
|
||||
What's interesting -- the dollar sign `'$'` and the underscore `'_'` are considered ordinary symbols, just like letters.
|
||||
|
||||
These names are valid:
|
||||
|
||||
```js run untrusted
|
||||
let $ = 1; // declared a variable with the name "$"
|
||||
let _ = 2; // and now the variable with the name "_"
|
||||
|
||||
alert( $ + _ ); // 3
|
||||
```
|
||||
|
||||
Examples of incorrect variable names:
|
||||
|
||||
```js no-beautify
|
||||
let 1a; // cannot start with a digit
|
||||
|
||||
let my-name; // a hyphen '-' is not allowed in the name
|
||||
```
|
||||
|
||||
```smart header="Case matters"
|
||||
Variables named `apple` and `AppLE` -- are two different variables.
|
||||
```
|
||||
|
||||
````smart header="Non-english letters are allowed, but not recommended"
|
||||
It is possible to use any language, including cyrillic letters or even hieroglyphs, like this:
|
||||
|
||||
```js
|
||||
let имя = '...';
|
||||
let 我 = '...';
|
||||
```
|
||||
|
||||
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.
|
||||
````
|
||||
|
||||
````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.
|
||||
|
||||
For example, words `let`, `class`, `return`, `function` are reserved.
|
||||
|
||||
The code below will give a syntax error:
|
||||
|
||||
```js run no-beautify
|
||||
let let = 5; // can't name a variable "let", error!
|
||||
let return = 5; // also can't name it "return", error!
|
||||
```
|
||||
````
|
||||
|
||||
## Non-Strict mode assignment
|
||||
|
||||
Without strict mode, it is possible to create a variable without a `let`, by a mere assignment of the value:
|
||||
|
||||
```js run no-strict
|
||||
num = 5; // the variable "num" is created if didn't exist
|
||||
|
||||
alert(num);
|
||||
```
|
||||
|
||||
...But that is an old feature of the language, kept for compatibility with the old scripts. It's usage has been frowned-upon for a long time. It's an error in the strict mode.
|
||||
|
||||
The code with `"use strict"` will give an error:
|
||||
|
||||
```js run untrusted
|
||||
"use strict";
|
||||
|
||||
*!*
|
||||
num = 5; // error: num is not defined
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
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 V8 will remind you about it by giving an error on `let`.
|
||||
|
||||
## Constants
|
||||
|
||||
Variables with a fixed value are called "constant variables" or just *constants*.
|
||||
|
||||
To declare a constant variable, one can use `const`:
|
||||
|
||||
```js run
|
||||
const myBirthday = '18.04.1982';
|
||||
|
||||
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.
|
||||
|
||||
```js run
|
||||
const myBirthday = '18.04.1982';
|
||||
|
||||
// do some calculations to get the age
|
||||
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:
|
||||
|
||||
```js run
|
||||
const COLOR_RED = "#F00";
|
||||
const COLOR_GREEN = "#0F0";
|
||||
const COLOR_BLUE = "#00F";
|
||||
const COLOR_ORANGE = "#FF7F00";
|
||||
|
||||
let color = COLOR_ORANGE;
|
||||
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`.
|
||||
|
||||
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
|
||||
|
||||
We're almost done with the initial understanding of variables, but there's one more thing.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Please spend some time thinking about the right name for a variable before declaring it. That will repay you a lot.
|
||||
|
||||
Few good-to-follow rules are:
|
||||
|
||||
- Use human-readable names like `userName` or `shoppingCart`.
|
||||
- Stay away from abbreviations or short names `a`, `b`, `c`, unless you really know what you're doing.
|
||||
- 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.
|
||||
- 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`.
|
||||
|
||||
Sounds simple? Indeed it is. But creating good descriptive-and-concise names in practice is not. Go for it.
|
||||
|
||||
```smart header="Reuse or create?"
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
P.S. Modern JavaScript minifiers and browsers optimize code well enough so that won't create a performance issue.
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
We can declare variables to store data. That can be done using `var` or `let` or `const`.
|
||||
|
||||
- `let` -- is a modern variable declaration. The code must be in strict mode to use `let` in Chrome (V8).
|
||||
- `var` -- is an old-school variable declaration. We'll study the subtle differences from `let` later.
|
||||
- `const` -- is like `let`, but the variable can't be changed.
|
||||
|
||||
Variables should be named in a way that allows to easily understand what's inside.
|
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 19 KiB |
|
@ -1,429 +0,0 @@
|
|||
# Data types
|
||||
|
||||
There are 7 data types in JavaScript.
|
||||
|
||||
Here we will get the common understanding of them. In the next chapters we'll talk about each type in detail.
|
||||
|
||||
[cut]
|
||||
|
||||
## A number
|
||||
|
||||
```js
|
||||
let n = 123;
|
||||
n = 12.345;
|
||||
```
|
||||
|
||||
A *number* type serves both for integer and floating point numbers.
|
||||
|
||||
Besides regular numbers there are so-called "special numeric values" which also belong to that type: `Infinity`, `-Infinity` and `NaN`.
|
||||
|
||||
- `Infinity` represents the mathematical [Infinity](https://en.wikipedia.org/wiki/Infinity). It is a value that's greater than any number.
|
||||
|
||||
We can get it as a result of division by zero:
|
||||
|
||||
```js run
|
||||
alert( 1 / 0 ); // Infinity
|
||||
```
|
||||
|
||||
Or just mention it in the code directly:
|
||||
|
||||
```js run
|
||||
alert( Infinity ); // Infinity
|
||||
```
|
||||
- `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
|
||||
```
|
||||
|
||||
`NaN` is sticky. Any further operation on `NaN` would give `NaN`:
|
||||
|
||||
```js run
|
||||
alert( "not a number" * 2 + 5 - 9 ); // still NaN
|
||||
```
|
||||
|
||||
So, in a long mathematical expression if we have `NaN` in one place, it propagates to the whole result.
|
||||
|
||||
```smart header="Maths is safe"
|
||||
Maths is safe in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc.
|
||||
|
||||
The script will never die. At worst we'll get `NaN` as the result.
|
||||
```
|
||||
|
||||
Special numeric values formally belong to the "number" type. Of course they are not numbers in a common sense of this word.
|
||||
|
||||
We'll see more into working with numbers in the chapter <info:number>.
|
||||
|
||||
## A string
|
||||
|
||||
```js
|
||||
let str = "Hello";
|
||||
let str2 = 'Single quotes are ok too';
|
||||
let phrase = `can embed ${str}`;
|
||||
```
|
||||
|
||||
In JavaScript, there are 3 types of quotes.
|
||||
|
||||
1. Double quotes: `"Hello"`.
|
||||
2. Single quotes: `'Hello'`.
|
||||
3. Backtricks: <code>`Hello`</code>.
|
||||
|
||||
Double and single quotes are essentially the same.
|
||||
|
||||
Backticks are "extended functionality" quotes. They allow to embed variables and expressions into a string by wrapping them in `${…}`, for example:
|
||||
|
||||
```js run
|
||||
let name = "John";
|
||||
|
||||
// embed variable
|
||||
alert( `Hello, ${name}!` ); // Hello, John!
|
||||
|
||||
// embed expression
|
||||
alert( `the result is ${1 + 2}` ); // the result is 3
|
||||
```
|
||||
|
||||
The expression inside `${…}` is evaluated and the result becomes a part of the string. We can put anything there: a variable like `name` or an arithmetical expression like `1 + 2` or something more complex.
|
||||
|
||||
We'll cover strings more thoroughly in the chapter <info:string>.
|
||||
|
||||
```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 JavaScript, there is no such type. There's only one type: `string`. A string may consist of only one character or many of them.
|
||||
```
|
||||
|
||||
## A boolean (logical)
|
||||
|
||||
The boolean type has only two values: `true` and `false`.
|
||||
|
||||
This type is commonly used to store the yes/no values.
|
||||
|
||||
For instance:
|
||||
|
||||
```js no-beautify
|
||||
let checked = true; // the form field is checked
|
||||
checked = false; // the form field is not checked
|
||||
```
|
||||
|
||||
Boolean values also come as the result of comparisons:
|
||||
|
||||
```js run
|
||||
let isGreater = 4 > 1;
|
||||
alert( isGreater ); // true
|
||||
```
|
||||
|
||||
We'll cover booleans more deeply while discussing logical operators.
|
||||
|
||||
## The "null" value
|
||||
|
||||
The special `null` value does not belong to any type described above.
|
||||
|
||||
It forms a separate type of its own, which contains only the `null` value:
|
||||
|
||||
```js
|
||||
let age = null;
|
||||
```
|
||||
|
||||
In JavaScript `null` is not a "reference to a non-existing object" or a "null pointer" like in some other languages.
|
||||
|
||||
It's just a special value which has the sense of "nothing" or "value unknown".
|
||||
|
||||
The code above states that the `age` is unknown.
|
||||
|
||||
## The "undefined" value
|
||||
|
||||
The special value `undefined` stands separately. It makes a type of its own, just like `null`.
|
||||
|
||||
The sense of `undefined` is "value is not assigned".
|
||||
|
||||
If a variable is declared, but not assigned, then its value is exactly `undefined`:
|
||||
|
||||
```js run
|
||||
let x;
|
||||
|
||||
alert( x ); // shows "undefined"
|
||||
```
|
||||
|
||||
Technically, it is possible to assign to `undefined`:
|
||||
|
||||
```js run
|
||||
let x = 123;
|
||||
|
||||
x = undefined;
|
||||
|
||||
alert( x ); // "undefined"
|
||||
```
|
||||
|
||||
...But it's not recommended to do that, because such assignment contradicts to the sense of `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.
|
||||
|
||||
## 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 any time later:
|
||||
|
||||
```js
|
||||
user.isAdmin = true;
|
||||
```
|
||||
|
||||
...Or remove it with the help of `delete` operator:
|
||||
|
||||
```js
|
||||
delete user.age;
|
||||
```
|
||||
|
||||
Any string can be used as a property name. But if it has multiple words, then we should use another kind of notation to access it. Namely, square brackets:
|
||||
|
||||
```js
|
||||
user["likes to swim?"] = true;
|
||||
```
|
||||
|
||||
See, the dot requires the property name to be a valid variable identifier. That is: no spaces and other limitations. Square brackets work with any string.
|
||||
|
||||
We can split the code above into two lines by putting the property name into a variable:
|
||||
|
||||
```js
|
||||
let key = "likes to swim?";
|
||||
user[key] = true; // same as above
|
||||
```
|
||||
|
||||
Objects in JavaScript are very powerful. Here we just started the topic that is really huge. We'll be closely working with objects in the next parts of the tutorial.
|
||||
|
||||
## Symbol type
|
||||
|
||||
The `symbol` type stands apart from the others. 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 with a given name.
|
||||
|
||||
A value of this type can be created like this:
|
||||
|
||||
```js
|
||||
// id is a symbol with the name "id"
|
||||
let id = Symbol("id");
|
||||
```
|
||||
|
||||
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) in that two symbols with the same name are different:
|
||||
|
||||
```js run
|
||||
let id1 = Symbol("id");
|
||||
let id2 = Symbol("id");
|
||||
|
||||
alert(id1 == id2); // false
|
||||
```
|
||||
|
||||
Symbols is a separate primitive type used for identifiers, which are guaranteed to be unique.
|
||||
|
||||
So if we want to create a "hidden" property in an object, only for us, and ensure that no other part of code can occasionally access it, we can create a symbol for it:
|
||||
|
||||
```js run
|
||||
let user = { name: "John" };
|
||||
let id = Symbol("id");
|
||||
|
||||
user[id] = "Secret ID Value";
|
||||
alert( user[id] ); // we can access the data
|
||||
```
|
||||
|
||||
Now, if another script wants his own "id" property inside `user`, it can create its own `Symbol("id")`. There will be no conflict, because symbols are always different.
|
||||
|
||||
Symbols are widely used by the JavaScript language itself to store "system" properties. We'll find out more details after studying objects.
|
||||
|
||||
## The typeof operator [#type-typeof]
|
||||
|
||||
The `typeof` operator returns the type of the argument.
|
||||
|
||||
It allows two forms of syntax:
|
||||
|
||||
1. As an operator: `typeof x`.
|
||||
2. Function style: `typeof(x)`.
|
||||
|
||||
In other words, it works both with the brackets or without them. They result is the same.
|
||||
|
||||
The result of `typeof x` is a string, which has the type name:
|
||||
|
||||
```js
|
||||
typeof undefined // "undefined"
|
||||
|
||||
typeof 0 // "number"
|
||||
|
||||
typeof true // "boolean"
|
||||
|
||||
typeof "foo" // "string"
|
||||
|
||||
typeof Symbol("id") // "symbol"
|
||||
|
||||
typeof {} // "object"
|
||||
|
||||
*!*
|
||||
typeof null // "object" (1)
|
||||
*/!*
|
||||
|
||||
*!*
|
||||
typeof alert // "function" (2)
|
||||
*/!*
|
||||
```
|
||||
|
||||
Please note the last two lines, because `typeof` behaves specially there.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
## Type conversions
|
||||
|
||||
A variable in JavaScript can contain any data. A variable can at one moment be a string and later recieve a numeric value:
|
||||
|
||||
```js
|
||||
// no error
|
||||
let message = "hello";
|
||||
message = 123456;
|
||||
```
|
||||
|
||||
...But sometimes we need to convert a value from one type to another. For example, `alert` automatically converts any value to a string, to show it. Or, so to say, an `if (value)` converts it's argument into a boolean to see if it's `true` or `false`.
|
||||
|
||||
There are also cases when we need to convert between types to ensure that we store the right data the right way, or to use special features of a certain type.
|
||||
|
||||
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 most often are:
|
||||
|
||||
1. String conversion.
|
||||
2. Numeric conversion.
|
||||
3. Boolean conversion.
|
||||
|
||||
Let's see how and when they happen.
|
||||
|
||||
### String conversion
|
||||
|
||||
The string conversion happens when we need a string form of a value.
|
||||
|
||||
For example, `alert` does it:
|
||||
|
||||
```js run
|
||||
let a = true;
|
||||
|
||||
alert( a ); // "true"
|
||||
```
|
||||
|
||||
We can also use a call `String(value)` function for that:
|
||||
|
||||
```js run
|
||||
let a = true;
|
||||
|
||||
a = String(a); // now: a = "true"
|
||||
alert(typeof a); // string
|
||||
```
|
||||
|
||||
The string conversion is obvious. A `false` becomes `"false"`, `null` becomes `"null"` etc.
|
||||
|
||||
### Numeric conversion
|
||||
|
||||
Numeric conversion happens in mathematical functions and expressions automatically.
|
||||
|
||||
For example, a mathematical operation like division '/' can be applied to non-numbers:
|
||||
|
||||
```js run
|
||||
alert( "6" / "2" ); // 3, strings become numbers
|
||||
```
|
||||
|
||||
We can use a `Number(value)` function to convert any `value` to a number:
|
||||
|
||||
```js run
|
||||
let str = "123";
|
||||
alert(typeof str); // string
|
||||
|
||||
let n = Number(str); // becomes a number 123
|
||||
|
||||
alert(typeof n); // number
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```js run
|
||||
let age = Number("an arbitrary string instead of a number");
|
||||
|
||||
alert(age); // NaN, conversion failed
|
||||
```
|
||||
|
||||
The numeric conversion rules:
|
||||
|
||||
| Value | Becomes... |
|
||||
|-------|-------------|
|
||||
|`undefined`|`NaN`|
|
||||
|`null`|`0`|
|
||||
|<code>true / false</code> | `1 / 0` |
|
||||
| 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`. |
|
||||
|
||||
Examples:
|
||||
|
||||
```js run
|
||||
alert( Number(" 123 ") ); // 123
|
||||
alert( Number("123z") ); // NaN (error reading a number at "z")
|
||||
alert( Number(true) ); // 1
|
||||
alert( Number(false) ); // 0
|
||||
```
|
||||
|
||||
Please note that `null` and `undefined` behave differently here. A `null` becomes a zero, but `undefined` becomes `NaN`.
|
||||
|
||||
### 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)`.
|
||||
|
||||
The conversion rules are simple here:
|
||||
|
||||
- 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.
|
||||
|
||||
```js run
|
||||
alert( Boolean("0") ); // true
|
||||
alert( Boolean(" ") ); // any non-empty string, even whitespaces are true
|
||||
```
|
||||
````
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
There are 7 basic types in JavaScript.
|
||||
|
||||
- `number` for numbers of any kind, can convert into it using `Number(value)`.
|
||||
- `string` for strings and characters, can convert into it using `String(value)`.
|
||||
- `boolean` for `true`/`false`, can convert into it using `Boolean(value)`.
|
||||
- `null` for unknown values.
|
||||
- `undefined` for unassigned values.
|
||||
- `object` for complex data structures.
|
||||
- `symbol` for unique identifiers.
|
||||
|
||||
The `typeof` operator allows to see which type is stored in the variable, but note that it mistakingly returns `"object"` for `null`.
|
||||
|
||||
Now let's study operators and other language constructs that actually form our code.
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
The answer is:
|
||||
|
||||
- `a = 2`
|
||||
- `b = 2`
|
||||
- `c = 2`
|
||||
- `d = 1`
|
||||
|
||||
```js run no-beautify
|
||||
let a = 1, b = 1;
|
||||
|
||||
alert( ++a ); // 2, prefix form returns the new value
|
||||
alert( b++ ); // 1, postfix form returns the old value
|
||||
|
||||
alert( a ); // 2, incremented once
|
||||
alert( b ); // 2, incremented once
|
||||
```
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# The postfix and prefix forms
|
||||
|
||||
What are the final values of all variables in the code below?
|
||||
|
||||
```js
|
||||
let a = 1, b = 1;
|
||||
|
||||
let c = ++a; // ?
|
||||
let d = b++; // ?
|
||||
```
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
The answer is:
|
||||
|
||||
- `a = 4` (multiplied by 2)
|
||||
- `x = 5` (calculated as 1 + 4)
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
importance: 3
|
||||
|
||||
---
|
||||
|
||||
# Assignment result
|
||||
|
||||
What will be values of `a` and `x` in the example below?
|
||||
|
||||
```js
|
||||
let a = 2;
|
||||
|
||||
let x = 1 + (a *= 2);
|
||||
```
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
|
||||
```js no-beautify
|
||||
"" + 1 + 0 = "10" // (1)
|
||||
"" - 1 + 0 = -1 // (2)
|
||||
true + false = 1
|
||||
6 / "3" = 2
|
||||
"2" * "3" = 6
|
||||
4 + 5 + "px" = "9px"
|
||||
"$" + 4 + 5 = "$45"
|
||||
"4" - 2 = 2
|
||||
"4px" - 2 = NaN
|
||||
7 / 0 = Infinity
|
||||
" -9\n" + 5 = " -9\n5"
|
||||
" -9\n" - 5 = -14
|
||||
null + 1 = 1 // (3)
|
||||
undefined + 1 = NaN // (4)
|
||||
```
|
||||
|
||||
1. The plus `"+"` operator in this case first converts `1` to a string: `"" + 1 = "1"`, and then adds `0`.
|
||||
2. The minus `"-"` operator only works with numbers, it converts an empty string `""` to zero immediately.
|
||||
3. `null` becomes `0` after the numeric conversion.
|
||||
4. `undefined` becomes `NaN` after the numeric conversion.
|
|
@ -1,28 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Type conversions
|
||||
|
||||
Let's recap type conversions in the context of operators.
|
||||
|
||||
What will be the result for these expressions?
|
||||
|
||||
```js no-beautify
|
||||
"" + 1 + 0
|
||||
"" - 1 + 0
|
||||
true + false
|
||||
6 / "3"
|
||||
2" * "3"
|
||||
4 + 5 + "px"
|
||||
$" + 4 + 5
|
||||
"4" - 2
|
||||
"4px" - 2
|
||||
7 / 0
|
||||
" -9\n" + 5
|
||||
" -9\n" - 5
|
||||
null + 1
|
||||
undefined + 1
|
||||
```
|
||||
|
||||
Think well, write down and then compare with the answer.
|
|
@ -1,405 +0,0 @@
|
|||
# Operators
|
||||
|
||||
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.
|
||||
|
||||
[cut]
|
||||
|
||||
## Terms: "unary", "binary", "operand"
|
||||
|
||||
Before we move on, let's make a dip in the common terminology, used in the development.
|
||||
|
||||
- *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".
|
||||
- An operator is called *unary* if it has a single operand. For example, the unary minus `"-"` reverses the sign of the number:
|
||||
|
||||
```js run
|
||||
let x = 1;
|
||||
|
||||
*!*
|
||||
x = -x;
|
||||
*/!*
|
||||
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:
|
||||
|
||||
```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).
|
||||
|
||||
## Strings concatenation, binary +
|
||||
|
||||
Usually the plus operator `'+'` sums numbers.
|
||||
|
||||
But if the binary `+` is applied to strings, it merges (concatenates) them:
|
||||
|
||||
```js
|
||||
let s = "my" + "string";
|
||||
alert( s ); // mystring
|
||||
```
|
||||
|
||||
If one of operands of `+` is a string, then the other one is converted to string too.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
alert( '1' + 2 ); // "12"
|
||||
alert( 2 + '1' ); // "21"
|
||||
```
|
||||
|
||||
Note that it doesn't matter whether the first operand is a string or the second one. The rule is simple: if any of operands is a string, then convert the other one into a string as well.
|
||||
|
||||
The string concatenation and conversion is the special feature of the binary plus `"+"`. Other arithmetic operators work only with numbers. They always convert their operands to numbers.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
alert( 2 - '1' ); // 1
|
||||
alert( 6 / '2' ); // 3
|
||||
```
|
||||
|
||||
## Numeric conversion, unary +
|
||||
|
||||
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.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
// No effect on numbers
|
||||
let x = 1;
|
||||
alert( +x ); // 1
|
||||
|
||||
let y = -2;
|
||||
alert( +y ); // -2
|
||||
|
||||
// Converts non-numbers
|
||||
alert( +true ); // 1
|
||||
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.
|
||||
|
||||
What if we want to sum them?
|
||||
|
||||
The binary plus would add them as strings:
|
||||
|
||||
```js run
|
||||
let apples = "2";
|
||||
let oranges = "3";
|
||||
|
||||
alert( apples + oranges ); // "23", the binary plus concatenates strings
|
||||
```
|
||||
|
||||
If we want to treat them as numbers, then we can convert and then sum:
|
||||
|
||||
```js run
|
||||
let apples = "2";
|
||||
let oranges = "3";
|
||||
|
||||
alert( Number(apples) + Number(oranges) ); // 5
|
||||
|
||||
// or the shorter variant:
|
||||
*!*
|
||||
alert( +apples + +oranges ); // 5
|
||||
// both values converted to numbers before the binary 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.
|
||||
|
||||
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*.
|
||||
|
||||
## Operators 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 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`.
|
||||
|
||||
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:
|
||||
|
||||
|
||||
| Precedence | Name | Sign |
|
||||
|------------|------|------|
|
||||
| ... | ... | ... |
|
||||
| 15 | unary plus | `+` |
|
||||
| 15 | unary minus | `-` |
|
||||
| 14 | multiplication | `*` |
|
||||
| 14 | division | `/` |
|
||||
| 13 | addition (binary) | `+` |
|
||||
| 13 | substraction | `-` |
|
||||
| ... | ... | ... |
|
||||
| 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.
|
||||
|
||||
## Assignment
|
||||
|
||||
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`, then the calculations are done first, and afterwards the `=` is evaluated, storing the result in `x`.
|
||||
|
||||
```js
|
||||
let x = 2 * 2 + 1;
|
||||
|
||||
alert( x ); // 5
|
||||
```
|
||||
|
||||
It is possible to chain assignments:
|
||||
|
||||
```js run
|
||||
let a, b, c;
|
||||
|
||||
*!*
|
||||
a = b = c = 2 + 2;
|
||||
*/!*
|
||||
|
||||
alert( a ); // 4
|
||||
alert( b ); // 4
|
||||
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.
|
||||
|
||||
````smart header="The assignment operator `\"=\"` returns a value"
|
||||
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*.
|
||||
|
||||
So it is actually possible to use an assignment as the part of a more complex expression:
|
||||
|
||||
```js run
|
||||
let a = 1;
|
||||
let b = 2;
|
||||
|
||||
*!*
|
||||
let c = 3 - (a = b + 1);
|
||||
*/!*
|
||||
|
||||
alert( a ); // 3
|
||||
alert( c ); // 0
|
||||
```
|
||||
|
||||
In the example above, the result of `(a = b + 1)` is the value which is assigned to `a` (that is `3`). It is then used to substract from `3`.
|
||||
|
||||
Funny code, isn't it? We should understand how it works, but don't write anything like that ourselves. Such tricks definitely don't make the code neater and more readable.
|
||||
````
|
||||
|
||||
## Remainder %
|
||||
|
||||
The remainder operator `%` despite it's look does not have a relation to percents.
|
||||
|
||||
The result of `a % b` is the remainder of the integer division of `a` by `b`.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
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( 6 % 3 ); // 0 is a remainder of 6 divided by 3
|
||||
```
|
||||
|
||||
## Increment/decrement: ++, --
|
||||
|
||||
Increasing or decreasing a number by one is among the most common numerical operations.
|
||||
|
||||
So, there are special operators for that:
|
||||
|
||||
- **Increment** `++` increases a variable by 1:
|
||||
|
||||
```js run no-beautify
|
||||
let counter = 2;
|
||||
counter++; // works same as counter = counter + 1, but shorter
|
||||
alert( counter ); // 3
|
||||
```
|
||||
- **Decrement** `--` decreases a variable by 1:
|
||||
|
||||
```js run no-beautify
|
||||
let counter = 2;
|
||||
counter--; // works same as counter = counter - 1, but shorter
|
||||
alert( counter ); // 1
|
||||
```
|
||||
|
||||
```warn
|
||||
Increment/decrement can be applied only to a variable. An attempt to use it on a value like `5++` will give an error.
|
||||
```
|
||||
|
||||
Operators `++` and `--` can be put both after and before the variable.
|
||||
|
||||
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`.
|
||||
|
||||
Is there any difference? Yes, but we can see it if we use the result of `++/--`.
|
||||
|
||||
As we know, all operators return a value. Increment/decrement is not an exception here. The prefix form returns the new value, while the postfix form returns the old value (prior to increment/decrement).
|
||||
|
||||
Let's see the examples:
|
||||
|
||||
```js run
|
||||
let counter = 1;
|
||||
let a = ++counter; // (*)
|
||||
|
||||
alert(a); // *!*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:
|
||||
|
||||
```js run
|
||||
let counter = 1;
|
||||
let a = counter++; // (*) changed ++counter to counter++
|
||||
|
||||
alert(a); // *!*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:
|
||||
|
||||
- If the result of increment/decrement is not used, then there is no difference which form to use:
|
||||
|
||||
```js run
|
||||
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 run
|
||||
let counter = 0;
|
||||
alert( ++counter ); // 1
|
||||
```
|
||||
- If we'd like to increment, but use the previous value, then we need the postfix form:
|
||||
|
||||
```js run
|
||||
let counter = 0;
|
||||
alert( counter++ ); // 0
|
||||
```
|
||||
|
||||
````smart header="Increment/decrement among other operators"
|
||||
Operators `++/--` can be used inside an expression as well. Their priority is higher than most other arithmetical operations.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
let counter = 1;
|
||||
alert( 2 * ++counter ); // 4
|
||||
```
|
||||
|
||||
Compare with:
|
||||
|
||||
```js run
|
||||
let counter = 1;
|
||||
alert( 2 * counter++ ); // 2, because counter++ returns the "old" value
|
||||
```
|
||||
|
||||
Though technically allowable, such notation usually makes the code less readable. One line does multiple things -- not good.
|
||||
|
||||
While reading the code, a fast "vertical" eye-scan can easily miss such `counter++`, and it won't be obvious that the variable increases.
|
||||
|
||||
The "one line -- one action" style is advised:
|
||||
|
||||
```js run
|
||||
let counter = 1;
|
||||
alert( 2 * counter );
|
||||
counter++;
|
||||
```
|
||||
````
|
||||
|
||||
## Bitwise operators
|
||||
|
||||
Bitwise operators treat arguments as 32-bit interger numbers and work on the level on their binary representation.
|
||||
|
||||
These operators are not JavaScript-specific. They are supported in most programming languages.
|
||||
|
||||
The list of operators:
|
||||
|
||||
- AND ( `&` )
|
||||
- OR ( `|` )
|
||||
- XOR ( `^` )
|
||||
- NOT ( `~` )
|
||||
- LEFT SHIFT ( `<<` )
|
||||
- RIGHT SHIFT ( `>>` )
|
||||
- ZERO-FILL RIGHT SHIFT ( `>>>` )
|
||||
|
||||
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
|
||||
|
||||
We often need to apply an operator to a variable and store the new result in it.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
let n = 2;
|
||||
n = n + 5;
|
||||
n = n * 2;
|
||||
```
|
||||
|
||||
This notation can be shortened using operators `+=` and *=`:
|
||||
|
||||
```js run
|
||||
let n = 2;
|
||||
n += 5; // now n=7 (same as n = n + 5)
|
||||
n *= 2; // now n=14 (same as n = n * 2)
|
||||
|
||||
alert( n ); // 14
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```js run
|
||||
let n = 2;
|
||||
n *= 3 + 5;
|
||||
|
||||
alert( n ); // 16 (same as n *= 8)
|
||||
```
|
||||
|
||||
## Comma
|
||||
|
||||
The comma operator `','` is one of most rare and unusual ones. Sometimes it's used to write shorter code, so we need to know it in order understand what's going on.
|
||||
|
||||
The comma operator allows to evaluate several expressions, dividing them with a comma `','`. Each of them is evaluated, but result of only the last one is returned.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
*!*
|
||||
a = (1+2, 3+4);
|
||||
*/!*
|
||||
|
||||
alert( a ); // 7 (the result of 3+4)
|
||||
```
|
||||
|
||||
Here, the first expression `1+2` is evaluated, and it's result is thrown away, then `3+4` is evaluated and returned as the result.
|
||||
|
||||
Why do we need such an operator which throws away everything except the last part?
|
||||
|
||||
Usually it is used in more complex constructs to put several actions in one line.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
// three operations in one line
|
||||
for (*!*a = 1, b = 3, c = a*b*/!*; a < 10; a++) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Such tricks are used in many JavaScript frameworks, that's why we mention about them. But usually they don't benefit to code readability, so take care.
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
|
||||
```js no-beautify
|
||||
5 > 4 → true
|
||||
"apple" > "pineapple" → false
|
||||
"2" > "12" → true
|
||||
undefined == null → true
|
||||
undefined === null → false
|
||||
null == "\n0\n" → false
|
||||
null === +"\n0\n" → false
|
||||
```
|
||||
|
||||
Some of the reasons:
|
||||
|
||||
1. Obviously, true.
|
||||
2. Dictionary comparison, hence true.
|
||||
3. Again, dictionary comparison, first char of `"2"` is greater than the first char of `"1"`.
|
||||
4. Values `null` and `undefined` equal each other only.
|
||||
5. Strict equality is strict. Different types from both sides lead to false.
|
||||
6. See (4).
|
||||
7. Strict equality of different types.
|
|
@ -1,18 +0,0 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Comparisons
|
||||
|
||||
What will be the result for expressions?
|
||||
|
||||
```js no-beautify
|
||||
5 > 4
|
||||
"apple" > "pineapple"
|
||||
"2" > "12"
|
||||
undefined == null
|
||||
undefined === null
|
||||
null == "\n0\n"
|
||||
null === +"\n0\n"
|
||||
```
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
# Comparisons
|
||||
|
||||
Many comparison operators we know from the maths:
|
||||
|
||||
- Greater/less than: <code>a > b</code>, <code>a < b</code>.
|
||||
- Greater/less than or equals: <code>a >= b</code>, <code>a <= b</code>.
|
||||
- Equality check is written as `a == b` (please note the double equation sign `'='`. A single symbol `a = b` would mean an assignment).
|
||||
- Not equals. In maths the sign is <code>≠</code>, in JavaScript we use an assignment with an exclamation before it: <code>a != b</code>.
|
||||
|
||||
[cut]
|
||||
|
||||
## Boolean is the result
|
||||
|
||||
Just as all other operators, a comparison returns a value. The value is of the boolean type.
|
||||
|
||||
- `true` -- means "yes", "correct" or "the truth".
|
||||
- `false` -- means "no", "wrong" or "a lie".
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
alert( 2 > 1 ); // true (correct)
|
||||
alert( 2 == 1 ); // false (wrong)
|
||||
alert( 2 != 1 ); // true (correct)
|
||||
```
|
||||
|
||||
A result of a comparison can be assigned to a variable, just like any value:
|
||||
|
||||
```js run
|
||||
let result = 5 > 4; // assign the result of the comparison
|
||||
alert( result ); // true
|
||||
```
|
||||
|
||||
## Strings comparison
|
||||
|
||||
To see which string is greater than the other, the so-called "dictionary" or "lexicographical" order is used.
|
||||
|
||||
In other words, strings are compared letter-by-letter.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
alert( 'Z' > 'A' ); // true
|
||||
alert( 'Glow' > 'Glee' ); // true
|
||||
alert( 'Bee' > 'Be' ); // true
|
||||
```
|
||||
|
||||
The algorithm to compare two strings is simple:
|
||||
|
||||
1. Compare the first characters of both strings.
|
||||
2. If the first one is greater(or less), then the first string is greater(or less) than the second and we're done.
|
||||
3. Otherwise if first characters are equal, compare the second characters the same way.
|
||||
4. Repeat until the end of any string.
|
||||
5. If both strings ended simultaneously, then they are equal. Otherwise the longer string is greater.
|
||||
|
||||
In the example above, the comparison `'Z' > 'A'` gets the result at the first step.
|
||||
|
||||
Strings `"Glow"` and `"Glee"` are compared character-by-character:
|
||||
|
||||
1. `G` is the same as `G`.
|
||||
2. `l` is the same as `l`.
|
||||
3. `o` is greater than `e`. Stop here. The first string is greater.
|
||||
|
||||
```smart header="Not a real dictionary"
|
||||
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
|
||||
|
||||
When compared values belong to different types, they get autoconverted to numbers.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
alert( '2' > 1 ); // true, string '2' becomes a number 2
|
||||
alert( '01' == 1 ); // true, string '01' becomes a number 1
|
||||
```
|
||||
|
||||
For boolean values, `true` becomes `1` and `false` becomes `0`, that's why:
|
||||
|
||||
```js run
|
||||
alert( true == 1 ); // true
|
||||
alert( false == 0 ); // true
|
||||
```
|
||||
|
||||
````smart header="A funny consequence"
|
||||
It is possible that in the same time:
|
||||
|
||||
- Two values are equal.
|
||||
- One of them is `true` as a boolean and the other one is `false` as a boolean.
|
||||
|
||||
For example:
|
||||
|
||||
```js run
|
||||
let a = 0;
|
||||
alert( Boolean(a) ); // false
|
||||
|
||||
let b = "0";
|
||||
alert( Boolean(b) ); // true
|
||||
|
||||
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.
|
||||
````
|
||||
|
||||
## Strict equality
|
||||
|
||||
A regular equality check `"=="` has a problem. It cannot differ `0` from `false`:
|
||||
|
||||
```js run
|
||||
alert( 0 == false ); // true
|
||||
```
|
||||
|
||||
The same thing with an empty string:
|
||||
|
||||
```js run
|
||||
alert( '' == false ); // true
|
||||
```
|
||||
|
||||
That's the natural consequence of what we've seen before. Operands of different types are converted to a number. An empty string, just like `false`, becomes a zero.
|
||||
|
||||
What to do if we'd like to differentiate `0` from `false`?
|
||||
|
||||
**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 convert them.
|
||||
|
||||
Let's try it:
|
||||
|
||||
```js run
|
||||
alert( 0 === false ); // false, because the types are different
|
||||
```
|
||||
|
||||
There also exists a "strict non-equality" operator `!==`, as an analogy for `!=`.
|
||||
|
||||
The string equality check is a bit longer to write, but it's more obvious what's going on.
|
||||
|
||||
## 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 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.
|
||||
|
||||
- For a strict equality check `===` these values are different, because each of them belong to a separate type of it's own.
|
||||
|
||||
- For evaluation of other comparisons including `<`, `>`, `<=`, `>=`, these values are converted to a number. We surely remember that `null` becomes `0`, while `undefined` becomes `NaN`.
|
||||
|
||||
Now let's see funny things that happen when we apply those rules.
|
||||
|
||||
### Strange result: null vs 0
|
||||
|
||||
Let's compare `null` with a zero:
|
||||
|
||||
```js run
|
||||
alert( null > 0 ); // false
|
||||
alert( null == 0 ); // false
|
||||
alert( null >= 0 ); // *!*true*/!*
|
||||
```
|
||||
|
||||
Yeah, mathematically that's strange. The last result states that "`null` is equal or greater than zero", and the former comparisons contradict it.
|
||||
|
||||
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.
|
||||
|
||||
That's why we have a strange-looking situation above.
|
||||
|
||||
### An uncomparable undefined
|
||||
|
||||
The value `undefined` shouldn't participate in comparisons at all:
|
||||
|
||||
```js run
|
||||
alert( undefined > 0 ); // false (1)
|
||||
alert( undefined < 0 ); // false (2)
|
||||
alert( undefined == 0 ); // false (3)
|
||||
```
|
||||
|
||||
Why does it dislike a zero so much? Always false!
|
||||
|
||||
We've got such result, because:
|
||||
|
||||
- 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.
|
||||
|
||||
### Conclusion
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
- Comparison operators return a logical value.
|
||||
- Strings are compared letter-by-letter in the "dictionary" order.
|
||||
- When values of different types are compared, they get converted to numbers (with the exclusion of a strict equality check).
|
||||
- Values `null` and `undefined` equal `==` each other and do not equal any other value.
|
||||
- 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.
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |