Parentheses can be omitted even if the constructor function has arguments:
```js
new function(test) {
return { test }
}
// Works the same as
new (function(test) {
return { test }
})();
```
Replace the value in the middle by "Classics". changed to Replace the value in the middle with "Classics" as the word 'with' describes the situation better
According to MDN, the precedence of unary plus, unary negation,
exponentiation, multiplication, division, addition, and
subtraction is 1 lower than it is in the document
Noticed that the word implementing was spelt incorrectly within the section for pointercancel events, thus I decided to correct it for reading comprehension reasons.
In the first paragraph, both of the following are correct:
you'll need other resources.
you'll need access to other sources.
I propose the first version
There is no hyphen in In-between, so you could write here: in between or between - but between is by far better.
I think it's safe now to assume that localStorage can store at least 5MB of data since the last time 2MB was mentioned was in 2015 for Android Browser v4 which has a reported global usage of 0.36% according to caniuse.com. Its' current version of 100 seems to support the same 5MB standard
Hey there! I suggest to slightly modify the first test case, so its input cover both checks in the solution.
Currently omitting the check for _a_ still let solution to pass the test.
```js
if (/* val < a || */ val > b) {
arr.splice(i, 1);
i--;
}
```
Removed the double quotes in the explanation for unary operator precedence in the file /1-js/02-first-steps/08-operators/article.md, so that readers do not potentially misinterpret the expression as a string.
ms - official international name for millisecond. 1 ms = 1 * 10**(-3) second (or 1e-3). Source : https://en.wikipedia.org/wiki/Metric_prefix .
0.000001 or 1e-6 - it's microsecond. Better name for this variable 'mcs' or 'us'. 'mcs' easier to understand.
Change the phrase "a property" to "the property" in line 57 (`Here the line (*) sets animal to be a prototype of rabbit.`) because it made it sound like an object can inherit more than one prototype at a time.
The sentence should say "Why we need tests" with no question mark, or "Why do we need tests?" I think keeping the question mark makes it more personal.
This mostly has readability improvements. There is one change, adding "(this is the same as (result => alert(result))" to a comment, that is solely there for clarification, to help out people learning about this for the first time.
I do not think it's likely but I do not want anyone to mistake those lines for legitimate JS expressions. I modified those two lines to match the format of pretty much every other comment in the article.
I think argN represents count of arbitrary parameters. But this syntax looks like "rest syntax". It could be more understandable to change it like this.
- comments are in pairs. The first of the pair talks about what
happened "caching" and the second pair talks about what was
alerted "the same". This is confusing.
- changed comment so both lines tell the reader what happened
and what result was returned.
We can declare local variables and give them initial values in parameter list of function definition. So we have another way to create local variables.
In the section describing the usage of `"super"`, example output says `// White Rabbit stands still. White rabbit hides!`
The `name` member in this example is set to `White Rabbit`, so the second sentence above should say `White Rabbit hides!` (capital R)
All operators should return a value because of the definition of the term 'operator'.
I could not find an operator as an exception which doesn't return a value.
Do you?
In the section "String concatenation with binary +", the example of 2 + 2 + "1" was given, but there was no example for when the first operand is a string.
Commit 10d1b1f25 added a hint about which word would be found by
a certain regexp:
"A call to str.match(/\w+/) will find only the first word in the line
(var). That’s not it."
Unfortunately the result is incorrect: the regexp would find `let`, not
`var`.
Updating the hint should resolve any confusion. The example has been
tested in the console to ensure that the regexp does indeed return
`let`.
This updates a small grammar error and adds some helpful info. Hoping it's better now. Let me know if you need any more changes and I'll update it immediately.
1. Without a real sorting part, the data output is not the same as with real sort (as the array is not really sorted when the callback returns `undefined`).
2. Current example may somehow encourage a reader to write sorting callbacks with undetermined behavior.
The task asks to multiply numeric object 'properties', however the term 'object properties' include both the 'property keys' of the object as well as the 'property values' of the object. It is clear the intention of the task is to change property values.
This change improves clarity of the task description.
An interesting question may arise in the example above: what’s the value of this inside set fullName(value)? Where are the properties this.name and this.surname written: into user or admin?
The answer is simple: this is not affected by prototypes at all.
No matter where the method is found: in an object or its prototype. In a method call, this is always the object before the dot.
So, the setter call admin.fullName= uses admin as this, not user.
That is actually a super-important thing, because we may have a big object with many methods, and have objects that inherit from it. And when the inheriting objects run the inherited methods, they will modify only their own states, not the state of the big object.
The example code doesn't show these concepts. Also, these additions can make readers ask questions before the explanation of the example code.
"// obj.toString === obj.__proto__.toString == Object.prototype.toString"
It is look like JS code but it gives different result from what we want to get.
There is different kind of equality operator ant these give more confusing what is the purpose of these?
It can be better to separate this line into 2 line of code to make it sensible and readable.
Subject and code is already hard but there is no need to make readers ask unnecessary questions.
The title makes me ask "is 'if' keyword operator or not?".
I think 'if' is not operator because it does not return any value and it is called if-statement.
`openRequest.result.version` in `onupgradeneeded` is not the current DB version. It is the requested version, equal to `event.newVersion`. `event.oldVersion` contains the current version.
I used the solution and examples already in the article.
I chose to make the test cases use Array.reduce() to compute the sum,
instead of hard-coding the answer myself.
Not sure how good of practice that is.
Cross-origin requests initiated by embedded images and forms actually bring cookies by default. Though it is incorrect to say that all cross-origin requests do not bring credentials by default.
true || alert("printed")
false || alert("not printed")
This is confusing to a student as the first won't be printed, but the second will print "not printed". I've reversed it to this so it makes much more sense to a learner:
true || alert("not printed")
false || alert("printed")
I had to look this up, not recalling having heard "somewhy" before. It's clear what it means, but is not a word in American English (though apparently it is used in British English, at least sometimes). Maybe should be a word, but somewhy it isn't.
Object.assign() is referring to wrong article, which is Sympol.
so I fix it to the right article "objects" with the right section #Cloning and merging, Object.assign
I think this is the way it is typically used here and elsewhere. reserving "brackets" without a qualifier for indicating square brackets., so probably no explanation is necessary.
But, for those who want to know more:
It does seem to be the case that in British English "brackets" typically means "round brackets", which are parentheses, but in American English "brackets" typically means square brackets ("[]").
Admittedly, "brackets" is easier to spell. And to pronounce. Even to type, once you get used to it.
"if arguments count" -> "if the arguments count"
"allows to easily" -> "allows us to easily"
"seen in the logging example:" -> "seen in the logging example,"
rephrasing rest of above sentence for readability
According to the MDN precedence-table you've linked some precedence numbers are incorrect. Having a quick look at different language versions (French and Russian) this error may has to be corrected at every version.
"`import` allows to import functionality.." -> "`import` allows the import of functionality..."
"relative the current file" -> "relative to the current file,"
My proposed change may not be right, but "make a request to URL" was unclear, and it's `fetch` that's used below to make the request. If 'request to URL' has some special meaning and is what you want to say, maybe some rephrasing is in order.
Several punctuation changes, yielding:
"1. We use the browser [fetch](info:fetch) method to download from a remote URL. It allows us to supply authorization and other headers if needed -- here GitHub requires `User-Agent`.
2. The fetch result is parsed as JSON. That's again a `fetch`-specific method.
3. We should get the next page URL from the `Link` header of the response. It has a special format, so we use a regexp for that. The next page URL may look like `https://api.github.com/repositories/93253246/commits?page=2`. It's generated by GitHub itself.
4. Then we yield all commits received, and when they finish, the next `while(url)` iteration will trigger, making one more request."
"yield is a two-way road" -> "yield is a two-way street"
"Two way street" is by far the more common and accepted way to say this. If you look up "two-way road" you will typically be redirected to "two-way street".
Small punctuation change.
Separately, I didn't change anything on this today, but note that line 34 above:
"So to summarize: the executor runs automatically and attempts to perform a job. When it is finished with the attempt it calls `resolve` if it was successful or `reject` if there was an error."
was, before it was changed recently, pretty much the same as line 82 above:
"To summarize, the executor should perform a job (usually something that takes time) and then call `resolve` or `reject` to change the state of the corresponding promise object."
So maybe some revision there is in order -- to not have both, or to change one or both. Not familiar enough with the article at this point to make the revision.
It was not mentioned earlier in the article that “A property can be either an accessor (has get/set methods) or a data property (has a value), not both”
So,we should not say "once again".
Remove comma, change spelling of "labeled".
While both "labelled" and "labeled" are correct, "labeled" is the preferred American spelling (though the British spelling "labelled" is more logical, given the general rules of English spelling, such as they are, since the "e" sound before the "l" is short, not long). Still, probably better with American spelling.
Adding 'object' after 'Property descriptor' -- even though it is said not far above that the 'property descriptor' returned by `Object.getOwnPropertyDescriptor` is an object, I think it wouldn't hurt to discretely include that info here (though of course it's also implied by the usage in the examples). Especially if someone is quickly scanning the article looking for `Object.defineProperty` and didn't just read the part above.
Grammar and phrasing changes to first paragraph. Wasn't 100% sure didn't change meaning and was going to leave it for review, but it seems I already committed it somehow when I was trying to make revisions, so hope it's right.
'awaits till `onclick`' -> "waits until the `onclick`".
"awaits" doesn't usually go with "until" (or "till" or "'til"). I can await someone's arrival, or I can wait until they arrive.
An alternate phrasing using "await" could be "it awaits the completion of the `onclick` processing".
When assigning the static method `staticMethod` to the `User` class, as a property directly, no parentheses should be used after `User`, since this leads to an error: `SyntaxError: Unexpected token '('`. For this reason, such parentheses have to be removed.
"but strongly" -> "but is strongly". "is strongly not recommended" is still a bit odd, though it's readable and totally understandable. Could maybe be changed to "but is strongly discouraged". Still, not bad as (now) is.
'"pro" and "contra" -> 'pros and cons'.
'pros and cons' is a much more typical way of saying it. But "pro" and "contra" is interesting. I hadn't previously thought about what "cons" stood for, though now it seems obvious.
Also, punctuation change.
Let's see what's so special about JavaScript, what we can achieve with it, and which other technologies play well with it.
Let's see what's so special about JavaScript, what we can achieve with it, and what other technologies play well with it.
## What is JavaScript?
*JavaScript* was initially created to *"make web pages alive"*.
*JavaScript* was initially created to "make web pages alive".
The programs in this language are called *scripts*. They can be written right in a web page's HTML and run automatically as the page loads.
@ -24,18 +24,18 @@ The browser has an embedded engine sometimes called a "JavaScript virtual machin
Different engines have different "codenames". For example:
- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- in Chrome and Opera.
- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- in Chrome, Opera and Edge.
- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- in Firefox.
- ...There are other codenames like "Trident" and "Chakra" for different versions of IE, "ChakraCore" for Microsoft Edge, "Nitro" and "SquirrelFish" for Safari, etc.
- ...There are other codenames like "Chakra" for IE, "JavaScriptCore", "Nitro" and "SquirrelFish" for Safari, etc.
The terms above are good to remember because they are used in developer articles on the internet. We'll use them too. For instance, if "a feature X is supported by V8", then it probably works in Chrome and Opera.
The terms above are good to remember because they are used in developer articles on the internet. We'll use them too. For instance, if "a feature X is supported by V8", then it probably works in Chrome, Opera and Edge.
```smart header="How do engines work?"
Engines are complicated. But the basics are easy.
1. The engine (embedded if it's a browser) reads ("parses") the script.
2. Then it converts ("compiles") the script to the machine language.
2. Then it converts ("compiles") the script to machine code.
3. And then the machine code runs, pretty fast.
The engine applies optimizations at each step of the process. It even watches the compiled script as it runs, analyzes the data that flows through it, and further optimizes the machine code based on that knowledge.
@ -43,7 +43,7 @@ The engine applies optimizations at each step of the process. It even watches th
## What can in-browser JavaScript do?
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.
Modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or the CPU, because it was initially created for browsers which do not require it.
JavaScript's capabilities greatly depend on the environment it's running in. For instance, [Node.js](https://wikipedia.org/wiki/Node.js) supports functions that allow JavaScript to read/write arbitrary files, perform network requests, etc.
@ -59,25 +59,25 @@ For instance, in-browser JavaScript is able to:
## What CAN'T in-browser JavaScript do?
JavaScript's abilities in the browser are limited for the sake of the user's safety. The aim is to prevent an evil webpage from accessing private information or harming the user's data.
JavaScript's abilities in the browser are limited to protect the user's safety. The aim is to prevent an evil webpage from accessing private information or harming the user's data.
Examples of such restrictions include:
- JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS system functions.
- JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS functions.
Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like "dropping" a file into a browser window or selecting it via an `<input>` tag.
There are ways to interact with camera/microphone and other devices, but they require a user's explicit permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the [NSA](https://en.wikipedia.org/wiki/National_Security_Agency).
- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other if they come from different sites (from a different domain, protocol or port).
There are ways to interact with the camera/microphone and other devices, but they require a user's explicit permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the [NSA](https://en.wikipedia.org/wiki/National_Security_Agency).
- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other page if they come from different sites (from a different domain, protocol or port).
This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and contain a special JavaScript code that handles it. We'll cover that in the tutorial.
This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and must contain special JavaScript code that handles it. We'll cover that in the tutorial.
This limitation is, again, for the user's safety. A page from `http://anysite.com` which a user has opened must not be able to access another browser tab with the URL `http://gmail.com` and steal information from there.
This limitation is, again, for the user's safety. A page from `http://anysite.com` which a user has opened must not be able to access another browser tab with the URL `http://gmail.com`, for example, and steal information from there.
- JavaScript can easily communicate over the net to the server where the current page came from. But its ability to receive data from other sites/domains is crippled. Though possible, it requires explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's a safety limitation.

Such limits do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow plugin/extensions which may ask for extended permissions.
Such limitations do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow plugins/extensions which may ask for extended permissions.
## What makes JavaScript unique?
@ -86,13 +86,13 @@ There are at least *three* great things about JavaScript:
```compare
+ Full integration with HTML/CSS.
+ Simple things are done simply.
+ Support by all major browsers and enabled by default.
+ Supported by all major browsers and enabled by default.
```
JavaScript is the only browser technology that combines these three things.
That's what makes JavaScript unique. That's why it's the most widespread tool for creating browser interfaces.
That said, JavaScript also allows to create servers, mobile applications, etc.
That said, JavaScript can be used to create servers, mobile applications, etc.
## Languages "over" JavaScript
@ -100,21 +100,23 @@ The syntax of JavaScript does not suit everyone's needs. Different people want d
That's to be expected, because projects and requirements are different for everyone.
So recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run in the browser.
So, recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run in the browser.
Modern tools make the transpilation very fast and transparent, actually allowing developers to code in another language and auto-converting it "under the hood".
Examples of such languages:
- [CoffeeScript](http://coffeescript.org/) is a "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it.
- [TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing" to simplify the development and support of complex systems. It is developed by Microsoft.
- [Flow](http://flow.org/) also adds data typing, but in a different way. Developed by Facebook.
- [CoffeeScript](https://coffeescript.org/) is "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it.
- [TypeScript](https://www.typescriptlang.org/) is concentrated on adding "strict data typing" to simplify the development and support of complex systems. It is developed by Microsoft.
- [Flow](https://flow.org/) also adds data typing, but in a different way. Developed by Facebook.
- [Dart](https://www.dartlang.org/) is a standalone language that has its own engine that runs in non-browser environments (like mobile apps), but also can be transpiled to JavaScript. Developed by Google.
- [Brython](https://brython.info/) is a Python transpiler to JavaScript that enables the writing of applications in pure Python without JavaScript.
- [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) is a modern, concise and safe programming language that can target the browser or Node.
There are more. Of course, even if we use one of transpiled languages, we should also know JavaScript to really understand what we're doing.
There are more. Of course, even if we use one of these transpiled languages, we should also know JavaScript to really understand what we're doing.
## Summary
- JavaScript was initially created as a browser-only language, but is now used in many other environments as well.
- Today, JavaScript has a unique position as the most widely-adopted browser language with full integration with HTML/CSS.
- JavaScript was initially created as a browser-only language, but it is now used in many other environments as well.
- Today, JavaScript has a unique position as the most widely-adopted browser language, fully integrated with HTML/CSS.
- There are many languages that get "transpiled" to JavaScript and provide certain features. It is recommended to take a look at them, at least briefly, after mastering JavaScript.
This book is a *tutorial*. It aims to help you gradually learn the language. But once you're familiar with the basics, you'll need other sources.
This book is a *tutorial*. It aims to help you gradually learn the language. But once you're familiar with the basics, you'll need other resources.
## Specification
@ -9,24 +9,19 @@ This book is a *tutorial*. It aims to help you gradually learn the language. But
But being that formalized, it's difficult to understand at first. So if you need the most trustworthy source of information about the language details, the specification is the right place. But it's not for everyday use.
A new specification version is released every year. In-between these releases, the latest specification draft is at <https://tc39.es/ecma262/>.
A new specification version is released every year. Between these releases, the latest specification draft is at <https://tc39.es/ecma262/>.
To read about new bleeding-edge features, including those that are "almost standard" (so-called "stage 3"), see proposals at <https://github.com/tc39/proposals>.
Also, if you're in developing for the browser, then there are other specs covered in the [second part](info:browser-environment) of the tutorial.
Also, if you're developing for the browser, then there are other specifications covered in the [second part](info:browser-environment) of the tutorial.
## Manuals
- **MDN (Mozilla) JavaScript Reference** is a manual with examples and other information. It's great to get in-depth information about individual language functions, methods etc.
- **MDN (Mozilla) JavaScript Reference** is the main manual with examples and other information. It's great to get in-depth information about individual language functions, methods etc.
One can find it at <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference>.
You can find it at <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference>.
Although, it's often best to use an internet search instead. Just use "MDN [term]" in the query, e.g. <https://google.com/search?q=MDN+parseInt> to search for `parseInt` function.
- **MSDN**– Microsoft manual with a lot of information, including JavaScript (often referred to as JScript). If one needs something specific to Internet Explorer, better go there: <http://msdn.microsoft.com/>.
Also, we can use an internet search with phrases such as "RegExp MSDN" or "RegExp MSDN jscript".
Although, it's often best to use an internet search instead. Just use "MDN [term]" in the query, e.g. <https://google.com/search?q=MDN+parseInt> to search for the `parseInt` function.
## Compatibility tables
@ -34,9 +29,9 @@ JavaScript is a developing language, new features get added regularly.
To see their support among browser-based and other engines, see:
- <http://caniuse.com> - per-feature tables of support, e.g. to see which engines support modern cryptography functions: <http://caniuse.com/#feat=cryptography>.
- <https://caniuse.com> - per-feature tables of support, e.g. to see which engines support modern cryptography functions: <https://caniuse.com/#feat=cryptography>.
- <https://kangax.github.io/compat-table> - a table with language features and engines that support those or don't support.
All these resources are useful in real-life development, as they contain valuable information about language details, their support etc.
All these resources are useful in real-life development, as they contain valuable information about language details, their support, etc.
Please remember them (or this page) for the cases when you need in-depth information about a particular feature.
For Windows, there's also "Visual Studio", not to be confused with "Visual Studio Code". "Visual Studio" is a paid and mighty Windows-only editor, well-suited for the .NET platform. It's also good at JavaScript. There's also a free version [Visual Studio Community](https://www.visualstudio.com/vs/community/).
@ -31,8 +31,6 @@ In practice, lightweight editors may have a lot of plugins including directory-l
@ -29,10 +29,15 @@ The exact look of developer tools depends on your version of Chrome. It changes
- Here we can see the red-colored error message. In this case, the script contains an unknown "lalala" command.
- On the right, there is a clickable link to the source `bug.html:12` with the line number where the error has occurred.
Below the error message, there is a blue `>` symbol. It marks a "command line" where we can type JavaScript commands. Press `key:Enter` to run them (`key:Shift+Enter` to input multi-line commands).
Below the error message, there is a blue `>` symbol. It marks a "command line" where we can type JavaScript commands. Press `key:Enter` to run them.
Now we can see errors, and that's enough for a start. We'll come back to developer tools later and cover debugging more in-depth in the chapter <info:debugging-chrome>.
```smart header="Multi-line input"
Usually, when we put a line of code into the console, and then press `key:Enter`, it executes.
To insert multiple lines, press `key:Shift+Enter`. This way one can enter long fragments of JavaScript code.
```
## Firefox, Edge, and others
@ -50,12 +55,6 @@ Open Preferences and go to the "Advanced" pane. There's a checkbox at the bottom
Now `key:Cmd+Opt+C` can toggle the console. Also, note that the new top menu item named "Develop" has appeared. It has many commands and options.
```smart header="Multi-line input"
Usually, when we put a line of code into the console, and then press `key:Enter`, it executes.
To insert multiple lines, press `key:Shift+Enter`. This way one can enter long fragments of JavaScript code.
```
## Summary
- Developer tools allow us to see errors, run commands, examine variables, and much more.
@ -9,7 +9,7 @@ So first, let's see how we attach a script to a webpage. For server-side environ
## The "script" tag
JavaScript programs can be inserted into any part of an HTML document with the help of the `<script>` tag.
JavaScript programs can be inserted almost anywhere into an HTML document using the `<script>` tag.
For instance:
@ -46,7 +46,7 @@ The `<script>` tag contains JavaScript code which is automatically executed when
The `<script>` tag has a few attributes that are rarely used nowadays but can still be found in old code:
The `type` attribute: <code><script <u>type</u>=...></code>
: The old HTML standard, HTML4, required a script to have a `type`. Usually it was `type="text/javascript"`. It's not required anymore. Also, the modern HTML standard totally changed the meaning of this attribute. Now, it can be used for JavaScript modules. But that's an advanced topic; we'll talk about modules in another part of the tutorial.
: The old HTML standard, HTML4, required a script to have a `type`. Usually it was `type="text/javascript"`. It's not required anymore. Also, the modern HTML standard totally changed the meaning of this attribute. Now, it can be used for JavaScript modules. But that's an advanced topic, we'll talk about modules in another part of the tutorial.
The `language` attribute: <code><script <u>language</u>=...></code>
: This attribute was meant to show the language of the script. This attribute no longer makes sense because JavaScript is the default language. There is no need to use it.
@ -73,12 +73,12 @@ Script files are attached to HTML with the `src` attribute:
<scriptsrc="/path/to/script.js"></script>
```
Here, `/path/to/script.js` is an absolute path to the script from the site root. One can also provide a relative path from the current page. For instance, `src="script.js"` would mean a file `"script.js"` in the current folder.
Here, `/path/to/script.js` is an absolute path to the script from the site root. One can also provide a relative path from the current page. For instance, `src="script.js"`, just like `src="./script.js"`, would mean a file `"script.js"` in the current folder.
The code outputs `6` because JavaScript does not insert semicolons here. It is intuitively obvious that if the line ends with a plus `"+"`, then it is an "incomplete expression", so the semicolon is not required. And in this case that works as intended.
The code outputs `6` because JavaScript does not insert semicolons here. It is intuitively obvious that if the line ends with a plus `"+"`, then it is an "incomplete expression", so a semicolon there would be incorrect. And in this case, that works as intended.
**But there are situations where JavaScript "fails" to assume a semicolon where it is really needed.**
@ -56,45 +56,41 @@ Errors which occur in such cases are quite hard to find and fix.
If you're curious to see a concrete example of such an error, check this code out:
```js run
[1, 2].forEach(alert)
alert("Hello");
[1, 2].forEach(alert);
```
No need to think about the meaning of the brackets `[]` and `forEach` yet. We'll study them later. For now, just remember the result of the code: it shows `1` then `2`.
No need to think about the meaning of the brackets `[]` and `forEach` yet. We'll study them later. For now, just remember the result of running the code: it shows `Hello`, then `1`, then `2`.
Now, let's add an `alert` before the code and *not* finish it with a semicolon:
Now let's remove the semicolon after the `alert`:
```js run no-beautify
alert("There will be an error")
alert("Hello")
[1, 2].forEach(alert)
[1, 2].forEach(alert);
```
Now if we run the code, only the first `alert` is shown and then we have an error!
The difference compared to the code above is only one character: the semicolon at the end of the first line is gone.
But everything is fine again if we add a semicolon after `alert`:
```js run
alert("All fine now");
If we run this code, only the first `Hello` shows (and there's an error, you may need to open the console to see it). There are no numbers any more.
[1, 2].forEach(alert)
```
That's because JavaScript does not assume a semicolon before square brackets `[...]`. So, the code in the last example is treated as a single statement.
Now we have the "All fine now" message followed by `1` and `2`.
The error in the no-semicolon variant occurs because JavaScript does not assume a semicolon before square brackets `[...]`.
So, because the semicolon is not auto-inserted, the code in the first example is treated as a single statement. Here's how the engine sees it:
Here's how the engine sees it:
```js run no-beautify
alert("There will be an error")[1, 2].forEach(alert)
alert("Hello")[1, 2].forEach(alert);
```
But it should be two separate statements, not one. Such a merging in this case is just wrong, hence the error. This can happen in other situations.
Looks weird, right? Such merging in this case is just wrong. We need to put a semicolon after `alert` for the code to work correctly.
This can happen in other situations also.
````
We recommend putting semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community. Let's note once again -- *it is possible* to leave out semicolons most of the time. But it's safer -- especially for a beginner -- to use them.
## Comments
## Comments [#code-comments]
As time goes on, programs become more and more complex. It becomes necessary to add *comments* which describe what the code does and why.
@ -136,7 +132,7 @@ alert('World');
```
```smart header="Use hotkeys!"
In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey). For Mac, try `key:Cmd` instead of `key:Ctrl`.
In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey). For Mac, try `key:Cmd` instead of `key:Ctrl` and `key:Option` instead of `key:Shift`.
```
````warn header="Nested comments are not supported!"
We will learn functions (a way to group commands) soon. Looking ahead, let's note that `"use strict"` can be put at the beginning of the function body instead of the whole script. Doing that enables strict mode in that function only. But usually, people use it for the whole script.
Quite soon we're going to learn functions (a way to group commands), so let's note in advance that `"use strict"` can be put at the beginning of a function. Doing that enables strict mode in that function only. But usually people use it for the whole script.
````warn header="Ensure that \"use strict\" is at the top"
Please make sure that `"use strict"` is at the top of your scripts, otherwise strict mode may not be enabled.
@ -42,16 +41,18 @@ Only comments may appear above `"use strict"`.
```warn header="There's no way to cancel `use strict`"
There is no directive like `"no use strict"` that reverts the engine to old behavior.
Once we enter strict mode, there's no return.
Once we enter strict mode, there's no going back.
```
## Browser console
For the future, when you use a browser console to test features, please note that it doesn't `use strict` by default.
When you use a [developer console](info:devtools) to run code, please note that it doesn't `use strict` by default.
Sometimes, when `use strict` makes a difference, you'll get incorrect results.
You can try to press `key:Shift+Enter` to input multiple lines, and put `use strict` on top, like this:
So, how to actually `use strict` in the console?
First, you can try to press `key:Shift+Enter` to input multiple lines, and put `use strict` on top, like this:
```js
'use strict'; <Shift+Enterforanewline>
@ -61,25 +62,28 @@ You can try to press `key:Shift+Enter` to input multiple lines, and put `use str
It works in most browsers, namely Firefox and Chrome.
If it doesn't, the most reliable way to ensure `use strict` would be to input the code into console like this:
If it doesn't, e.g. in an old browser, there's an ugly, but reliable way to ensure `use strict`. Put it inside this kind of wrapper:
```js
(function() {
'use strict';
// ...your code...
// ...your code here...
})()
```
## Always "use strict"
## Should we "use strict"?
We have yet to cover the differences between strict mode and the "default" mode.
The question may sound obvious, but it's not so.
In the next chapters, as we learn language features, we'll note the differences between the strict and default modes. Luckily, there aren't many and they actually make our lives better.
One could recommend to start scripts with `"use strict"`... But you know what's cool?
For now, it's enough to know about it in general:
Modern JavaScript supports "classes" and "modules" - advanced language structures (we'll surely get to them), that enable `use strict` automatically. So we don't need to add the `"use strict"` directive, if we use them.
1. The `"use strict"` directive switches the engine to the "modern" mode, changing the behavior of some built-in features. We'll see the details later in the tutorial.
2. Strict mode is enabled by placing `"use strict"` at the top of a script or function. Several language features, like "classes" and "modules", enable strict mode automatically.
3. Strict mode is supported by all modern browsers.
4. We recommended always starting scripts with `"use strict"`. All examples in this tutorial assume strict mode unless (very rarely) specified otherwise.
**So, for now `"use strict";` is a welcome guest at the top of your scripts. Later, when your code is all in classes and modules, you may omit it.**
As of now, we've got to know about `use strict` in general.
In the next chapters, as we learn language features, we'll see the differences between the strict and old modes. Luckily, there aren't many and they actually make our lives better.
All examples in this tutorial assume strict mode unless (very rarely) specified otherwise.
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.
Note, we could use a shorter name `planet`, but it might not be obvious what planet it refers to. It's nice to be more verbose. At least until the variable isNotTooLong.
Here we have a constant `birthday` date and the `age` is calculated from `birthday` with the help of some code (it is not provided for shortness, and because details don't matter here).
Here we have a constant `birthday` for the date, and also the `age` constant.
The `age` is calculated from `birthday` using `someCode()`, which means a function call that we didn't explain yet (we will soon!), but the details don't matter here, the point is that `age` is calculated somehow based on the `birthday`.
Would it be right to use upper case for `birthday`? For `age`? Or even for both?
```js
const BIRTHDAY = '18.04.1982'; // make uppercase?
const BIRTHDAY = '18.04.1982'; // make birthday uppercase?
const AGE = someCode(BIRTHDAY); // make uppercase?
const AGE = someCode(BIRTHDAY); // make age uppercase?
@ -24,7 +24,7 @@ Now, we can put some data into it by using the assignment operator `=`:
let message;
*!*
message = 'Hello'; // store the string
message = 'Hello'; // store the string 'Hello' in the variable named message
*/!*
```
@ -64,6 +64,7 @@ let message = 'Hello';
```
Some people also define multiple variables in this multiline style:
```js no-beautify
let user = 'John',
age = 25,
@ -80,7 +81,6 @@ let user = 'John'
Technically, all these variants do the same thing. So, it's a matter of personal taste and aesthetics.
````smart header="`var` instead of `let`"
In older scripts, you may also find another keyword: `var` instead of `let`:
@ -104,6 +104,7 @@ For instance, the variable `message` can be imagined as a box labeled `"message"
We can put any value in the box.
We can also change it as many times as we want:
```js run
let message;
@ -135,6 +136,20 @@ alert(hello); // Hello world!
alert(message); // Hello world!
```
````warn header="Declaring twice triggers an error"
A variable should be declared only once.
A repeated declaration of the same variable is an error:
```js run
let message = "This";
// repeated 'let' leads to an error
let message = "That"; // SyntaxError: 'message' has already been declared
```
So, we should declare a variable once and then refer to it without `let`.
````
```smart header="Functional languages"
It's interesting to note that there exist [functional](https://en.wikipedia.org/wiki/Functional_programming) programming languages, like [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/) that forbid changing variable values.
@ -179,7 +194,7 @@ let my-name; // hyphens '-' aren't allowed in the name
```
```smart header="Case matters"
Variables named `apple` and `AppLE` are two different variables.
Variables named `apple` and `APPLE` are two different variables.
```
````smart header="Non-Latin letters are allowed, but not recommended"
@ -190,7 +205,7 @@ 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 from other countries may need to read it some time.
Technically, there is no error here. Such names are allowed, but there is an international convention to use English in variable names. Even if we're writing a small script, it may have a long life ahead. People from other countries may need to read it some time.
When a programmer is sure that a variable will never change, they can declare it with `const` to guarantee and clearly communicate that fact to everyone.
### Uppercase constants
There is a widespread practice to use constants as aliases for difficult-to-remember values that are known prior to execution.
@ -278,6 +292,7 @@ When should we use capitals for a constant and when should we name it normally?
Being a "constant" just means that a variable's value never changes. But there are constants that are known prior to execution (like a hexadecimal value for red) and there are constants that are *calculated* in run-time, during the execution, but do not change after their initial assignment.
For instance:
```js
const pageLoadTime = /* time taken by a webpage to load */;
A variable in JavaScript can contain any data. A variable can at one moment be a string and at another be a number:
A value in JavaScript is always of a certain type. For example, a string or a number.
There are eight basic data types in JavaScript. Here, we'll cover them in general and in the next chapters we'll talk about each of them in detail.
We can put any type in a variable. For example, a variable can at one moment be a string and then store a number:
```js
// no error
@ -8,11 +12,9 @@ let message = "hello";
message = 123456;
```
Programming languages that allow such things are called "dynamically typed", meaning that there are data types, but variables are not bound to any of them.
Programming languages that allow such things, such as JavaScript, are called "dynamically typed", meaning that there exist data types, but variables are not bound to any of them.
There are seven basic data types in JavaScript. Here, we'll cover them in general and in the next chapters we'll talk about each of them in detail.
## A number
## Number
```js
let n = 123;
@ -44,13 +46,15 @@ Besides regular numbers, there are so-called "special numeric values" which also
alert( "not a number" / 2 ); // NaN, such division is erroneous
```
`NaN` is sticky. Any further operation on `NaN` returns `NaN`:
`NaN` is sticky. Any further mathematical operation on `NaN` returns `NaN`:
```js run
alert( "not a number" / 2 + 5 ); // NaN
alert( NaN + 1 ); // NaN
alert( 3 * NaN ); // NaN
alert( "not a number" / 2 - 1 ); // NaN
```
So, if there's a `NaN` somewhere in a mathematical expression, it propagates to the whole result.
So, if there's a `NaN` somewhere in a mathematical expression, it propagates to the whole result (there's only one exception to that: `NaN ** 0` is `1`).
```smart header="Mathematical operations are safe"
Doing maths is "safe" in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc.
@ -62,14 +66,49 @@ Special numeric values formally belong to the "number" type. Of course they are
We'll see more about working with numbers in the chapter <info:number>.
## A string
## BigInt [#bigint-type]
In JavaScript, the "number" type cannot safely represent integer values larger than <code>(2<sup>53</sup>-1)</code> (that's `9007199254740991`), or less than <code>-(2<sup>53</sup>-1)</code> for negatives.
To be really precise, the "number" type can store larger integers (up to <code>1.7976931348623157 * 10<sup>308</sup></code>), but outside of the safe integer range <code>±(2<sup>53</sup>-1)</code> there'll be a precision error, because not all digits fit into the fixed 64-bit storage. So an "approximate" value may be stored.
For example, these two numbers (right above the safe range) are the same:
So to say, all odd integers greater than <code>(2<sup>53</sup>-1)</code> can't be stored at all in the "number" type.
For most purposes <code>±(2<sup>53</sup>-1)</code> range is quite enough, but sometimes we need the entire range of really big integers, e.g. for cryptography or microsecond-precision timestamps.
`BigInt` type was recently added to the language to represent integers of arbitrary length.
A `BigInt` value is created by appending `n` to the end of an integer:
As `BigInt` numbers are rarely needed, we don't cover them here, but devoted them a separate chapter <info:bigint>. Read it when you need such big numbers.
```smart header="Compatibility issues"
Right now, `BigInt` is supported in Firefox/Chrome/Edge/Safari, but not in IE.
```
You can check [*MDN* BigInt compatibility table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) to know which versions of a browser are supported.
## String
A string in JavaScript must be surrounded by quotes.
```js
let str = "Hello";
let str2 = 'Single quotes are ok too';
let phrase = `can embed ${str}`;
let phrase = `can embed another ${str}`;
```
In JavaScript, there are 3 types of quotes.
@ -78,7 +117,7 @@ In JavaScript, there are 3 types of quotes.
2. Single quotes: `'Hello'`.
3. Backticks: <code>`Hello`</code>.
Double and single quotes are "simple" quotes. There's no difference between them in JavaScript.
Double and single quotes are "simple" quotes. There's practically no difference between them in JavaScript.
Backticks are "extended functionality" quotes. They allow us to embed variables and expressions into a string by wrapping them in `${…}`, for example:
@ -102,12 +141,12 @@ alert( "the result is ${1 + 2}" ); // the result is ${1 + 2} (double quotes do n
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 and in Java it is `char`.
In some languages, there is a special "character" type for a single character. For example, in the C language and in Java it is called "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.
In JavaScript, there is no such type. There's only one type: `string`. A string may consist of zero characters (be empty), one character or many of them.
```
## A boolean (logical type)
## Boolean (logical type)
The boolean type has only two values: `true` and `false`.
@ -144,7 +183,7 @@ In JavaScript, `null` is not a "reference to a non-existing object" or a "null p
It's just a special value which represents "nothing", "empty" or "value unknown".
The code above states that `age` is unknown or empty for some reason.
The code above states that `age` is unknown.
## The "undefined" value
@ -155,49 +194,47 @@ The meaning of `undefined` is "value is not assigned".
If a variable is declared, but not assigned, then its value is `undefined`:
```js run
let x;
let age;
alert(x); // shows "undefined"
alert(age); // shows "undefined"
```
Technically, it is possible to assign `undefined` to any variable:
Technically, it is possible to explicitly assign `undefined` to a variable:
```js run
let x = 123;
let age = 100;
x = undefined;
// change the value to undefined
age = undefined;
alert(x); // "undefined"
alert(age); // "undefined"
```
...But we don't recommend doing that. Normally, we use `null` to assign an "empty" or "unknown" value to a variable, and we use `undefined` for checks like seeing if a variable has been assigned.
...But we don't recommend doing that. Normally, one uses `null` to assign an "empty" or "unknown" value to a variable, while `undefined` is reserved as a default initial value for unassigned things.
## Objects and Symbols
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 data and more complex entities. We'll deal with them later in the chapter <info:object> after we learn more about primitives.
All other types are called "primitive" because their values can contain only a single thing (be it a string or a number or whatever). In contrast, objects are used to store collections of data and more complex entities.
The `symbol` type is used to create unique identifiers for objects. We mention it here for completeness, but we'll study it after objects.
Being that important, objects deserve a special treatment. We'll deal with them later in the chapter <info:object>, after we learn more about primitives.
The `symbol` type is used to create unique identifiers for objects. We have to mention it here for the sake of completeness, but also postpone the details till we know objects.
## The typeof operator [#type-typeof]
The `typeof` operator returns the type of the argument. It's useful when we want to process values of different types differently or just want to do a quick check.
It supports two forms of syntax:
1. As an operator: `typeof x`.
2. As a function: `typeof(x)`.
In other words, it works with parentheses or without them. The result is the same.
The call to `typeof x` returns a string with the type name:
A call to `typeof x` returns a string with the type name:
The last three lines may need additional explanation:
1. `Math` is a built-in object that provides mathematical operations. We will learn it in the chapter <info:number>. Here, it serves just as an example of an object.
2. The result of `typeof null` is `"object"`. That's wrong. It is an officially recognized error in `typeof`, kept for compatibility. Of course, `null` is not an object. It is a special value with a separate type of its own. So, again, this is an error in the language.
3. The result of `typeof alert` is `"function"`, because `alert` is a function. We'll study functions in the next chapters where we'll also see that there's no special "function" type in JavaScript. Functions belong to the object type. But `typeof` treats them differently, returning `"function"`. That's not quite correct, but very convenient in practice.
2. The result of `typeof null` is `"object"`. That's an officially recognized error in `typeof`, coming from very early days of JavaScript and kept for compatibility. Definitely, `null` is not an object. It is a special value with a separate type of its own. The behavior of `typeof` is wrong here.
3. The result of `typeof alert` is `"function"`, because `alert` is a function. We'll study functions in the next chapters where we'll also see that there's no special "function" type in JavaScript. Functions belong to the object type. But `typeof` treats them differently, returning `"function"`. That also comes from the early days of JavaScript. Technically, such behavior isn't correct, but can be convenient in practice.
```smart header="The `typeof(x)` syntax"
You may also come across another syntax: `typeof(x)`. It's the same as `typeof x`.
To put it clear: `typeof` is an operator, not a function. The parentheses here aren't a part of `typeof`. It's the kind of parentheses used for mathematical grouping.
Usually, such parentheses contain a mathematical expression, such as `(2 + 2)`, but here they contain only one argument `(x)`. Syntactically, they allow to avoid a space between the `typeof` operator and its argument, and some people like it.
Some people prefer `typeof(x)`, although the `typeof x` syntax is much more common.
```
## Summary
There are 7 basic data types in JavaScript.
There are 8 basic data types in JavaScript.
- `number` for numbers of any kind: integer or floating-point.
- `string` for strings. A string may have one or more characters, there's no separate single-character type.
- `boolean` for `true`/`false`.
- `null` for unknown values -- a standalone type that has a single value `null`.
- `undefined` for unassigned values -- a standalone type that has a single value `undefined`.
- `object` for more complex data structures.
- `symbol` for unique identifiers.
- Seven primitive data types:
- `number` for numbers of any kind: integer or floating-point, integers are limited by <code>±(2<sup>53</sup>-1)</code>.
- `bigint` for integer numbers of arbitrary length.
- `string` for strings. A string may have zero or more characters, there's no separate single-character type.
- `boolean` for `true`/`false`.
- `null` for unknown values -- a standalone type that has a single value `null`.
- `undefined` for unassigned values -- a standalone type that has a single value `undefined`.
- `symbol` for unique identifiers.
- And one non-primitive data type:
- `object` for more complex data structures.
The `typeof` operator allows us to see which type is stored in a variable.
- Two forms: `typeof x` or `typeof(x)`.
- Usually used as `typeof x`, but `typeof(x)` is also possible.
- Returns a string with the name of the type, like `"string"`.
- For `null` returns `"object"` -- this is an error in the language, it's not actually an object.
In this part of the tutorial we cover JavaScript language "as is", without environment-specific tweaks.
But we'll still be using the browser as our demo environment, so we should know at least a few of its user-interface functions. In this chapter, we'll get familiar with the browser functions `alert`, `prompt` and `confirm`.
As we'll be using the browser as our demo environment, let's see a couple of functions to interact with the user: `alert`, `prompt` and `confirm`.
## alert
Syntax:
```js
alert(message);
```
This shows a message and pauses script execution until the user presses "OK".
This one we've seen already. It shows a message and waits for the user to press "OK".
For example:
@ -20,7 +12,7 @@ For example:
alert("Hello");
```
The mini-window with the message is called a *modal window*. The word "modal" means that the visitor can't interact with the rest of the page, press other buttons, etc. until they have dealt with the window. In this case -- until they press "OK".
The mini-window with the message is called a *modal window*. The word "modal" means that the visitor can't interact with the rest of the page, press other buttons, etc, until they have dealt with the window. In this case -- until they press "OK".
## prompt
@ -38,7 +30,11 @@ It shows a modal window with a text message, an input field for the visitor, and
`default`
: An optional second parameter, the initial value for the input field.
The visitor may type something in the prompt input field and press OK. Or they can cancel the input by pressing Cancel or hitting the `key:Esc` key.
```smart header="The square brackets in syntax `[...]`"
The square brackets around `default` in the syntax above denote that the parameter is optional, not required.
```
The visitor can type something in the prompt input field and press OK. Then we get that text in the `result`. Or they can cancel the input by pressing Cancel or hitting the `key:Esc` key, then we get `null` as the `result`.
The call to `prompt` returns the text from the input field or `null` if the input was canceled.
@ -7,7 +7,9 @@ For example, `alert` automatically converts any value to a string to show it. Ma
There are also cases when we need to explicitly convert a value to the expected type.
```smart header="Not talking about objects yet"
In this chapter, we won't cover objects. Instead, we'll study primitives first. Later, after we learn about objects, we'll see how object conversion works in the chapter <info:object-toprimitive>.
In this chapter, we won't cover objects. For now, we'll just be talking about primitives.
Later, after we learn about objects, in the chapter <info:object-toprimitive> we'll see how objects fit in.
```
## String Conversion
@ -68,7 +70,7 @@ Numeric conversion rules:
|`undefined`|`NaN`|
|`null`|`0`|
|<code>true and false</code> | `1` and `0` |
| `string` | Whitespaces from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. |
| `string` | Whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. |
Examples:
@ -81,18 +83,7 @@ alert( Number(false) ); // 0
Please note that `null` and `undefined` behave differently here: `null` becomes zero while `undefined` becomes `NaN`.
Almost all mathematical operations convert values to numbers. A notable exception is addition `+`. If one of the added values is a string, the other one is also converted to a string.
Then, it concatenates (joins) them:
```js run
alert( 1 + '2' ); // '12' (string to the right)
alert( '1' + 2 ); // '12' (string to the left)
```
This only happens when at least one of the arguments is a string. Otherwise, values are converted to numbers.
````
Most mathematical operators also perform such conversion, we'll see that in the next chapter.
## Boolean Conversion
@ -139,7 +130,7 @@ The conversion follows the rules:
|`undefined`|`NaN`|
|`null`|`0`|
|<code>true / false</code> | `1 / 0` |
| `string` | The string is read "as is", whitespaces from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. |
| `string` | The string is read "as is", whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. |
**`Boolean Conversion`** -- Occurs in logical operations. Can be performed with `Boolean(value)`.
4. The subtraction always converts to numbers, so it makes `" -9 "` a number `-9` (ignoring spaces around it).
5. `null` becomes `0` after the numeric conversion.
6. `undefined` becomes `NaN` after the numeric conversion.
7. Space characters, are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`.
7. Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`.
We know many operators from school. They are things like addition `+`, multiplication `*`, subtraction `-`, and so on.
In this chapter, we'll concentrate on aspects of operators that are not covered by school arithmetic.
In this chapter, we’ll start with simple operators, then concentrate on JavaScript-specific aspects, not covered by school arithmetic.
## Terms: "unary", "binary", "operand"
@ -28,9 +28,59 @@ Before we move on, let's grasp some common terminology.
Formally, in the examples above we have two different operators that share the same symbol: the negation operator, a unary operator that reverses the sign, and the subtraction operator, a binary operator that subtracts one number from another.
## String concatenation, binary +
## Maths
Now, let's see special features of JavaScript operators that are beyond school arithmetics.
The following math operations are supported:
- Addition `+`,
- Subtraction `-`,
- Multiplication `*`,
- Division `/`,
- Remainder `%`,
- Exponentiation `**`.
The first four are straightforward, while `%` and `**` need a few words about them.
### Remainder %
The remainder operator `%`, despite its appearance, is not related to percents.
The result of `a % b` is the [remainder](https://en.wikipedia.org/wiki/Remainder) of the integer division of `a` by `b`.
For instance:
```js run
alert( 5 % 2 ); // 1, a remainder of 5 divided by 2
alert( 8 % 3 ); // 2, a remainder of 8 divided by 3
```
### Exponentiation **
The exponentiation operator `a ** b` raises `a` to the power of `b`.
In school maths, we write that as a<sup>b</sup>.
For instance:
```js run
alert( 2 ** 2 ); // 2² = 4
alert( 2 ** 3 ); // 2³ = 8
alert( 2 ** 4 ); // 2⁴ = 16
```
Just like in maths, the exponentiation operator is defined for non-integer numbers as well.
For example, a square root is an exponentiation by ½:
```js run
alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root)
alert( 8 ** (1/3) ); // 2 (power of 1/3 is the same as a cubic root)
```
## String concatenation with binary +
Let's meet features of JavaScript operators that are beyond school arithmetics.
Usually, the plus operator `+` sums numbers.
@ -41,7 +91,7 @@ let s = "my" + "string";
alert(s); // mystring
```
Note that if one of the operands is a string, the other one is converted to a string too.
Note that if any of the operands is a string, then the other one is converted to a string too.
For example:
@ -50,22 +100,28 @@ alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
```
See, it doesn't matter whether the first operand is a string or the second one. The rule is simple: if either operand is a string, the other one is converted into a string as well.
However, note that operations run from left to right. If there are two numbers followed by a string, the numbers will be added before being converted to a string:
See, it doesn't matter whether the first operand is a string or the second one.
Here's a more complex example:
```js run
alert(2 + 2 + '1' ); // "41" and not "221"
```
String concatenation and conversion is a special feature of the binary plus `+`. Other arithmetic operators work only with numbers and always convert their operands to numbers.
For instance, subtraction and division:
Here, operators work one after another. The first `+` sums two numbers, so it returns `4`, then the next `+` adds the string `1` to it, so it's like `4 + '1' = '41'`.
```js run
alert( 2 - '1' ); // 1
alert( '6' / '2' ); // 3
alert('1' + 2 + 2); // "122" and not "14"
```
Here, the first operand is a string, the compiler treats the other two operands as strings too. The `2` gets concatenated to `'1'`, so it's like `'1' + 2 = "12"` and `"12" + 2 = "122"`.
The binary `+` is the only operator that supports strings in such a way. Other arithmetic operators work only with numbers and always convert their operands to numbers.
Here's the demo for subtraction and division:
```js run
alert( 6 - '2' ); // 4, converts '2' to a number
alert( '6' / '2' ); // 3, converts both operands to numbers
```
## Numeric conversion, unary +
@ -133,26 +189,27 @@ Parentheses override any precedence, so if we're not satisfied with the default
There are many operators in JavaScript. Every operator has a corresponding precedence number. The one with the larger number executes first. If the precedence is the same, the execution order is from left to right.
Here's an extract from the [precedence table](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence) (you don't need to remember this, but note that unary operators are higher than corresponding binary ones):
Here's an extract from the [precedence table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) (you don't need to remember this, but note that unary operators are higher than corresponding binary ones):
| Precedence | Name | Sign |
|------------|------|------|
| ... | ... | ... |
| 16 | unary plus | `+` |
| 16 | unary negation | `-` |
| 14 | multiplication | `*` |
| 14 | division | `/` |
| 13 | addition | `+` |
| 13 | subtraction | `-` |
| 14 | unary plus | `+` |
| 14 | unary negation | `-` |
| 13 | exponentiation | `**` |
| 12 | multiplication | `*` |
| 12 | division | `/` |
| 11 | addition | `+` |
| 11 | subtraction | `-` |
| ... | ... | ... |
| 3 | assignment | `=` |
| 2 | assignment | `=` |
| ... | ... | ... |
As we can see, the "unary plus" has a priority of `16` which is higher than the `13` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition.
As we can see, the "unary plus" has a priority of `14` which is higher than the `11` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition.
## 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`.
Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `2`.
That's why, when we assign a variable, like `x = 2 * 2 + 1`, the calculations are done first and then the `=` is evaluated, storing the result in `x`.
@ -162,24 +219,11 @@ let x = 2 * 2 + 1;
alert( x ); // 5
```
It is possible to chain assignments:
### Assignment = returns a value
```js run
let a, b, c;
The fact of `=` being an operator, not a "magical" language construct has an interesting implication.
*!*
a = b = c = 2 + 2;
*/!*
alert( a ); // 4
alert( b ); // 4
alert( c ); // 4
```
Chained assignments evaluate from right to left. First, the rightmost expression `2 + 2` is evaluated and then assigned to the variables on the left: `c`, `b` and `a`. At the end, all the variables share a single value.
````smart header="The assignment operator `\"=\"` returns a value"
An operator always returns a value. That's obvious for most of them like addition `+` or multiplication `*`. But the assignment operator follows this rule too.
All operators in JavaScript return a value. That's obvious for `+` and `-`, but also true for `=`.
The call `x = value` writes the `value` into `x`*and then returns it*.
@ -199,49 +243,74 @@ alert( c ); // 0
In the example above, the result of expression `(a = b + 1)` is the value which was assigned to `a` (that is `3`). It is then used for further evaluations.
Funny code, isn't it? We should understand how it works, because sometimes we see it in JavaScript libraries, but shouldn't write anything like that ourselves. Such tricks definitely don't make code clearer or readable.
````
Funny code, isn't it? We should understand how it works, because sometimes we see it in JavaScript libraries.
## Remainder %
Although, please don't write the code like that. Such tricks definitely don't make code clearer or readable.
The remainder operator `%`, despite its appearance, is not related to percents.
### Chaining assignments
The result of `a % b` is the remainder of the integer division of `a` by `b`.
For instance:
Another interesting feature is the ability to chain assignments:
```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
let a, b, c;
*!*
a = b = c = 2 + 2;
*/!*
alert( a ); // 4
alert( b ); // 4
alert( c ); // 4
```
## Exponentiation **
Chained assignments evaluate from right to left. First, the rightmost expression `2 + 2` is evaluated and then assigned to the variables on the left: `c`, `b` and `a`. At the end, all the variables share a single value.
The exponentiation operator `**` is a recent addition to the language.
Once again, for the purposes of readability it's better to split such code into few lines:
For a natural number `b`, the result of `a ** b` is `a` multiplied by itself `b` times.
```js
c = 2 + 2;
b = c;
a = c;
```
That's easier to read, especially when eye-scanning the code fast.
For instance:
## Modify-in-place
```js run
alert( 2 ** 2 ); // 4 (2 * 2)
alert( 2 ** 3 ); // 8 (2 * 2 * 2)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
We often need to apply an operator to a variable and store the new result in that same variable.
For example:
```js
let n = 2;
n = n + 5;
n = n * 2;
```
The operator works for non-integer numbers as well.
For instance:
This notation can be shortened using the operators `+=` and `*=`:
```js run
alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root, that's maths)
alert( 8 ** (1/3) ); // 2 (power of 1/3 is the same as a cubic root)
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 all arithmetical and bitwise operators: `/=`, `-=`, etc.
Such operators have the same precedence as a normal assignment, so they run after most other calculations:
```js run
let n = 2;
n *= 3 + 5; // right part evaluated first, same as n *= 8
alert( n ); // 16
```
## Increment/decrement
<!-- Can't use -- in title, because built-in parse turns it into –-->
<!-- Can't use -- in title, because the built-in parser turns it into a 'long dash'–-->
Increasing or decreasing a number by one is among the most common numerical operations.
@ -368,41 +437,7 @@ The list of operators:
- RIGHT SHIFT ( `>>` )
- ZERO-FILL RIGHT SHIFT ( `>>>` )
These operators are used very rarely. To understand them, we need to delve into low-level number representation and it would not be optimal to do that right now, especially since we won't need them any time soon. If you're curious, you can read the [Bitwise Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) article on MDN. It would be more practical to do that when a real need arises.
## Modify-in-place
We often need to apply an operator to a variable and store the new result in that same variable.
For example:
```js
let n = 2;
n = n + 5;
n = n * 2;
```
This notation can be shortened using the 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 all arithmetical and bitwise operators: `/=`, `-=`, etc.
Such operators have the same precedence as a normal assignment, so they run after most other calculations:
```js run
let n = 2;
n *= 3 + 5;
alert( n ); // 16 (right part evaluated first, same as n *= 8)
```
These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) chapter on MDN when a need arises.
- Greater/less than or equals: <code>a >= b</code>, <code>a <= b</code>.
- Equals: `a == b` (please note the double equals sign `=`. A single symbol `a = b` would mean an assignment).
- Not equals. In maths the notation is <code>≠</code>, but in JavaScript it's written as an assignment with an exclamation sign before it: <code>a != b</code>.
- Equals: `a == b`, please note the double equality sign `==` means the equality test, while a single one `a = b` means an assignment.
- Not equals: In maths the notation is <code>≠</code>, but in JavaScript it's written as <code>a != b</code>.
In this article we'll learn more about different types of comparisons, how JavaScript makes them, including important peculiarities.
At the end you'll find a good recipe to avoid "JavaScript quirks"-related issues.
## Boolean is the result
Like all other operators, a comparison returns a value. In this case, the value is a boolean.
All comparison operators return a boolean value:
- `true` -- means "yes", "correct" or "the truth".
- `false` -- means "no", "wrong" or "not the truth".
@ -51,7 +57,9 @@ The algorithm to compare two strings is simple:
4. Repeat until the end of either string.
5. If both strings end at the same length, then they are equal. Otherwise, the longer string is greater.
In the examples above, the comparison `'Z' > 'A'` gets to a result at the first step while the strings `"Glow"` and `"Glee"` are compared character-by-character:
In the first example above, the comparison `'Z' > 'A'` gets to a result at the first step.
The second comparison `'Glow'` and `'Glee'` needs more steps as strings are compared character-by-character:
1. `G` is the same as `G`.
2. `l` is the same as `l`.
@ -192,13 +200,12 @@ We get these results 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`, `undefined`, and no other value.
### Evade problems
### Avoid problems
Why did we go over these examples? Should we remember these peculiarities all the time? Well, not really. Actually, these tricky things will gradually become familiar over time, but there's a solid way to evade problems with them:
Why did we go over these examples? Should we remember these peculiarities all the time? Well, not really. Actually, these tricky things will gradually become familiar over time, but there's a solid way to avoid problems with them:
Just treat any comparison with `undefined/null` except the strict equality `===` with exceptional care.
Don't use comparisons `>= > < <=` with a variable which may be `null/undefined`, unless you're really sure of what you're doing. If a variable can have these values, check for them separately.
- Treat any comparison with `undefined/null` except the strict equality `===` with exceptional care.
- Don't use comparisons `>= > < <=` with a variable which may be `null/undefined`, unless you're really sure of what you're doing. If a variable can have these values, check for them separately.
There are three logical operators in JavaScript: `||` (OR), `&&` (AND), `!` (NOT).
There are four logical operators in JavaScript: `||` (OR), `&&` (AND), `!` (NOT), `??` (Nullish Coalescing). Here we cover the first three, the `??` operator is in the next article.
Although they are called "logical", they can be applied to values of any type, not only boolean. Their result can also be of any type.
alert( name ); // selects "John" – the first truthy value
```
If both `currentUser` and `defaultUser` were falsy, `"unnamed"` would be the result.
If all variables were falsy, `"Anonymous"` would show up.
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. This process is called "a short-circuit evaluation" because it goes as short as possible from left to right.
Another feature of OR `||` operator is the so-called "short-circuit" evaluation.
This is clearly seen when the expression given as the second argument has a side effect like a variable assignment.
It means that `||` processes its arguments until the first truthy value is reached, and then the value is returned immediately, without even touching the other argument.
In the example below, `x` does not get assigned:
The importance of this feature becomes obvious if an operand isn't just a value, but an expression with a side effect, such as a variable assignment or a function call.
In the example below, only the second message is printed:
```js run no-beautify
let x;
*!*true*/!* || (x = 1);
alert(x); // undefined, because (x = 1) not evaluated
*!*true*/!* || alert("not printed");
*!*false*/!* || alert("printed");
```
If, instead, the first argument is `false`, `||` evaluates the second one, thus running the assignment:
In the first line, the OR `||` operator stops the evaluation immediately upon seeing `true`, so the `alert` isn't run.
```js run no-beautify
let x;
*!*false*/!* || (x = 1);
alert(x); // 1
```
An assignment is a simple case. There may be side effects, that won't show up if the evaluation doesn't reach them.
As we can see, such a use case is a "shorter way of doing `if`". The first operand is converted to boolean. If it's false, the second one is evaluated.
Most of time, it's better to use a "regular" `if` to keep the code easy to understand, but sometimes this can be handy.
Sometimes, people use this feature to execute commands only if the condition on the left part is falsy.
## && (AND)
@ -236,7 +223,8 @@ The precedence of AND `&&` operator is higher than OR `||`.
So the code `a && b || c && d` is essentially the same as if the `&&` expressions were in parentheses: `(a && b) || (c && d)`.
````
Just like OR, the AND `&&` operator can sometimes replace `if`.
````warn header="Don't replace `if` with `||` or `&&`"
Sometimes, people use the AND `&&` operator as a "shorter way to write `if`".
For instance:
@ -253,14 +241,12 @@ So we basically have an analogue for:
```js run
let x = 1;
if (x > 0) {
alert( 'Greater than zero!' );
}
if (x > 0) alert( 'Greater than zero!' );
```
The variant with `&&` appears shorter. But `if` is more obvious and tends to be a little bit more readable.
Although, the variant with `&&` appears shorter, `if` is more obvious and tends to be a little bit more readable. So we recommend using every construct for its purpose: use `if` if we want `if` and use `&&` if we want AND.
````
So we recommend using every construct for its purpose: use `if` if we want if and use `&&` if we want AND.
The nullish coalescing operator is written as two question marks `??`.
As it treats `null` and `undefined` similarly, we'll use a special term here, in this article. For brevity, we'll say that a value is "defined" when it's neither `null` nor `undefined`.
The result of `a ?? b` is:
- if `a` is defined, then `a`,
- if `a` isn't defined, then `b`.
In other words, `??` returns the first argument if it's not `null/undefined`. Otherwise, the second one.
The nullish coalescing operator isn't anything completely new. It's just a nice syntax to get the first "defined" value of the two.
We can rewrite `result = a ?? b` using the operators that we already know, like this:
```js
result = (a !== null && a !== undefined) ? a : b;
```
Now it should be absolutely clear what `??` does. Let's see where it helps.
The common use case for `??` is to provide a default value.
For example, here we show `user` if its value isn't `null/undefined`, otherwise `Anonymous`:
```js run
let user;
alert(user ?? "Anonymous"); // Anonymous (user not defined)
```
Here's the example with `user` assigned to a name:
```js run
let user = "John";
alert(user ?? "Anonymous"); // John (user defined)
```
We can also use a sequence of `??` to select the first value from a list that isn't `null/undefined`.
Let's say we have a user's data in variables `firstName`, `lastName` or `nickName`. All of them may be not defined, if the user decided not to fill in the corresponding values.
We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are `null/undefined`.
The OR `||` operator can be used in the same way as `??`, as it was described in the [previous chapter](info:logical-operators#or-finds-the-first-truthy-value).
For example, in the code above we could replace `??` with `||` and still get the same result:
Historically, the OR `||` operator was there first. It exists since the beginning of JavaScript, so developers were using it for such purposes for a long time.
On the other hand, the nullish coalescing operator `??` was added to JavaScript only recently, and the reason for that was that people weren't quite happy with `||`.
The important difference between them is that:
- `||` returns the first *truthy* value.
- `??` returns the first *defined* value.
In other words, `||` doesn't distinguish between `false`, `0`, an empty string `""` and `null/undefined`. They are all the same -- falsy values. If any of these is the first argument of `||`, then we'll get the second argument as the result.
In practice though, we may want to use default value only when the variable is `null/undefined`. That is, when the value is really unknown/not set.
For example, consider this:
```js run
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
```
- The `height || 100` checks `height` for being a falsy value, and it's `0`, falsy indeed.
- so the result of `||` is the second argument, `100`.
- The `height ?? 100` checks `height` for being `null/undefined`, and it's not,
- so the result is `height` "as is", that is `0`.
In practice, the zero height is often a valid value, that shouldn't be replaced with the default. So `??` does just the right thing.
## Precedence
The precedence of the `??` operator is the same as `||`. They both equal `3` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table).
That means that, just like `||`, the nullish coalescing operator `??` is evaluated before `=` and `?`, but after most other operations, such as `+`, `*`.
So we may need to add parentheses in expressions like this:
```js run
let height = null;
let width = null;
// important: use parentheses
let area = (height ?? 100) * (width ?? 50);
alert(area); // 5000
```
Otherwise, if we omit parentheses, then as `*` has the higher precedence than `??`, it would execute first, leading to incorrect results.
```js
// without parentheses
let area = height ?? 100 * width ?? 50;
// ...works this way (not what we want):
let area = height ?? (100 * width) ?? 50;
```
### Using ?? with && or ||
Due to safety reasons, JavaScript forbids using `??` together with `&&` and `||` operators, unless the precedence is explicitly specified with parentheses.
The code below triggers a syntax error:
```js run
let x = 1 && 2 ?? 3; // Syntax error
```
The limitation is surely debatable, it was added to the language specification with the purpose to avoid programming mistakes, when people start to switch from `||` to `??`.
Use explicit parentheses to work around it:
```js run
*!*
let x = (1 && 2) ?? 3; // Works
*/!*
alert(x); // 2
```
## Summary
- The nullish coalescing operator `??` provides a short way to choose the first "defined" value from a list.
It's used to assign default values to variables:
```js
// set height=100, if height is null or undefined
height = height ?? 100;
```
- The operator `??` has a very low precedence, only a bit higher than `?` and `=`, so consider adding parentheses when using it in an expression.
- It's forbidden to use it with `||` or `&&` without explicit parentheses.
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 `&& num` is false when `num` is `null` or a empty string. Then the `while` loop stops too.
2. The check `&& num` is false when `num` is `null` or an empty string. Then the `while` loop stops too.
P.S. If `num` is `null` then `num <= 100` is `true`, so without the 2nd check the loop wouldn't stop if the user clicks CANCEL. Both checks are required.
A loop that shows odd values could look like this:
```js
```js run
for (let i = 0; i <10;i++){
if (i % 2) {
@ -268,7 +279,7 @@ for (let i = 0; i < 10; i++) {
From a technical point of view, this is identical to the example above. Surely, we can just wrap the code in an `if` block instead of using `continue`.
But as a side-effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of`if` is longer than a few lines, that may decrease the overall readability.
But as a sideeffect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of`if` is longer than a few lines, that may decrease the overall readability.
````
````warn header="No `break/continue` to the right side of '?'"
@ -286,7 +297,6 @@ if (i > 5) {
...and rewrite it using a question mark:
```js no-beautify
(i > 5) ? alert(i) : *!*continue*/!*; // continue isn't allowed here
```
@ -318,9 +328,10 @@ alert('Done!');
We need a way to stop the process if the user cancels the input.
The ordinary `break` after `input` would only break the inner loop. That's not sufficient--labels, come to the rescue!
The ordinary `break` after `input` would only break the inner loop. That's not sufficient--labels, come to the rescue!
A *label* is an identifier with a colon before a loop:
```js
labelName: for (...) {
...
@ -342,6 +353,7 @@ The `break <labelName>` statement in the loop below breaks out to the label:
// do something with the value...
}
}
alert('Done!');
```
@ -362,13 +374,26 @@ The `continue` directive can also be used with a label. In this case, code execu
Labels do not allow us to jump into an arbitrary place in the code.
For example, it is impossible to do this:
```js
break label; // doesn't jumps to the label below
break label; // jump to the label below (doesn't work)
label: for (...)
```
A call to `break/continue` is only possible from inside a loop and the label must be somewhere above the directive.
A `break` directive must be inside a code block. Technically, any labelled code block will do, e.g.:
```js
label: {
// ...
break label; // works
// ...
}
```
...Although, 99.9% of the time `break` is used inside loops, as we've seen in the examples above.
@ -117,7 +117,7 @@ Several variants of `case` which share the same code can be grouped.
For example, if we want the same code to run for `case 3` and `case 5`:
```js run no-beautify
let a = 2 + 2;
let a = 3;
switch (a) {
case 4:
@ -139,7 +139,7 @@ switch (a) {
Now both `3` and `5` show the same message.
The ability to "group" cases is a side-effect of how `switch/case` works without `break`. Here the execution of `case 3` starts from the line `(*)` and goes through `case 5`, because there's no `break`.
The ability to "group" cases is a sideeffect 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 `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above) and finally the code of the function, also named "the function body", between curly braces.
The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above, we'll see examples later) and finally the code of the function, also named "the function body", between curly braces.
```js
function name(parameters) {
...body...
function name(parameter1, parameter2, ... parameterN) {
// body
}
```
@ -137,26 +137,23 @@ It's a good practice to minimize the use of global variables. Modern code has fe
## Parameters
We can pass arbitrary data to functions using parameters (also called *function arguments*) .
We can pass arbitrary data to functions using parameters.
In the example below, the function has two parameters: `from` and `text`.
```js run
function showMessage(*!*from, text*/!*) { // arguments: from, text
function showMessage(*!*from, text*/!*) { // parameters: from, text
When the function is called in lines `(*)` and `(**)`, the given values are copied to local variables `from` and `text`. Then the function uses them.
Here's one more example: we have a variable `from` and pass it to the function. Please note: the function changes `from`, but the change is not seen outside, because a function always gets a copy of the value:
When a value is passed as a function parameter, it's also called an *argument*.
In other words, to put these terms straight:
- A parameter is the variable listed inside the parentheses in the function declaration (it's a declaration time term).
- An argument is the value that is passed to the function when it is called (it's a call time term).
We declare functions listing their parameters, then call them passing arguments.
In the example above, one might say: "the function `showMessage` is declared with two parameters, then called with two arguments: `from` and `"Hello"`".
## Default values
If a parameter is not provided, then its value becomes `undefined`.
If a function is called, but an argument is not provided, then the corresponding value becomes `undefined`.
For instance, the aforementioned function `showMessage(from, text)` can be called with a single argument:
@ -185,9 +194,9 @@ For instance, the aforementioned function `showMessage(from, text)` can be calle
showMessage("Ann");
```
That's not an error. Such a call would output `"Ann: undefined"`. There's no `text`, so it's assumed that `text === undefined`.
That's not an error. Such a call would output `"*Ann*: undefined"`. As the value for `text` isn't passed, it becomes `undefined`.
If we want to use a "default" `text` in this case, then we can specify it after`=`:
We can specify the so-called "default" (to use if omitted) value for a parameter in the function declaration, using`=`:
```js run
function showMessage(from, *!*text = "no text given"*/!*) {
@ -197,7 +206,13 @@ function showMessage(from, *!*text = "no text given"*/!*) {
showMessage("Ann"); // Ann: no text given
```
Now if the `text` parameter is not passed, it will get the value `"no text given"`
Now if the `text` parameter is not passed, it will get the value `"no text given"`.
The default value also jumps in if the parameter exists, but strictly equals `undefined`, like this:
```js
showMessage("Ann", undefined); // Ann: no text given
```
Here `"no text given"` is a string, but it can be a more complex expression, which is only evaluated and assigned if the parameter is missing. So, this is also possible:
@ -211,13 +226,17 @@ function showMessage(from, text = anotherFunction()) {
```smart header="Evaluation of default parameters"
In JavaScript, a default parameter is evaluated every time the function is called without the respective parameter.
In the example above, `anotherFunction()` is called every time `showMessage()` is called without the `text` parameter.
In the example above, `anotherFunction()` isn't called at all, if the `text` parameter is provided.
On the other hand, it's independently called every time when `text` is missing.
```
````smart header="Default parameters old-style"
Old editions of JavaScript did not support default parameters. So there are alternative ways to support them, that you can find mostly in the old scripts.
````smart header="Default parameters in old JavaScript code"
Several years ago, JavaScript didn't support the syntax for default parameters. So people used other ways to specify them.
For instance, an explicit check for being `undefined`:
Nowadays, we can come across them in old scripts.
For example, an explicit check for `undefined`:
```js
function showMessage(from, text) {
@ -231,20 +250,64 @@ function showMessage(from, text) {
}
```
...Or the `||` operator:
...Or using the `||` operator:
```js
function showMessage(from, text) {
// if text is falsy then text gets the "default" value
// If the value of text is falsy, assign the default value
// this assumes that text == "" is the same as no text at all
text = text || 'no text given';
...
}
```
````
### Alternative default parameters
Sometimes it makes sense to assign default values for parameters at a later stage after the function declaration.
We can check if the parameter is passed during the function execution, by comparing it with `undefined`:
```js run
function showMessage(text) {
// ...
*!*
if (text === undefined) { // if the parameter is missing
text = 'empty message';
}
*/!*
alert(text);
}
showMessage(); // empty message
```
...Or we could use the `||` operator:
```js
function showMessage(text) {
// if text is undefined or otherwise falsy, set it to 'empty'
text = text || 'empty';
...
}
```
Modern JavaScript engines support the [nullish coalescing operator](info:nullish-coalescing-operator) `??`, it's better when most falsy values, such as `0`, should be considered "normal":
```js run
function showCount(count) {
// if count is undefined or null, show "unknown"
alert(count ?? "unknown");
}
showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown
```
## Returning a value
A function can return a value back into the calling code as the result.
@ -266,7 +329,7 @@ There may be many occurrences of `return` in a single function. For instance:
```js run
function checkAge(age) {
if (age > 18) {
if (age >= 18) {
*!*
return true;
*/!*
@ -399,7 +462,7 @@ Functions that are used *very often* sometimes have ultrashort names.
For example, the [jQuery](http://jquery.com) framework defines a function with `$`. The [Lodash](http://lodash.com/) library has its core function named `_`.
These are exceptions. Generally functions names should be concise and descriptive.
These are exceptions. Generally function names should be concise and descriptive.
```
## Functions == Comments
@ -465,7 +528,7 @@ function name(parameters, delimited, by, comma) {
To make the code clean and easy to understand, it's recommended to use mainly local variables and parameters in the function, not outer variables.
It is always easier to understand a function which gets parameters, works with them and returns a result than a function which gets no parameters, but modifies outer variables as a side-effect.
It is always easier to understand a function which gets parameters, works with them and returns a result than a function which gets no parameters, but modifies outer variables as a sideeffect.
There is another syntax for creating a function that is called a *Function Expression*.
It looks like this:
It allows us to create a new function in the middle of any expression.
For example:
```js
let sayHi = function() {
@ -20,9 +22,19 @@ let sayHi = function() {
};
```
Here, the function is created and assigned to the variable explicitly, like any other value. No matter how the function is defined, it's just a value stored in the variable `sayHi`.
Here we can see a variable `sayHi` getting a value, the new function, created as `function() { alert("Hello"); }`.
The meaning of these code samples is the same: "create a function and put it into the variable `sayHi`".
As the function creation happens in the context of the assignment expression (to the right side of `=`), this is a *Function Expression*.
Please note, there's no name after the `function` keyword. Omitting a name is allowed for Function Expressions.
Here we immediately assign it to the variable, so the meaning of these code samples is the same: "create a function and put it into the variable `sayHi`".
In more advanced situations, that we'll come across later, a function may be created and immediately called or scheduled for a later execution, not stored anywhere, thus remaining anonymous.
## Function is a value
Let's reiterate: no matter how the function is created, a function is a value. Both examples above store a function in the `sayHi` variable.
We can even print out that value using `alert`:
@ -63,10 +75,10 @@ Here's what happens above in detail:
2. Line `(2)` copies it into the variable `func`. Please note again: there are no parentheses after `sayHi`. If there were, then `func = sayHi()` would write *the result of the call*`sayHi()` into `func`, not *the function*`sayHi` itself.
3. Now the function can be called as both `sayHi()` and `func()`.
Note that we could also have used a Function Expression to declare `sayHi`, in the first line:
We could also have used a Function Expression to declare `sayHi`, in the first line:
```js
let sayHi = function() {
let sayHi = function() { // (1) create
alert( "Hello" );
};
@ -78,7 +90,7 @@ Everything would work the same.
````smart header="Why is there a semicolon at the end?"
You might wonder, why does Function Expression have a semicolon `;` at the end, but Function Declaration does not:
You might wonder, why do Function Expressions have a semicolon `;` at the end, but Function Declarations do not:
```js
function sayHi() {
@ -90,9 +102,9 @@ let sayHi = function() {
}*!*;*/!*
```
The answer is simple:
- There's no need for `;` at the end of code blocks and syntax structures that use them like `if { ... }`, `for { }`, `function f { }` etc.
- A Function Expression is used inside the statement: `let sayHi = ...;`, as a value. It's not a code block, but rather an assignment. The semicolon `;` is recommended at the end of statements, no matter what the value is. So the semicolon here is not related to the Function Expression itself, it just terminates the statement.
The answer is simple: a Function Expression is created here as `function(…) {…}` inside the assignment statement: `let sayHi = …;`. The semicolon `;` is recommended at the end of the statement, it's not a part of the function syntax.
The semicolon would be there for a simpler assignment, such as `let sayHi = 5;`, and it's also there for a function assignment.
````
## Callback functions
@ -132,13 +144,13 @@ function showCancel() {
ask("Do you agree?", showOk, showCancel);
```
In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such function usually draws a nice-looking question window. But that's another story.
In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such functions usually draw a nice-looking question window. But that's another story.
**The arguments `showOk` and `showCancel` of `ask` are called *callback functions* or just *callbacks*.**
The idea is that we pass a function and expect it to be "called back" later if necessary. In our case, `showOk` becomes the callback for "yes" answer, and `showCancel` for "no" answer.
We can use Function Expressions to write the same function much shorter:
We can use Function Expressions to write an equivalent, shorter function:
```js run no-beautify
function ask(question, yes, no) {
@ -174,7 +186,7 @@ Let's formulate the key differences between Function Declarations and Expression
First, the syntax: how to differentiate between them in the code.
- *Function Declaration:* a function, declared as a separate statement, in the main code flow.
- *Function Declaration:* a function, declared as a separate statement, in the main code flow:
```js
// Function Declaration
@ -182,7 +194,7 @@ First, the syntax: how to differentiate between them in the code.
return a + b;
}
```
- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created at the right side of the "assignment expression" `=`:
- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created on the right side of the "assignment expression" `=`:
```js
// Function Expression
@ -348,7 +360,7 @@ welcome(); // ok now
```smart header="When to choose Function Declaration versus Function Expression?"
As a rule of thumb, when we need to declare a function, the first to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
As a rule of thumb, when we need to declare a function, the first thing to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
That's also better for readability, as it's easier to look up `function f(…) {…}` in the code than `let f = function(…) {…};`. Function Declarations are more "eye-catching".
@ -5,15 +5,15 @@ There's another very simple and concise syntax for creating functions, that's of
It's called "arrow functions", because it looks like this:
```js
let func = (arg1, arg2, ...argN) => expression
let func = (arg1, arg2, ..., argN) => expression;
```
...This creates a function `func` that accepts arguments `arg1..argN`, then evaluates the `expression` on the right side with their use and returns its result.
This creates a function `func` that accepts arguments `arg1..argN`, then evaluates the `expression` on the right side with their use and returns its result.
In other words, it's the shorter version of:
```js
let func = function(arg1, arg2, ...argN) {
let func = function(arg1, arg2, ..., argN) {
return expression;
};
```
@ -33,7 +33,7 @@ let sum = function(a, b) {
alert( sum(1, 2) ); // 3
```
As you can, see `(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result.
As you can see,`(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result.
- If we have only one argument, then parentheses around parameters can be omitted, making that even shorter.
@ -48,7 +48,7 @@ As you can, see `(a, b) => a + b` means a function that accepts two arguments na
alert( double(3) ); // 6
```
- If there are no arguments, parentheses will be empty (but they should be present):
- If there are no arguments, parentheses are empty, but they must be present:
```js run
let sayHi = () => alert("Hello!");
@ -64,10 +64,10 @@ For instance, to dynamically create a function:
let age = prompt("What is your age?", 18);
let welcome = (age <18)?
() => alert('Hello') :
() => alert('Hello!') :
() => alert("Greetings!");
welcome(); // ok now
welcome();
```
Arrow functions may appear unfamiliar and not very readable at first, but that quickly changes as the eyes get used to the structure.
@ -76,9 +76,9 @@ They are very convenient for simple one-line actions, when we're just too lazy t
## Multiline arrow functions
The examples above took arguments from the left of `=>` and evaluated the right-side expression with them.
The arrow functions that we've seen so far were very simple. They took arguments from the left of `=>`, evaluated and returned the right-side expression with them.
Sometimes we need something a little bit more complex, like multiple expressions or statements. It is also possible, but we should enclose them in curly braces. Then use a normal `return` within them.
Sometimes we need a more complex function, with multiple expressions and statements. In that case, we can enclose them in curly braces. The major difference is that curly braces require a `return` within them to return a value (just like a regular function does).
Like this:
@ -105,7 +105,7 @@ For now, we can already use arrow functions for one-line actions and callbacks.
## Summary
Arrow functions are handy for one-liners. They come in two flavors:
Arrow functions are handy for simple actions, especially for one-liners. They come in two flavors:
1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result.
1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result. Parentheses can be omitted, if there's only a single argument, e.g. `n => n*2`.
2. With curly braces: `(...args) => { body }` -- brackets allow us to write multiple statements inside the function, but we need an explicit `return` to return something.
@ -55,7 +55,7 @@ To fully enable all features of modern JavaScript, we should start scripts with
The directive must be at the top of a script or at the beginning of a function body.
Without `"use strict"`, everything still works, but some features behave in the old-fashion, "compatible" way. We'd generally prefer the modern behavior.
Without `"use strict"`, everything still works, but some features behave in the old-fashioned, "compatible" way. We'd generally prefer the modern behavior.
Some modern features of the language (like classes that we'll study in the future) enable strict mode implicitly.
@ -81,9 +81,10 @@ let x = 5;
x = "John";
```
There are 7 data types:
There are 8 data types:
- `number` for both floating-point and integer numbers,
- `bigint` for integer numbers of arbitrary length,
- `string` for strings,
- `boolean` for logical values: `true/false`,
- `null` -- a type with a single value `null`, meaning "empty" or "does not exist",
@ -143,7 +144,7 @@ Assignments
: There is a simple assignment: `a = b` and combined ones like `a *= 2`.
Bitwise
: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](mdn:/JavaScript/Reference/Operators/Bitwise_Operators) when they are needed.
: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](mdn:/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) when they are needed.
Conditional
: The only operator with three parameters: `cond ? resultA : resultB`. If `cond` is truthy, returns `resultA`, otherwise `resultB`.
@ -151,6 +152,9 @@ Conditional
Logical operators
: Logical AND `&&` and OR `||` perform short-circuit evaluation and then return the value where it stopped (not necessary `true`/`false`). Logical NOT `!` converts the operand to boolean type and returns the inverse value.
Nullish coalescing operator
: The `??` operator provides a way to choose a defined value from a list of variables. The result of `a ?? b` is `a` unless it's `null/undefined`, then `b`.
Comparisons
: Equality check `==` for values of different types converts them to a number (except `null` and `undefined` that equal each other and nothing else), so these are equal:
@ -170,7 +174,7 @@ Comparisons
Other operators
: There are few others, like a comma operator.
More in: <info:operators>, <info:comparison>, <info:logical-operators>.
More in: <info:operators>, <info:comparison>, <info:logical-operators>, <info:nullish-coalescing-operator>.
## Loops
@ -212,6 +216,7 @@ let age = prompt('Your age?', 18);
switch (age) {
case 18:
alert("Won't work"); // the result of prompt is a string, not a number
break;
case "18":
alert("This works!");
@ -251,7 +256,7 @@ We covered three ways to create a function in JavaScript:
3. Arrow functions:
```js
// expression at the right side
// expression on the right side
let sum = (a, b) => a + b;
// or multi-line syntax with { ... }, need return here:
@ -268,7 +273,7 @@ We covered three ways to create a function in JavaScript:
```
- Functions may have local variables: those declared inside its body. Such variables are only visible inside the function.
- Functions may have local variables: those declared inside its body or its parameter list. Such variables are only visible inside the function.
- Parameters can have default values: `function sum(a = 1, b = 2) {...}`.
- Functions always return something. If there's no `return` statement, then the result is `undefined`.
Before writing more complex code, let's talk about debugging.
[Debugging](https://en.wikipedia.org/wiki/Debugging) is the process of finding and fixing errors within a script. All modern browsers and most other environments support debugging tools -- a special UI in developer tools that makes debugging much easier. It also allows to trace the code step by step to see what exactly is going on.
We'll be using Chrome here, because it has enough features, most other browsers have a similar process`.
We'll be using Chrome here, because it has enough features, most other browsers have a similar process.
## The "Sources" panel
@ -24,11 +24,11 @@ Let's click it and select `hello.js` in the tree view. Here's what should show u

Here we can see three zones:
The Sources panel has 3 parts:
1. The **Resources zone** lists HTML, JavaScript, CSS and other files, including images that are attached to the page. Chrome extensions may appear here too.
2. The **Source zone** shows the source code.
3. The **Information and control zone** is for debugging, we'll explore it soon.
1. The **File Navigator** pane lists HTML, JavaScript, CSS and other files, including images that are attached to the page. Chrome extensions may appear here too.
2. The **Code Editor** pane shows the source code.
3. The **JavaScript Debugging** pane is for debugging, we'll explore it soon.
Now you could click the same toggler <spanclass="devtools"style="background-position:-172px -122px"></span> again to hide the resources list and give the code some space.
@ -38,7 +38,7 @@ If we press `key:Esc`, then a console opens below. We can type commands there an
After a statement is executed, its result is shown below.
For example, here `1+2` results in `3`, and`hello("debugger")` returns nothing, so the result is `undefined`:
For example, here `1+2` results in `3`, while the function call`hello("debugger")` returns nothing, so the result is `undefined`:

@ -63,12 +63,12 @@ We can always find a list of breakpoints in the right panel. That's useful when
- ...And so on.
```smart header="Conditional breakpoints"
*Right click* on the line number allows to create a *conditional* breakpoint. It only triggers when the given expression is truthy.
*Right click* on the line number allows to create a *conditional* breakpoint. It only triggers when the given expression, that you should provide when you create it, is truthy.
That's handy when we need to stop only for a certain variable value or for certain function parameters.
```
## Debugger command
## The command "debugger"
We can also pause the code by using the `debugger` command in it, like this:
@ -84,8 +84,7 @@ function hello(name) {
}
```
That's very convenient when we are in a code editor and don't want to switch to the browser and look up the script in developer tools to set the breakpoint.
Such command works only when the development tools are open, otherwise the browser ignores it.
## Pause and look around
@ -99,7 +98,7 @@ Please open the informational dropdowns to the right (labeled with arrows). They
1. **`Watch` -- shows current values for any expressions.**
You can click the plus `+` and input an expression. The debugger will show its value at any moment, automatically recalculating it in the process of execution.
You can click the plus `+` and input an expression. The debugger will show its value, automatically recalculating it in the process of execution.
2. **`Call Stack` -- shows the nested calls chain.**
@ -135,11 +134,11 @@ There are buttons for it at the top of the right panel. Let's engage them.
Clicking this again and again will step through all script statements one by one.
<spanclass="devtools"style="background-position:-62px -192px"></span> -- "Step over": run the next command, but *don't go into a function*, hotkey `key:F10`.
: Similar to the previous the "Step" command, but behaves differently if the next statement is a function call. That is: not a built-in, like `alert`, but a function of our own.
: Similar to the previous "Step" command, but behaves differently if the next statement is a function call (not a built-in, like `alert`, but a function of our own).
The "Step" command goes into it and pauses the execution at its first line, while "Step over" executes the nested function call invisibly, skipping the function internals.
If we compare them, the "Step" command goes into a nested function call and pauses the execution at its first line, while "Step over" executes the nested function call invisibly to us, skipping the function internals.
The execution is then paused immediately after that function.
The execution is then paused immediately after that function call.
That's good if we're not interested to see what happens inside the function call.
@ -155,7 +154,7 @@ There are buttons for it at the top of the right panel. Let's engage them.
: That button does not move the execution. Just a mass on/off for breakpoints.
<spanclass="devtools"style="background-position:-90px -146px"></span> -- enable/disable automatic pause in case of an error.
: When enabled, and the developer tools is open, a script error automatically pauses the execution. Then we can analyze variables to see what went wrong. So if our script dies with an error, we can open debugger, enable this option and reload the page to see where it dies and what's the context at that moment.
: When enabled, if the developer tools is open, an error during the script execution automatically pauses it. Then we can analyze variables in the debugger to see what went wrong. So if our script dies with an error, we can open debugger, enable this option and reload the page to see where it dies and what's the context at that moment.
```smart header="Continue to here"
Right click on a line of code opens the context menu with a great option called "Continue to here".
@ -187,7 +186,7 @@ As we can see, there are three main ways to pause a script:
2. The `debugger` statements.
3. An error (if dev tools are open and the button <spanclass="devtools"style="background-position:-90px -146px"></span> is "on").
When paused, we can debug - examine variables and trace the code to see where the execution goes wrong.
When paused, we can debug: examine variables and trace the code to see where the execution goes wrong.
There are many more options in developer tools than covered here. The full manual is at <https://developers.google.com/web/tools/chrome-devtools>.
@ -301,11 +301,11 @@ The great thing about them is that style-checking can also find some bugs, like
Here are some well-known linting tools:
- [JSLint](http://www.jslint.com/) -- one of the first linters.
- [JSHint](http://www.jshint.com/) -- more settings than JSLint.
- [ESLint](http://eslint.org/) -- probably the newest one.
- [JSLint](https://www.jslint.com/) -- one of the first linters.
- [JSHint](https://jshint.com/) -- more settings than JSLint.
- [ESLint](https://eslint.org/) -- probably the newest one.
All of them can do the job. The author uses [ESLint](http://eslint.org/).
All of them can do the job. The author uses [ESLint](https://eslint.org/).
Most linters are integrated with many popular editors: just enable the plugin in the editor and configure the style.
@ -328,14 +328,14 @@ Here's an example of an `.eslintrc` file:
},
"rules": {
"no-console": 0,
"indent": ["warning", 2]
"indent": 2
}
}
```
Here the directive `"extends"` denotes that the configuration is based on the "eslint:recommended" set of settings. After that, we specify our own.
It is also possible to download style rule sets from the web and extend them instead. See <http://eslint.org/docs/user-guide/getting-started> for more details about installation.
It is also possible to download style rule sets from the web and extend them instead. See <https://eslint.org/docs/user-guide/getting-started> for more details about installation.
Also certain IDEs have built-in linting, which is convenient but not as customizable as ESLint.
: There's a special syntax [JSDoc](http://en.wikipedia.org/wiki/JSDoc) to document a function: usage, parameters, returned value.
For instance:
```js
/**
For instance:
```js
/**
* Returns x raised to the n-th power.
*
* @param {number} x The number to raise.
* @param {number} n The power, must be a natural number.
* @return {number} x raised to the n-th power.
*/
function pow(x, n) {
function pow(x, n) {
...
}
```
}
```
Such comments allow us to understand the purpose of the function and use it the right way without looking in its code.
Such comments allow us to understand the purpose of the function and use it the right way without looking in its code.
By the way, many editors like [WebStorm](https://www.jetbrains.com/webstorm/) can understand them as well and use them to provide autocomplete and some automatic code-checking.
By the way, many editors like [WebStorm](https://www.jetbrains.com/webstorm/) can understand them as well and use them to provide autocomplete and some automatic code-checking.
Also, there are tools like [JSDoc 3](https://github.com/jsdoc3/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at <http://usejsdoc.org/>.
Also, there are tools like [JSDoc 3](https://github.com/jsdoc/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at <https://jsdoc.app>.
Why is the task solved this way?
: What's written is important. But what's *not* written may be even more important to understand what's going on. Why is the task solved exactly this way? The code gives no answer.
Learning without thought is labor lost; thought without learning is perilous.
```
@ -43,7 +43,7 @@ The Dao hides in wordlessness. Only the Dao is well begun and well
completed.
```
Another way to code faster is to use single-letter variable names everywhere. Like `a`, `b` or `c`.
Another way to code shorter is to use single-letter variable names everywhere. Like `a`, `b` or `c`.
A short variable disappears in the code like a real ninja in the forest. No one will be able to find it using "search" of the editor. And even if someone does, they won't be able to "decipher" what the name `a` or `b` means.
@ -104,8 +104,8 @@ A quick read of such code becomes impossible. And when there's a typo... Ummm...
## Smart synonyms
```quote author="Confucius"
The hardest thing of all is to find a black cat in a dark room, especially if there is no cat.
```quote author="Laozi (Tao Te Ching)"
The Tao that can be told is not the eternal Tao. The name that can be named is not the eternal name.
```
Using *similar* names for *same* things makes life more interesting and shows your creativity to the public.
Automated testing will be used in further tasks, and it's also widely used in real projects.
## Why we need tests?
## Why do we need tests?
When we write a function, we can usually imagine what it should do: which parameters give which results.
@ -51,7 +51,7 @@ describe("pow", function() {
A spec has three main building blocks that you can see above:
`describe("title", function() { ... })`
: What functionality we're describing. In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks.
: What functionality we're describing? In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks.
`it("use case description", function() { ... })`
: In the title of `it` we *in a human-readable way* describe the particular use case, and the second argument is a function that tests it.
@ -79,7 +79,7 @@ So, the development is *iterative*. We write the spec, implement it, make sure t
Let's see this development flow in our practical case.
The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use few JavaScript libraries to run the tests, just to see that they are working (they will all fail).
The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use a few JavaScript libraries to run the tests, just to see that they are working (they will all fail).
## The spec in action
@ -159,8 +159,8 @@ We can select one of two ways to organize the test here:
assert.equal(pow(2, 3), 8);
});
it("3 raised to power 3 is 27", function() {
assert.equal(pow(3, 3), 27);
it("3 raised to power 4 is 81", function() {
assert.equal(pow(3, 4), 81);
});
});
@ -182,7 +182,7 @@ The result:
[iframe height=250 src="pow-2" edit border="1"]
As we could expect, the second test failed. Sure, our function always returns `8`, while the `assert` expects `27`.
As we could expect, the second test failed. Sure, our function always returns `8`, while the `assert` expects `81`.
The JavaScript language steadily evolves. New proposals to the language appear regularly, they are analyzed and, if considered worthy, are appended to the list at <https://tc39.github.io/ecma262/> and then progress to the [specification](http://www.ecma-international.org/publications/standards/Ecma-262.htm).
Teams behind JavaScript engines have their own ideas about what to implement first. They may decide to implement proposals that are in draft and postpone things that are already in the spec, because they are less interesting or just harder to do.
So it's quite common for an engine to implement only the part of the standard.
So it's quite common for an engine to implement only part of the standard.
A good page to see the current state of support for language features is <https://kangax.github.io/compat-table/es6/> (it's big, we have a lot to study yet).
## Babel
As programmers, we'd like to use most recent features. The more good stuff - the better!
When we use modern features of the language, some engines may fail to support such code. Just as said, not all features are implemented everywhere.
On the other hand, how to make our modern code work on older engines that don't understand recent features yet?
Here Babel comes to the rescue.
There are two tools for that:
[Babel](https://babeljs.io) is a [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler). It rewrites modern JavaScript code into the previous standard.
1. Transpilers.
2. Polyfills.
Actually, there are two parts in Babel:
Here, in this chapter, our purpose is to get the gist of how they work, and their place in web development.
1. First, the transpiler program, which rewrites the code. The developer runs it on their own computer. It rewrites the code into the older standard. And then the code is delivered to the website for users. Modern project build systems like [webpack](http://webpack.github.io/) provide means to run transpiler automatically on every code change, so that very easy to integrate into development process.
## Transpilers
2. Second, the polyfill.
A [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler) is a special piece of software that translates source code to another source code. It can parse ("read and understand") modern code and rewrite it using older syntax constructs, so that it'll also work in outdated engines.
New language features may include new built-in functions and syntax constructs.
The transpiler rewrites the code, transforming syntax constructs into older ones. But as for new built-in functions, we need to implement them. JavaScript is a highly dynamic language, scripts may add/modify any functions, so that they behave according to the modern standard.
E.g. JavaScript before year 2020 didn't have the "nullish coalescing operator" `??`. So, if a visitor uses an outdated browser, it may fail to understand the code like `height = height ?? 100`.
A script that updates/adds new functions is called "polyfill". It "fills in" the gap and adds missing implementations.
A transpiler would analyze our code and rewrite `height ?? 100` into `(height !== undefined && height !== null) ? height : 100`.
Two interesting polyfills are:
- [core js](https://github.com/zloirock/core-js) that supports a lot, allows to include only needed features.
- [polyfill.io](http://polyfill.io) service that provides a script with polyfills, depending on the features and user's browser.
```js
// before running the transpiler
height = height ?? 100;
So, if we're going to use modern language features, a transpiler and a polyfill are necessary.
## Examples in the tutorial
````online
Most examples are runnable at-place, like this:
```js run
alert('Press the "Play" button in the upper-right corner to run');
Examples that use modern JS will work only if your browser supports it.
````
Now the rewritten code is suitable for older JavaScript engines.
```offline
As you're reading the offline version, in PDF examples are not runnable. In EPUB some of them can run.
Usually, a developer runs the transpiler on their own computer, and then deploys the transpiled code to the server.
Speaking of names, [Babel](https://babeljs.io) is one of the most prominent transpilers out there.
Modern project build systems, such as [webpack](https://webpack.js.org/), provide a means to run a transpiler automatically on every code change, so it's very easy to integrate into the development process.
## Polyfills
New language features may include not only syntax constructs and operators, but also built-in functions.
For example, `Math.trunc(n)` is a function that "cuts off" the decimal part of a number, e.g `Math.trunc(1.23)` returns `1`.
In some (very outdated) JavaScript engines, there's no `Math.trunc`, so such code will fail.
As we're talking about new functions, not syntax changes, there's no need to transpile anything here. We just need to declare the missing function.
A script that updates/adds new functions is called "polyfill". It "fills in" the gap and adds missing implementations.
For this particular case, the polyfill for `Math.trunc` is a script that implements it, like this:
```js
if (!Math.trunc) { // if no such function
// implement it
Math.trunc = function(number) {
// Math.ceil and Math.floor exist even in ancient JavaScript engines
// they are covered later in the tutorial
return number <0?Math.ceil(number):Math.floor(number);
};
}
```
Google Chrome is usually the most up-to-date with language features, good to run bleeding-edge demos without any transpilers, but other modern browsers also work fine.
JavaScript is a highly dynamic language. Scripts may add/modify any function, even built-in ones.
Two interesting polyfill libraries are:
- [core js](https://github.com/zloirock/core-js) that supports a lot, allows to include only needed features.
- [polyfill.io](http://polyfill.io) service that provides a script with polyfills, depending on the features and user's browser.
## Summary
In this chapter we'd like to motivate you to study modern and even "bleeding-edge" language features, even if they aren't yet well-supported by JavaScript engines.
Just don't forget to use a transpiler (if using modern syntax or operators) and polyfills (to add functions that may be missing). They'll ensure that the code works.
For example, later when you're familiar with JavaScript, you can setup a code build system based on [webpack](https://webpack.js.org/) with the [babel-loader](https://github.com/babel/babel-loader) plugin.
Good resources that show the current state of support for various features:
- <https://kangax.github.io/compat-table/es6/> - for pure JavaScript.
- <https://caniuse.com/> - for browser-related functions.
P.S. Google Chrome is usually the most up-to-date with language features, try it if a tutorial demo fails. Most tutorial demos work with any modern browser though.
As we know from the chapter <info:types>, there are seven data types in JavaScript. Six of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever).
As we know from the chapter <info:types>, there are eight data types in JavaScript. Seven of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever).
In contrast, objects are used to store keyed collections of various data and more complex entities. In JavaScript, objects penetrate almost every aspect of the language. So we must understand them first before going in-depth anywhere else.
@ -44,7 +44,7 @@ The resulting `user` object can be imagined as a cabinet with two signed files l

We can add, remove and read files from it any time.
We can add, remove and read files from it at any time.
Property values are accessible using the dot notation:
@ -62,7 +62,7 @@ user.isAdmin = true;

To remove a property, we can use `delete` operator:
To remove a property, we can use the `delete` operator:
```js
delete user.age;
@ -101,7 +101,9 @@ For multiword properties, the dot access doesn't work:
user.likes birds = true
```
That's because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations.
JavaScript doesn't understand that. It thinks that we address `user.likes`, and then gives a syntax error when comes across unexpected `birds`.
The dot requires the key to be a valid variable identifier. That implies: contains no spaces, doesn't start with a digit and doesn't include special characters (`$` and `_` are allowed).
There's an alternative "square bracket notation" that works with any string:
@ -159,7 +161,7 @@ alert( user.key ) // undefined
### Computed properties
We can use square brackets in an object literal. That's called *computed properties*.
We can use square brackets in an object literal, when creating an object. That's called *computed properties*.
For instance:
@ -199,50 +201,13 @@ let bag = {
};
```
Square brackets are much more powerful than the dot notation. They allow any property names and variables. But they are also more cumbersome to write.
Square brackets are much more powerful than dot notation. They allow any property names and variables. But they are also more cumbersome to write.
So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets.
````smart header="Reserved words are allowed as property names"
A variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.
But for an object property, there's no such restriction. Any name is fine:
```js run
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
```
Basically, any name is allowed, but there's a special one: `"__proto__"` that gets special treatment for historical reasons. For instance, we can't set it to a non-object value:
```js run
let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // [object Object], didn't work as intended
```
As we see from the code, the assignment to a primitive `5` is ignored.
That can become a source of bugs and even vulnerabilities if we intend to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys.
In that case the visitor may choose `__proto__` as the key, and the assignment logic will be ruined (as shown above).
There is a way to make objects treat `__proto__` as a regular property, which we'll cover later, but first we need to know more about objects.
There's also another data structure [Map](info:map-set), that we'll learn in the chapter <info:map-set>, which supports arbitrary keys.
````
## Property value shorthand
In real code we often use existing variables as values for property names.
In real code, we often use existing variables as values for property names.
For instance:
@ -250,7 +215,7 @@ For instance:
function makeUser(name, age) {
return {
name: name,
age: age
age: age,
// ...other properties
};
}
@ -268,7 +233,7 @@ function makeUser(name, age) {
*!*
return {
name, // same as name: name
age // same as age: age
age, // same as age: age
// ...
};
*/!*
@ -284,9 +249,57 @@ let user = {
};
```
## Existence check
A notable objects feature is that it's possible to access any property. There will be no error if the property doesn't exist! Accessing a non-existing property just returns `undefined`. It provides a very common way to test whether the property exists -- to get it and compare vs undefined:
## Property names limitations
As we already know, a variable cannot have a name equal to one of the language-reserved words like "for", "let", "return" etc.
But for an object property, there's no such restriction:
```js run
// these properties are all right
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
```
In short, there are no limitations on property names. They can be any strings or symbols (a special type for identifiers, to be covered later).
Other types are automatically converted to strings.
For instance, a number `0` becomes a string `"0"` when used as a property key:
```js run
let obj = {
0: "test" // same as "0": "test"
};
// both alerts access the same property (the number 0 is converted to string "0")
alert( obj["0"] ); // test
alert( obj[0] ); // test (same property)
```
There's a minor gotcha with a special property named `__proto__`. We can't set it to a non-object value:
```js run
let obj = {};
obj.__proto__ = 5; // assign a number
alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended
```
As we see from the code, the assignment to a primitive `5` is ignored.
We'll cover the special nature of `__proto__` in [subsequent chapters](info:prototype-inheritance), and suggest the [ways to fix](info:prototype-methods) such behavior.
## Property existence test, "in" operator
A notable feature of objects in JavaScript, compared to many other languages, is that it's possible to access any property. There will be no error if the property doesn't exist!
Reading a non-existing property just returns `undefined`. So we can easily test whether the property exists:
```js run
let user = {};
@ -294,7 +307,7 @@ let user = {};
alert( user.noSuchProperty === undefined ); // true means "no such property"
```
There also exists a special operator `"in"` to check for the existence of a property.
There's also a special operator `"in"` for that.
The syntax is:
```js
@ -312,17 +325,18 @@ alert( "blabla" in user ); // false, user.blabla doesn't exist
Please note that on the left side of `in` there must be a *property name*. That's usually a quoted string.
If we omit quotes, that would mean a variable containing the actual name will be tested. For instance:
If we omit quotes, that means a variable should contain the actual name to be tested. For instance:
```js run
let user = { age: 30 };
let key = "age";
alert( *!*key*/!* in user ); // true, takes the name from key and checks for such property
alert( *!*key*/!* in user ); // true, property "age" exists
```
````smart header="Using \"in\" for properties that store `undefined`"
Usually, the strict comparison `"=== undefined"` check the property existance just fine. But there's a special case when it fails, but `"in"` works correctly.
Why does the `in` operator exist? Isn't it enough to compare against `undefined`?
Well, most of the time the comparison with `undefined` works fine. But there's a special case when it fails, but `"in"` works correctly.
It's when an object property exists, but stores `undefined`:
@ -336,13 +350,12 @@ alert( obj.test ); // it's undefined, so - no such property?
alert( "test" in obj ); // true, the property does exist!
```
In the code above, the property `obj.test` technically exists. So the `in` operator works right.
Situations like this happen very rarely, because `undefined` is usually not assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code.
````
Situations like this happen very rarely, because `undefined` should not be explicitly assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code.
## The "for..in" loop
## The "for..in" loop [#forin]
To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we studied before.
@ -375,7 +388,6 @@ Note that all "for" constructs allow us to declare the looping variable inside t
Also, we could use another variable name here instead of `key`. For instance, `"for (let prop in obj)"` is also widely used.
### Ordered like an object
Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order they were added? Can we rely on this?
@ -400,7 +412,7 @@ for (let code in codes) {
*/!*
```
The object may be used to suggest a list of options to the user. If we're making a site mainly for German audience then we probably want `49` to be the first.
The object may be used to suggest a list of options to the user. If we're making a site mainly for a German audience then we probably want `49` to be the first.
But if we run the code, we see a totally different picture:
@ -412,9 +424,10 @@ The phone codes go in the ascending sorted order, because they are integers. So
The "integer property" term here means a string that can be converted to-and-from an integer without a change.
So, "49" is an integer property name, because when it's transformed to an integer number and back, it's still the same. But "+49" and "1.2" are not:
So, `"49"` is an integer property name, because when it's transformed to an integer number and back, it's still the same. But `"+49"` and `"1.2"` are not:
```js run
// Number(...) explicitly converts to a number
// Math.trunc is a built-in function that removes the decimal part
alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property
@ -459,262 +472,6 @@ for (let code in codes) {
Now it works as intended.
## Copying by reference
One of the fundamental differences of objects vs primitives is that they are stored and copied "by reference".
Primitive values: strings, numbers, booleans -- are assigned/copied "as a whole value".
For instance:
```js
let message = "Hello!";
let phrase = message;
```
As a result we have two independent variables, each one is storing the string `"Hello!"`.

Objects are not like that.
**A variable stores not the object itself, but its "address in memory", in other words "a reference" to it.**
Here's the picture for the object:
```js
let user = {
name: "John"
};
```

Here, the object is stored somewhere in memory. And the variable `user` has a "reference" to it.
**When an object variable is copied -- the reference is copied, the object is not duplicated.**
If we imagine an object as a cabinet, then a variable is a key to it. Copying a variable duplicates the key, but not the cabinet itself.
For instance:
```js no-beautify
let user = { name: "John" };
let admin = user; // copy the reference
```
Now we have two variables, each one with the reference to the same object:

We can use any variable to access the cabinet and modify its contents:
```js run
let user = { name: 'John' };
let admin = user;
*!*
admin.name = 'Pete'; // changed by the "admin" reference
*/!*
alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference
```
The example above demonstrates that there is only one object. As if we had a cabinet with two keys and used one of them (`admin`) to get into it. Then, if we later use the other key (`user`) we would see changes.
### Comparison by reference
The equality `==` and strict equality `===` operators for objects work exactly the same.
**Two objects are equal only if they are the same object.**
For instance, if two variables reference the same object, they are equal:
```js run
let a = {};
let b = a; // copy the reference
alert( a == b ); // true, both variables reference the same object
alert( a === b ); // true
```
And here two independent objects are not equal, even though both are empty:
```js run
let a = {};
let b = {}; // two independent objects
alert( a == b ); // false
```
For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are necessary very rarely and usually are a result of a coding mistake.
### Const object
An object declared as `const`*can* be changed.
For instance:
```js run
const user = {
name: "John"
};
*!*
user.age = 25; // (*)
*/!*
alert(user.age); // 25
```
It might seem that the line `(*)` would cause an error, but no, there's totally no problem. That's because `const` fixes only value of `user` itself. And here `user` stores the reference to the same object all the time. The line `(*)` goes *inside* the object, it doesn't reassign `user`.
The `const` would give an error if we try to set `user` to something else, for instance:
```js run
const user = {
name: "John"
};
*!*
// Error (can't reassign user)
*/!*
user = {
name: "Pete"
};
```
...But what if we want to make constant object properties? So that `user.age = 25` would give an error. That's possible too. We'll cover it in the chapter <info:property-descriptors>.
## Cloning and merging, Object.assign
So, copying an object variable creates one more reference to the same object.
But what if we need to duplicate an object? Create an independent copy, a clone?
That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. Actually, that's rarely needed. Copying by reference is good most of the time.
But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level.
Like this:
```js run
let user = {
name: "John",
age: 30
};
*!*
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
*/!*
// now clone is a fully independent clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
```
Also we can use the method [Object.assign](mdn:js/Object/assign) for that.
The syntax is:
```js
Object.assign(dest, [src1, src2, src3...])
```
- Arguments `dest`, and `src1, ..., srcN` (can be as many as needed) are objects.
- It copies the properties of all objects `src1, ..., srcN` into `dest`. In other words, properties of all arguments starting from the 2nd are copied into the 1st. Then it returns `dest`.
For instance, we can use it to merge several objects into one:
```js
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
*!*
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
*/!*
// now user = { name: "John", canView: true, canEdit: true }
```
If the receiving object (`user`) already has the same named property, it will be overwritten:
We also can use `Object.assign` to replace the loop for simple cloning:
```js
let user = {
name: "John",
age: 30
};
*!*
let clone = Object.assign({}, user);
*/!*
```
It copies all properties of `user` into the empty object and returns it. Actually, the same as the loop, but shorter.
Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them?
Like this:
```js run
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
alert( user.sizes.height ); // 182
```
Now it's not enough to copy `clone.sizes = user.sizes`, because the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes:
Like this:
```js run
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
```
To fix that, we should use the cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning".
There's a standard algorithm for deep cloning that handles the case above and more complex cases, called the [Structured cloning algorithm](https://html.spec.whatwg.org/multipage/structured-data.html#safe-passing-of-structured-data). In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library [lodash](https://lodash.com), the method is called [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep).
## Summary
Objects are associative arrays with several special features.
@ -725,17 +482,13 @@ They store properties (key-value pairs), where:
To access a property, we can use:
- The dot notation: `obj.property`.
- Square brackets notation `obj["property"]`. Square brackets allow to take the key from a variable, like `obj[varWithKey]`.
- Square brackets notation `obj["property"]`. Square brackets allow taking the key from a variable, like `obj[varWithKey]`.
Additional operators:
- To delete a property: `delete obj.prop`.
- To check if a property with the given key exists: `"key" in obj`.
- To iterate over an object: `for (let key in obj)` loop.
Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object. All operations via copied references (like adding/removing properties) are performed on the same single object.
To make a "real copy" (a clone) we can use `Object.assign` or [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep).
What we've studied in this chapter is called a "plain object", or just `Object`.
There are many other kinds of objects in JavaScript: