Tutorials
DOM tree
The backbone of an HTML document is tags.
According to the Document Object Model (DOM), every HTML tag is an object. Nested tags are âchildrenâ of the enclosing one. The text inside a tag is an object as well.
All these objects are accessible using JavaScript, and we can use them to modify the page.
For example, document.body
is the object representing the <body>
tag.
Running this code will make the <body>
red for 3 seconds:
Here we used style.background
to change the background color of document.body
, but there are many other properties, such as:
innerHTML
â HTML contents of the node.offsetWidth
â the node width (in pixels)âŠand so on.
Soon weâll learn more ways to manipulate the DOM, but first we need to know about its structure.
Letâs start with the following simple document:
The DOM represents HTML as a tree structure of tags. Hereâs how it looks:âŸHTMLâŸHEAD#text â”âŁâŁâŸTITLE#text About elk#text â”#text â”âŸBODY#text The truth about elk.
On the picture above, you can click on element nodes and their children will open/collapse.
Every tree node is an object.
Tags are element nodes (or just elements) and form the tree structure: <html>
is at the root, then <head>
and <body>
are its children, etc.
The text inside elements forms text nodes, labelled as #text
. A text node contains only a string. It may not have children and is always a leaf of the tree.
For instance, the <title>
tag has the text "About elk"
.
Please note the special characters in text nodes:
a newline:
â”
(in JavaScript known as\n
)a space:
âŁ
Spaces and newlines are totally valid characters, like letters and digits. They form text nodes and become a part of the DOM. So, for instance, in the example above the <head>
tag contains some spaces before <title>
, and that text becomes a #text
node (it contains a newline and some spaces only).
There are only two top-level exclusions:
Spaces and newlines before
<head>
are ignored for historical reasons.If we put something after
</body>
, then that is automatically moved inside thebody
, at the end, as the HTML spec requires that all content must be inside<body>
. So there canât be any spaces after</body>
.
In other cases everythingâs straightforward â if there are spaces (just like any character) in the document, then they become text nodes in the DOM, and if we remove them, then there wonât be any.
Here are no space-only text nodes:
âŸHTMLâŸHEADâŸTITLE#text About elkâŸBODY#text The truth about elk.Spaces at string start/end and space-only text nodes are usually hidden in tools
Browser tools (to be covered soon) that work with DOM usually do not show spaces at the start/end of the text and empty text nodes (line-breaks) between tags.
Developer tools save screen space this way.
On further DOM pictures weâll sometimes omit them when they are irrelevant. Such spaces usually do not affect how the document is displayed.
If the browser encounters malformed HTML, it automatically corrects it when making the DOM.
For instance, the top tag is always <html>
. Even if it doesnât exist in the document, it will exist in the DOM, because the browser will create it. The same goes for <body>
.
As an example, if the HTML file is the single word "Hello"
, the browser will wrap it into <html>
and <body>
, and add the required <head>
, and the DOM will be:âŸHTMLâŸHEADâŸBODY#text Hello
While generating the DOM, browsers automatically process errors in the document, close tags and so on.
A document with unclosed tags:
âŠwill become a normal DOM as the browser reads tags and restores the missing parts:âŸHTMLâŸHEADâŸBODYâŸP#text HelloâŸLI#text MomâŸLI#text andâŸLI#text DadTables always have <tbody>
An interesting âspecial caseâ is tables. By DOM specification they must have <tbody>
tag, but HTML text may omit it. Then the browser creates <tbody>
in the DOM automatically.
For the HTML:
DOM-structure will be:âŸTABLEâŸTBODYâŸTRâŸTD#text 1
You see? The <tbody>
appeared out of nowhere. We should keep this in mind while working with tables to avoid surprises.
There are some other node types besides elements and text nodes.
For example, comments:
âŸHTMLâŸHEADâŸBODY#text The truth about elk.âŸOL#text â”âŁâŁâŁâŁâŸLI#text An elk is a smart#text â”âŁâŁâŁâŁ#comment comment#text â”âŁâŁâŁâŁâŸLI#text ...and cunning animal!#text â”âŁâŁ#text â”â”â”
We can see here a new tree node type â comment node, labeled as #comment
, between two text nodes.
We may think â why is a comment added to the DOM? It doesnât affect the visual representation in any way. But thereâs a rule â if somethingâs in HTML, then it also must be in the DOM tree.
Everything in HTML, even comments, becomes a part of the DOM.
Even the <!DOCTYPE...>
directive at the very beginning of HTML is also a DOM node. Itâs in the DOM tree right before <html>
. Few people know about that. We are not going to touch that node, we even donât draw it on diagrams, but itâs there.
The document
object that represents the whole document is, formally, a DOM node as well.
There are 12 node types. In practice we usually work with 4 of them:
document
â the âentry pointâ into DOM.element nodes â HTML-tags, the tree building blocks.
text nodes â contain text.
comments â sometimes we can put information there, it wonât be shown, but JS can read it from the DOM.
To see the DOM structure in real-time, try Live DOM Viewer. Just type in the document, and it will show up as a DOM at an instant.
Another way to explore the DOM is to use the browser developer tools. Actually, thatâs what we use when developing.
To do so, open the web page elk.html, turn on the browser developer tools and switch to the Elements tab.
It should look like this:
You can see the DOM, click on elements, see their details and so on.
Please note that the DOM structure in developer tools is simplified. Text nodes are shown just as text. And there are no âblankâ (space only) text nodes at all. Thatâs fine, because most of the time we are interested in element nodes.
Clicking the button in the left-upper corner allows us to choose a node from the webpage using a mouse (or other pointer devices) and âinspectâ it (scroll to it in the Elements tab). This works great when we have a huge HTML page (and corresponding huge DOM) and would like to see the place of a particular element in it.
Another way to do it would be just right-clicking on a webpage and selecting âInspectâ in the context menu.
At the right part of the tools there are the following subtabs:
Styles â we can see CSS applied to the current element rule by rule, including built-in rules (gray). Almost everything can be edited in-place, including the dimensions/margins/paddings of the box below.
Computed â to see CSS applied to the element by property: for each property we can see a rule that gives it (including CSS inheritance and such).
Event Listeners â to see event listeners attached to DOM elements (weâll cover them in the next part of the tutorial).
âŠand so on.
The best way to study them is to click around. Most values are editable in-place.
As we work the DOM, we also may want to apply JavaScript to it. Like: get a node and run some code to modify it, to see the result. Here are few tips to travel between the Elements tab and the console.
For the start:
Select the first
<li>
in the Elements tab.Press Esc â it will open console right below the Elements tab.
Now the last selected element is available as $0
, the previously selected is $1
etc.
We can run commands on them. For instance, $0.style.background = 'red'
makes the selected list item red, like this:
Thatâs how to get a node from Elements in Console.
Thereâs also a road back. If thereâs a variable referencing a DOM node, then we can use the command inspect(node)
in Console to see it in the Elements pane.
Or we can just output the DOM node in the console and explore âin-placeâ, like document.body
below:
Thatâs for debugging purposes of course. From the next chapter on weâll access and modify DOM using JavaScript.
The browser developer tools are a great help in development: we can explore the DOM, try things and see what goes wrong
An Introduction to JavaScript
Letâs see whatâs so special about JavaScript, what we can achieve with it, and what other technologies play well with it.
JavaScript was initially created to âmake web pages aliveâ.
The programs in this language are called scripts. They can be written right in a web pageâs HTML and run automatically as the page loads.
Scripts are provided and executed as plain text. They donât need special preparation or compilation to run.
In this aspect, JavaScript is very different from another language called Java.Why is it called JavaScript?
When JavaScript was created, it initially had another name: âLiveScriptâ. But Java was very popular at that time, so it was decided that positioning a new language as a âyounger brotherâ of Java would help.
But as it evolved, JavaScript became a fully independent language with its own specification called ECMAScript, and now it has no relation to Java at all.
Today, JavaScript can execute not only in the browser, but also on the server, or actually on any device that has a special program called the JavaScript engine.
The browser has an embedded engine sometimes called a âJavaScript virtual machineâ.
Different engines have different âcodenamesâ. For example:
V8 â in Chrome and Opera.
SpiderMonkey â in Firefox.
âŠThere are other codenames like âChakraâ for IE, âChakraCoreâ for Microsoft Edge, âNitroâ and âSquirrelFishâ for Safari, etc.
The terms above are good to remember because they are used in developer articles on the internet. Weâll use them too. For instance, if âa feature X is supported by V8â, then it probably works in Chrome and Opera.How do engines work?
Engines are complicated. But the basics are easy.
The engine (embedded if itâs a browser) reads (âparsesâ) the script.
Then it converts (âcompilesâ) the script to the machine language.
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.
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.
JavaScriptâs capabilities greatly depend on the environment itâs running in. For instance, Node.js supports functions that allow JavaScript to read/write arbitrary files, perform network requests, etc.
In-browser JavaScript can do everything related to webpage manipulation, interaction with the user, and the webserver.
For instance, in-browser JavaScript is able to:
Add new HTML to the page, change the existing content, modify styles.
React to user actions, run on mouse clicks, pointer movements, key presses.
Get and set cookies, ask questions to the visitor, show messages.
Remember the data on the client-side (âlocal storageâ).
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.
Examples of such restrictions include:
JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS functions.
Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like âdroppingâ a file into a browser window or selecting it via an
<input>
tag.There are ways to interact with 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.
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).
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 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 URLhttp://gmail.com
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.
There are at least three great things about JavaScript:
Full integration with HTML/CSS.
Simple things are done simply.
Support 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.
The syntax of JavaScript does not suit everyoneâs needs. Different people want different features.
Thatâs to be expected, because projects and requirements are different for everyone.
So recently a plethora of new languages appeared, which are transpiled (converted) to JavaScript before they run in the browser.
Modern tools make the transpilation very fast and transparent, actually allowing developers to code in another language and auto-converting it âunder the hoodâ.
Examples of such languages:
CoffeeScript 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 is concentrated on adding âstrict data typingâ to simplify the development and support of complex systems. It is developed by Microsoft.
Flow also adds data typing, but in a different way. Developed by Facebook.
Dart 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 is a Python transpiler to JavaScript that enables the writing of applications in pure Python without JavaScript.
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.
Hello, world!
This part of the tutorial is about core JavaScript, the language itself.
But we need a working environment to run our scripts and, since this book is online, the browser is a good choice. Weâll keep the amount of browser-specific commands (like alert
) to a minimum so that you donât spend time on them if you plan to concentrate on another environment (like Node.js). Weâll focus on JavaScript in the browser in the next part of the tutorial.
So first, letâs see how we attach a script to a webpage. For server-side environments (like Node.js), you can execute the script with a command like "node my.js"
.
JavaScript programs can be inserted almost anywhere into an HTML document using the <script>
tag.
For instance:
You can run the example by clicking the âPlayâ button in the right-top corner of the box above.
The <script>
tag contains JavaScript code which is automatically executed when the browser processes the tag.
The <script>
tag has a few attributes that are rarely used nowadays but can still be found in old code:The type
attribute: <script type=âŠ>
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: <script language=âŠ>
This attribute was meant to show the language of the script. This attribute no longer makes sense because JavaScript is the default language. There is no need to use it.Comments before and after scripts.
In really ancient books and guides, you may find comments inside <script>
tags, like this:
This trick isnât used in modern JavaScript. These comments hide JavaScript code from old browsers that didnât know how to process the <script>
tag. Since browsers released in the last 15 years donât have this issue, this kind of comment can help you identify really old code.
If we have a lot of JavaScript code, we can put it into a separate file.
Script files are attached to HTML with the src
attribute:
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.
We can give a full URL as well. For instance:
To attach several scripts, use multiple tags:
Please note:
As a rule, only the simplest scripts are put into HTML. More complex ones reside in separate files.
The benefit of a separate file is that the browser will download it and store it in its cache.
Other pages that reference the same script will take it from the cache instead of downloading it, so the file is actually downloaded only once.
That reduces traffic and makes pages faster.If src
is set, the script content is ignored.
A single <script>
tag canât have both the src
attribute and code inside.
This wonât work:
We must choose either an external <script src="âŠ">
or a regular <script>
with code.
The example above can be split into two scripts to work:
Type Conversions
Most of the time, operators and functions automatically convert the values given to them to the right type.
For example, alert
automatically converts any value to a string to show it. Mathematical operations convert values to numbers.
There are also cases when we need to explicitly convert a value to the expected type.Not talking about objects yet
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 Object to primitive conversion weâll see how objects fit in.
String conversion happens when we need the string form of a value.
For example, alert(value)
does it to show the value.
We can also call the String(value)
function to convert a value to a string:
String conversion is mostly obvious. A false
becomes "false"
, null
becomes "null"
, etc.
Numeric conversion happens in mathematical functions and expressions automatically.
For example, when division /
is applied to non-numbers:
We can use the Number(value)
function to explicitly convert a value
to a number:
Explicit conversion is usually required when we read a value from a string-based source like a text form but expect a number to be entered.
If the string is not a valid number, the result of such a conversion is NaN
. For instance:
Numeric conversion rules:
Value
BecomesâŠ
undefined
NaN
null
0
true and false
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
.
Examples:
Please note that null
and undefined
behave differently here: null
becomes zero while undefined
becomes NaN
.
Most mathematical operators also perform such conversion, weâll see that in the next chapter.
Boolean conversion is the simplest one.
It happens in logical operations (later weâll meet condition tests and other similar things) but can also be performed explicitly with a call to Boolean(value)
.
The conversion rule:
Values that are intuitively âemptyâ, like
0
, an empty string,null
,undefined
, andNaN
, becomefalse
.Other values become
true
.
For instance:
Please note: the string with zero "0"
is true
Some languages (namely PHP) treat "0"
as false
. But in JavaScript, a non-empty string is always true
.
Loops: while and for
We often need to repeat actions.
For example, outputting goods from a list one after another or just running the same code for each number from 1 to 10.
Loops are a way to repeat the same code multiple times.
The while
loop has the following syntax:
While the condition
is truthy, the code
from the loop body is executed.
For instance, the loop below outputs i
while i < 3
:
A single execution of the loop body is called an iteration. The loop in the example above makes three iterations.
If i++
was missing from the example above, the loop would repeat (in theory) forever. In practice, the browser provides ways to stop such loops, and in server-side JavaScript, we can kill the process.
Any expression or variable can be a loop condition, not just comparisons: the condition is evaluated and converted to a boolean by while
.
For instance, a shorter way to write while (i != 0)
is while (i)
:
Curly braces are not required for a single-line body
If the loop body has a single statement, we can omit the curly braces {âŠ}
:
The condition check can be moved below the loop body using the do..while
syntax:
The loop will first execute the body, then check the condition, and, while itâs truthy, execute it again and again.
For example:
This form of syntax should only be used when you want the body of the loop to execute at least once regardless of the condition being truthy. Usually, the other form is preferred: while(âŠ) {âŠ}
.
The for
loop is more complex, but itâs also the most commonly used loop.
It looks like this:
Letâs learn the meaning of these parts by example. The loop below runs alert(i)
for i
from 0
up to (but not including) 3
:
Letâs examine the for
statement part-by-part:
part
begin
i = 0
Executes once upon entering the loop.
condition
i < 3
Checked before every loop iteration. If false, the loop stops.
body
alert(i)
Runs again and again while the condition is truthy.
step
i++
Executes after the body on each iteration.
The general loop algorithm works like this:
That is, begin
executes once, and then it iterates: after each condition
test, body
and step
are executed.
If you are new to loops, it could help to go back to the example and reproduce how it runs step-by-step on a piece of paper.
Hereâs exactly what happens in our case:
Inline variable declaration
Here, the âcounterâ variable i
is declared right in the loop. This is called an âinlineâ variable declaration. Such variables are visible only inside the loop.
Instead of defining a variable, we could use an existing one:
Any part of for
can be skipped.
For example, we can omit begin
if we donât need to do anything at the loop start.
Like here:
We can also remove the step
part:
This makes the loop identical to while (i < 3)
.
We can actually remove everything, creating an infinite loop:
Please note that the two for
semicolons ;
must be present. Otherwise, there would be a syntax error.
Normally, a loop exits when its condition becomes falsy.
But we can force the exit at any time using the special break
directive.
For example, the loop below asks the user for a series of numbers, âbreakingâ when no number is entered:
The break
directive is activated at the line (*)
if the user enters an empty line or cancels the input. It stops the loop immediately, passing control to the first line after the loop. Namely, alert
.
The combination âinfinite loop + break
as neededâ is great for situations when a loopâs condition must be checked not in the beginning or end of the loop, but in the middle or even in several places of its body.
The continue
directive is a âlighter versionâ of break
. It doesnât stop the whole loop. Instead, it stops the current iteration and forces the loop to start a new one (if the condition allows).
We can use it if weâre done with the current iteration and would like to move on to the next one.
The loop below uses continue
to output only odd values:
For even values of i
, the continue
directive stops executing the body and passes control to the next iteration of for
(with the next number). So the alert
is only called for odd values.The continue
directive helps decrease nesting
A loop that shows odd values could look like this:
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.No break/continue
to the right side of â?â
Please note that syntax constructs that are not expressions cannot be used with the ternary operator ?
. In particular, directives such as break/continue
arenât allowed there.
For example, if we take this code:
âŠand rewrite it using a question mark:
âŠit stops working: thereâs a syntax error.
This is just another reason not to use the question mark operator ?
instead of if
.
Sometimes we need to break out from multiple nested loops at once.
For example, in the code below we loop over i
and j
, prompting for the coordinates (i, j)
from (0,0)
to (2,2)
:
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!
A label is an identifier with a colon before a loop:
The break <labelName>
statement in the loop below breaks out to the label:
In the code above, break outer
looks upwards for the label named outer
and breaks out of that loop.
So the control goes straight from (*)
to alert('Done!')
.
We can also move the label onto a separate line:
The continue
directive can also be used with a label. In this case, code execution jumps to the next iteration of the labeled loop.Labels do not allow to âjumpâ anywhere
Labels do not allow us to jump into an arbitrary place in the code.
For example, it is impossible to do this:
A call to break/continue
is only possible from inside a loop and the label must be somewhere above the directive.
Variables
Most of the time, a JavaScript application needs to work with information. Here are two examples:
An online shop â the information might include goods being sold and a shopping cart.
A chat application â the information might include users, messages, and much more.
Variables are used to store this information.
A variable is a ânamed storageâ for data. We can use variables to store goodies, visitors, and other data.
To create a variable in JavaScript, use the let
keyword.
The statement below creates (in other words: declares) a variable with the name âmessageâ:
Now, we can put some data into it by using the assignment operator =
:
The string is now saved into the memory area associated with the variable. We can access it using the variable name:
To be concise, we can combine the variable declaration and assignment into a single line:
We can also declare multiple variables in one line:
That might seem shorter, but we donât recommend it. For the sake of better readability, please use a single line per variable.
The multiline variant is a bit longer, but easier to read:
Some people also define multiple variables in this multiline style:
âŠOr even in the âcomma-firstâ style:
Technically, all these variants do the same thing. So, itâs a matter of personal taste and aesthetics.var
instead of let
In older scripts, you may also find another keyword: var
instead of let
:
The var
keyword is almost the same as let
. It also declares a variable, but in a slightly different, âold-schoolâ way.
There are subtle differences between let
and var
, but they do not matter for us yet. Weâll cover them in detail in the chapter The old "var".
We can easily grasp the concept of a âvariableâ if we imagine it as a âboxâ for data, with a uniquely-named sticker on it.
For instance, the variable message
can be imagined as a box labeled "message"
with the value "Hello!"
in it:
We can put any value in the box.
We can also change it as many times as we want:
When the value is changed, the old data is removed from the variable:
We can also declare two variables and copy data from one into the other.
Declaring twice triggers an error
A variable should be declared only once.
A repeated declaration of the same variable is an error:
So, we should declare a variable once and then refer to it without let
.Functional languages
Itâs interesting to note that there exist functional programming languages, like Scala or Erlang that forbid changing variable values.
In such languages, once the value is stored âin the boxâ, itâs there forever. If we need to store something else, the language forces us to create a new box (declare a new variable). We canât reuse the old one.
Though it may seem a little odd at first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation confers certain benefits. Studying such a language (even if youâre not planning to use it soon) is recommended to broaden the mind.
There are two limitations on variable names in JavaScript:
The name must contain only letters, digits, or the symbols
$
and_
.The first character must not be a digit.
Examples of valid names:
When the name contains multiple words, camelCase is commonly used. That is: words go one after another, each word except first starting with a capital letter: myVeryLongName
.
Whatâs interesting â the dollar sign '$'
and the underscore '_'
can also be used in names. They are regular symbols, just like letters, without any special meaning.
These names are valid:
Examples of incorrect variable names:
Case matters
Variables named apple
and AppLE
are two different variables.Non-Latin letters are allowed, but not recommended
It is possible to use any language, including cyrillic letters or even hieroglyphs, like this:
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.Reserved names
There is a list of reserved words, which cannot be used as variable names because they are used by the language itself.
For example: let
, class
, return
, and function
are reserved.
The code below gives a syntax error:
An assignment without use strict
Normally, we need to define a variable before using it. But in the old times, it was technically possible to create a variable by a mere assignment of the value without using let
. This still works now if we donât put use strict
in our scripts to maintain compatibility with old scripts.
This is a bad practice and would cause an error in strict mode:
To declare a constant (unchanging) variable, use const
instead of let
:
Variables declared using const
are called âconstantsâ. They cannot be reassigned. An attempt to do so would cause an error:
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.
There is a widespread practice to use constants as aliases for difficult-to-remember values that are known prior to execution.
Such constants are named using capital letters and underscores.
For instance, letâs make constants for colors in so-called âwebâ (hexadecimal) format:
Benefits:
COLOR_ORANGE
is much easier to remember than"#FF7F00"
.It is much easier to mistype
"#FF7F00"
thanCOLOR_ORANGE
.When reading the code,
COLOR_ORANGE
is much more meaningful than#FF7F00
.
When should we use capitals for a constant and when should we name it normally? Letâs make that clear.
Being a âconstantâ just means that a variableâs value never changes. But there are constants that are known prior to execution (like a hexadecimal value for red) and there are constants that are calculated in run-time, during the execution, but do not change after their initial assignment.
For instance:
The value of pageLoadTime
is not known prior to the page load, so itâs named normally. But itâs still a constant because it doesnât change after assignment.
In other words, capital-named constants are only used as aliases for âhard-codedâ values.
Talking about variables, thereâs one more extremely important thing.
A variable name should have a clean, obvious meaning, describing the data that it stores.
Variable naming is one of the most important and complex skills in programming. A quick glance at variable names can reveal which code was written by a beginner versus an experienced developer.
In a real project, most of the time is spent modifying and extending an existing code base rather than writing something completely separate from scratch. When we return to some code after doing something else for a while, itâs much easier to find information that is well-labeled. Or, in other words, when the variables have good names.
Please spend time thinking about the right name for a variable before declaring it. Doing so will repay you handsomely.
Some good-to-follow rules are:
Use human-readable names like
userName
orshoppingCart
.Stay away from abbreviations or short names like
a
,b
,c
, unless you really know what youâre doing.Make names maximally descriptive and concise. Examples of bad names are
data
andvalue
. Such names say nothing. Itâs only okay to use them if the context of the code makes it exceptionally obvious which data or value the variable is referencing.Agree on terms within your team and in your own mind. If a site visitor is called a âuserâ then we should name related variables
currentUser
ornewUser
instead ofcurrentVisitor
ornewManInTown
.
Sounds simple? Indeed it is, but creating descriptive and concise variable names in practice is not. Go for it.Reuse or create?
And the last note. There are some lazy programmers who, instead of declaring new variables, tend to reuse existing ones.
As a result, their variables are like boxes into which people throw different things without changing their stickers. Whatâs inside the box now? Who knows? We need to come closer and check.
Such programmers save a little bit on variable declaration but lose ten times more on debugging.
An extra variable is good, not evil.
Modern JavaScript minifiers and browsers optimize code well enough, so it wonât create performance issues. Using different variables for different values can even help the engine optimize your code.
We can declare variables to store data by using the var
, let
, or const
keywords.
let
â is a modern variable declaration.var
â is an old-school variable declaration. Normally we donât use it at all, but weâll cover subtle differences fromlet
in the chapter The old "var", just in case you need them.const
â is likelet
, but the value of the variable canât be changed.
Variables should be named in a way that allows us to easily understand whatâs inside them.
importance: 2
Declare two variables:
admin
andname
.Assign the value
"John"
toname
.Copy the value from
name
toadmin
.Show the value of
admin
usingalert
(must output âJohnâ).
solution
importance: 3
Create a variable with the name of our planet. How would you name such a variable?
Create a variable to store the name of a current visitor to a website. How would you name that variable?
solution
importance: 4
Examine the following code:
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).
Would it be right to use upper case for birthday
? For age
? Or even for both?
Data types
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:
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.
The number type represents both integer and floating point numbers.
There are many operations for numbers, e.g. multiplication *
, division /
, addition +
, subtraction -
, and so on.
Besides regular numbers, there are so-called âspecial numeric valuesâ which also belong to this data type: Infinity
, -Infinity
and NaN
.
Infinity
represents the mathematical Infinity â. It is a special value thatâs greater than any number.We can get it as a result of division by zero:
Or just reference it directly:
NaN
represents a computational error. It is a result of an incorrect or an undefined mathematical operation, for instance:NaN
is sticky. Any further operation onNaN
returnsNaN
:So, if thereâs a
NaN
somewhere in a mathematical expression, it propagates to the whole result.
Mathematical operations are safe
Doing maths is âsafeâ in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc.
The script will never stop with a fatal error (âdieâ). At worst, weâll get NaN
as the result.
Special numeric values formally belong to the ânumberâ type. Of course they are not numbers in the common sense of this word.
Weâll see more about working with numbers in the chapter Numbers.
In JavaScript, the ânumberâ type cannot represent integer values larger than (253-1)
(thatâs 9007199254740991
), or less than -(253-1)
for negatives. Itâs a technical limitation caused by their internal representation.
For most purposes thatâs quite enough, but sometimes we need really big numbers, e.g. for cryptography or microsecond-precision timestamps.
BigInt
type was recently added to the language to represent integers of arbitrary length.
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 BigInt. Read it when you need such big numbers.Compatibility issues
Right now, BigInt
is supported in Firefox/Chrome/Edge/Safari, but not in IE.
You can check MDN BigInt compatibility table to know which versions of a browser are supported.
A string in JavaScript must be surrounded by quotes.
In JavaScript, there are 3 types of quotes.
Double quotes:
"Hello"
.Single quotes:
'Hello'
.Backticks:
`Hello`
.
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:
The expression inside ${âŠ}
is evaluated and the result becomes a part of the string. We can put anything in there: a variable like name
or an arithmetical expression like 1 + 2
or something more complex.
Please note that this can only be done in backticks. Other quotes donât have this embedding functionality!
Weâll cover strings more thoroughly in the chapter Strings.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 called âcharâ.
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.
The boolean type has only two values: true
and false
.
This type is commonly used to store yes/no values: true
means âyes, correctâ, and false
means âno, incorrectâ.
For instance:
Boolean values also come as a result of comparisons:
Weâll cover booleans more deeply in the chapter Logical operators.
The special null
value does not belong to any of the types described above.
It forms a separate type of its own which contains only the null
value:
In JavaScript, null
is not a âreference to a non-existing objectâ or a ânull pointerâ like in some other languages.
Itâs just a special value which represents ânothingâ, âemptyâ or âvalue unknownâ.
The code above states that age
is unknown.
The special value undefined
also stands apart. It makes a type of its own, just like null
.
The meaning of undefined
is âvalue is not assignedâ.
If a variable is declared, but not assigned, then its value is undefined
:
Technically, it is possible to explicitly assign undefined
to a variable:
âŠ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.
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.
Being that important, objects deserve a special treatment. Weâll deal with them later in the chapter Objects, 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 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:
As an operator:
typeof x
.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:
The last three lines may need additional explanation:
Math
is a built-in object that provides mathematical operations. We will learn it in the chapter Numbers. Here, it serves just as an example of an object.The result of
typeof null
is"object"
. Thatâs an officially recognized error intypeof
behavior, coming from the early days of JavaScript and kept for compatibility. Definitely,null
is not an object. It is a special value with a separate type of its own.The result of
typeof alert
is"function"
, becausealert
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. Buttypeof
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.
There are 8 basic data types in JavaScript.
number
for numbers of any kind: integer or floating-point, integers are limited by±(253-1)
.bigint
is for integer numbers of arbitrary length.string
for strings. A string may have zero or more characters, thereâs no separate single-character type.boolean
fortrue
/false
.null
for unknown values â a standalone type that has a single valuenull
.undefined
for unassigned values â a standalone type that has a single valueundefined
.object
for more complex data structures.symbol
for unique identifiers.
The typeof
operator allows us to see which type is stored in a variable.
Two forms:
typeof x
ortypeof(x)
.Returns a string with the name of the type, like
"string"
.For
null
returns"object"
â this is an error in the language, itâs not actually an object.
In the next chapters, weâll concentrate on primitive values and once weâre familiar with them, weâll move on to objects.
importance: 5
What is the output of the script?
solution
Backticks embed the expression inside ${...}
into the string.
Conditional branching: if, '?'
Sometimes, we need to perform different actions based on different conditions.
To do that, we can use the if
statement and the conditional operator ?
, thatâs also called a âquestion markâ operator.
The if(...)
statement evaluates a condition in parentheses and, if the result is true
, executes a block of code.
For example:
In the example above, the condition is a simple equality check (year == 2015
), but it can be much more complex.
If we want to execute more than one statement, we have to wrap our code block inside curly braces:
We recommend wrapping your code block with curly braces {}
every time you use an if
statement, even if there is only one statement to execute. Doing so improves readability.
The if (âŠ)
statement evaluates the expression in its parentheses and converts the result to a boolean.
Letâs recall the conversion rules from the chapter Type Conversions:
A number
0
, an empty string""
,null
,undefined
, andNaN
all becomefalse
. Because of that they are called âfalsyâ values.Other values become
true
, so they are called âtruthyâ.
So, the code under this condition would never execute:
âŠand inside this condition â it always will:
We can also pass a pre-evaluated boolean value to if
, like this:
The if
statement may contain an optional âelseâ block. It executes when the condition is falsy.
For example:
Sometimes, weâd like to test several variants of a condition. The else if
clause lets us do that.
For example:
In the code above, JavaScript first checks year < 2015
. If that is falsy, it goes to the next condition year > 2015
. If that is also falsy, it shows the last alert
.
There can be more else if
blocks. The final else
is optional.
Sometimes, we need to assign a variable depending on a condition.
For instance:
The so-called âconditionalâ or âquestion markâ operator lets us do that in a shorter and simpler way.
The operator is represented by a question mark ?
. Sometimes itâs called âternaryâ, because the operator has three operands. It is actually the one and only operator in JavaScript which has that many.
The syntax is:
The condition
is evaluated: if itâs truthy then value1
is returned, otherwise â value2
.
For example:
Technically, we can omit the parentheses around age > 18
. The question mark operator has a low precedence, so it executes after the comparison >
.
This example will do the same thing as the previous one:
But parentheses make the code more readable, so we recommend using them.Please note:
In the example above, you can avoid using the question mark operator because the comparison itself returns true/false
:
A sequence of question mark operators ?
can return a value that depends on more than one condition.
For instance:
It may be difficult at first to grasp whatâs going on. But after a closer look, we can see that itâs just an ordinary sequence of tests:
The first question mark checks whether
age < 3
.If true â it returns
'Hi, baby!'
. Otherwise, it continues to the expression after the colon â":"â, checkingage < 18
.If thatâs true â it returns
'Hello!'
. Otherwise, it continues to the expression after the next colon â":"â, checkingage < 100
.If thatâs true â it returns
'Greetings!'
. Otherwise, it continues to the expression after the last colon â":"â, returning'What an unusual age!'
.
Hereâs how this looks using if..else
:
Sometimes the question mark ?
is used as a replacement for if
:
Depending on the condition company == 'Netscape'
, either the first or the second expression after the ?
gets executed and shows an alert.
We donât assign a result to a variable here. Instead, we execute different code depending on the condition.
Itâs not recommended to use the question mark operator in this way.
The notation is shorter than the equivalent if
statement, which appeals to some programmers. But it is less readable.
Here is the same code using if
for comparison:
Our eyes scan the code vertically. Code blocks which span several lines are easier to understand than a long, horizontal instruction set.
The purpose of the question mark operator ?
is to return one value or another depending on its condition. Please use it for exactly that. Use if
when you need to execute different branches of code.
importance: 5
Will alert
be shown?
solution
importance: 2
Using the if..else
construct, write the code which asks: âWhat is the âofficialâ name of JavaScript?â
If the visitor enters âECMAScriptâ, then output âRight!â, otherwise â output: âDidnât know? ECMAScript!â
Demo in new windowsolution
importance: 2
Using if..else
, write the code which gets a number via prompt
and then shows in alert
:
1
, if the value is greater than zero,-1
, if less than zero,0
, if equals zero.
In this task we assume that the input is always a number.
Demo in new windowsolution
importance: 5
Rewrite this if
using the conditional operator '?'
:
solution
importance: 5
Rewrite if..else
using multiple ternary operators '?'
.
For readability, itâs recommended to split the code into multiple lines.
solution
Code structure
The first thing weâll study is the building blocks of code.
Statements are syntax constructs and commands that perform actions.
Weâve already seen a statement, alert('Hello, world!')
, which shows the message âHello, world!â.
We can have as many statements in our code as we want. Statements can be separated with a semicolon.
For example, here we split âHello Worldâ into two alerts:
Usually, statements are written on separate lines to make the code more readable:
A semicolon may be omitted in most cases when a line break exists.
This would also work:
Here, JavaScript interprets the line break as an âimplicitâ semicolon. This is called an automatic semicolon insertion.
In most cases, a newline implies a semicolon. But âin most casesâ does not mean âalwaysâ!
There are cases when a newline does not mean a semicolon. For example:
The code outputs 6
because JavaScript does not insert semicolons here. It is intuitively obvious that if the line ends with a plus "+"
, then it is an âincomplete expressionâ, so the semicolon is not required. And in this case that works as intended.
But there are situations where JavaScript âfailsâ to assume a semicolon where it is really needed.
Errors which occur in such cases are quite hard to find and fix.An example of an error
If youâre curious to see a concrete example of such an error, check this code out:
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
.
Now, letâs add an alert
before the code and not finish it with a semicolon:
Now if we run the code, only the first alert
is shown and then we have an error!
But everything is fine again if we add a semicolon after alert
:
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:
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.
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.
As time goes on, programs become more and more complex. It becomes necessary to add comments which describe what the code does and why.
Comments can be put into any place of a script. They donât affect its execution because the engine simply ignores them.
One-line comments start with two forward slash characters //
.
The rest of the line is a comment. It may occupy a full line of its own or follow a statement.
Like here:
Multiline comments start with a forward slash and an asterisk /*
and end with an asterisk and a forward slash */
.
Like this:
The content of comments is ignored, so if we put code inside /* ⊠*/
, it wonât execute.
Sometimes it can be handy to temporarily disable a part of code:
Functions
Quite often we need to perform a similar action in many places of the script.
For example, we need to show a nice-looking message when a visitor logs in, logs out and maybe somewhere else.
Functions are the main âbuilding blocksâ of the program. They allow the code to be called many times without repetition.
Weâve already seen examples of built-in functions, like alert(message)
, prompt(message, default)
and confirm(question)
. But we can create functions of our own as well.
To create a function we can use a function declaration.
It looks like this:
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.
Our new function can be called by its name: showMessage()
.
For instance:
The call showMessage()
executes the code of the function. Here we will see the message two times.
This example clearly demonstrates one of the main purposes of functions: to avoid code duplication.
If we ever need to change the message or the way it is shown, itâs enough to modify the code in one place: the function which outputs it.
A variable declared inside a function is only visible inside that function.
For example:
A function can access an outer variable as well, for example:
The function has full access to the outer variable. It can modify it as well.
For instance:
The outer variable is only used if thereâs no local one.
If a same-named variable is declared inside the function then it shadows the outer one. For instance, in the code below the function uses the local userName
. The outer one is ignored:
Global variables
Variables declared outside of any function, such as the outer userName
in the code above, are called global.
Global variables are visible from any function (unless shadowed by locals).
Itâs a good practice to minimize the use of global variables. Modern code has few or no globals. Most variables reside in their functions. Sometimes though, they can be useful to store project-level data.
We can pass arbitrary data to functions using parameters (also called function arguments) .
In the example below, the function has two parameters: from
and text
.
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:
If a parameter is not provided, then its value becomes undefined
.
For instance, the aforementioned function showMessage(from, text)
can be called with a single argument:
Thatâs not an error. Such a call would output "*Ann*: undefined"
. Thereâs no text
, so itâs assumed that text === undefined
.
If we want to use a âdefaultâ text
in this case, then we can specify it after =
:
Now if the text
parameter is not passed, it will get the value "no text given"
Here "no text given"
is a string, but it can be a more complex expression, which is only evaluated and assigned if the parameter is missing. So, this is also possible:
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.
Sometimes it makes sense to set default values for parameters not in the function declaration, but at a later stage, during its execution.
To check for an omitted parameter, we can compare it with undefined
:
âŠOr we could use the ||
operator:
Modern JavaScript engines support the nullish coalescing operator ??
, itâs better when falsy values, such as 0
, are considered regular:
A function can return a value back into the calling code as the result.
The simplest example would be a function that sums two values:
The directive return
can be in any place of the function. When the execution reaches it, the function stops, and the value is returned to the calling code (assigned to result
above).
There may be many occurrences of return
in a single function. For instance:
It is possible to use return
without a value. That causes the function to exit immediately.
For example:
In the code above, if checkAge(age)
returns false
, then showMovie
wonât proceed to the alert
.A function with an empty return
or without it returns undefined
If a function does not return a value, it is the same as if it returns undefined
:
An empty return
is also the same as return undefined
:
Never add a newline between return
and the value
For a long expression in return
, it might be tempting to put it on a separate line, like this:
That doesnât work, because JavaScript assumes a semicolon after return
. Thatâll work the same as:
So, it effectively becomes an empty return.
If we want the returned expression to wrap across multiple lines, we should start it at the same line as return
. Or at least put the opening parentheses there as follows:
And it will work just as we expect it to.
Functions are actions. So their name is usually a verb. It should be brief, as accurate as possible and describe what the function does, so that someone reading the code gets an indication of what the function does.
It is a widespread practice to start a function with a verbal prefix which vaguely describes the action. There must be an agreement within the team on the meaning of the prefixes.
For instance, functions that start with "show"
usually show something.
Function starting withâŠ
"getâŠ"
â return a value,"calcâŠ"
â calculate something,"createâŠ"
â create something,"checkâŠ"
â check something and return a boolean, etc.
Examples of such names:
With prefixes in place, a glance at a function name gives an understanding what kind of work it does and what kind of value it returns.One function â one action
A function should do exactly what is suggested by its name, no more.
Two independent actions usually deserve two functions, even if they are usually called together (in that case we can make a 3rd function that calls those two).
A few examples of breaking this rule:
getAge
â would be bad if it shows analert
with the age (should only get).createForm
â would be bad if it modifies the document, adding a form to it (should only create it and return).checkPermission
â would be bad if it displays theaccess granted/denied
message (should only perform the check and return the result).
These examples assume common meanings of prefixes. You and your team are free to agree on other meanings, but usually theyâre not much different. In any case, you should have a firm understanding of what a prefix means, what a prefixed function can and cannot do. All same-prefixed functions should obey the rules. And the team should share the knowledge.Ultrashort function names
Functions that are used very often sometimes have ultrashort names.
For example, the jQuery framework defines a function with $
. The Lodash library has its core function named _
.
These are exceptions. Generally functions names should be concise and descriptive.
Functions should be short and do exactly one thing. If that thing is big, maybe itâs worth it to split the function into a few smaller functions. Sometimes following this rule may not be that easy, but itâs definitely a good thing.
A separate function is not only easier to test and debug â its very existence is a great comment!
For instance, compare the two functions showPrimes(n)
below. Each one outputs prime numbers up to n
.
The first variant uses a label:
The second variant uses an additional function isPrime(n)
to test for primality:
The second variant is easier to understand, isnât it? Instead of the code piece we see a name of the action (isPrime
). Sometimes people refer to such code as self-describing.
So, functions can be created even if we donât intend to reuse them. They structure the code and make it readable.
Logical operators
There are three logical operators in JavaScript: ||
(OR), &&
(AND), !
(NOT).
Although they are called âlogicalâ, they can be applied to values of any type, not only boolean. Their result can also be of any type.
Letâs see the details.
The âORâ operator is represented with two vertical line symbols:
In classical programming, the logical OR is meant to manipulate boolean values only. If any of its arguments are true
, it returns true
, otherwise it returns false
.
In JavaScript, the operator is a little bit trickier and more powerful. But first, letâs see what happens with boolean values.
There are four possible logical combinations:
As we can see, the result is always true
except for the case when both operands are false
.
If an operand is not a boolean, itâs converted to a boolean for the evaluation.
For instance, the number 1
is treated as true
, the number 0
as false
:
Most of the time, OR ||
is used in an if
statement to test if any of the given conditions is true
.
For example:
We can pass more conditions:
The logic described above is somewhat classical. Now, letâs bring in the âextraâ features of JavaScript.
The extended algorithm works as follows.
Given multiple ORâed values:
The OR ||
operator does the following:
Evaluates operands from left to right.
For each operand, converts it to boolean. If the result is
true
, stops and returns the original value of that operand.If all operands have been evaluated (i.e. all were
false
), returns the last operand.
A value is returned in its original form, without the conversion.
In other words, a chain of OR ||
returns the first truthy value or the last one if no truthy value is found.
For instance:
This leads to some interesting usage compared to a âpure, classical, boolean-only ORâ.
Getting the first truthy value from a list of variables or expressions.
For instance, we have
firstName
,lastName
andnickName
variables, all optional (i.e. can be undefined or have falsy values).Letâs use OR
||
to choose the one that has the data and show it (or"Anonymous"
if nothing set):If all variables were falsy,
"Anonymous"
would show up.Short-circuit evaluation.
Another feature of OR
||
operator is the so-called âshort-circuitâ evaluation.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.That importance of this feature becomes obvious if an operand isnât just a value, but an expression with a side effect, such as a variable assignment or a function call.
In the example below, only the second message is printed:
In the first line, the OR
||
operator stops the evaluation immediately upon seeingtrue
, so thealert
isnât run.Sometimes, people use this feature to execute commands only if the condition on the left part is falsy.
The AND operator is represented with two ampersands &&
:
In classical programming, AND returns true
if both operands are truthy and false
otherwise:
An example with if
:
Just as with OR, any value is allowed as an operand of AND:
Given multiple ANDâed values:
The AND &&
operator does the following:
Evaluates operands from left to right.
For each operand, converts it to a boolean. If the result is
false
, stops and returns the original value of that operand.If all operands have been evaluated (i.e. all were truthy), returns the last operand.
In other words, AND returns the first falsy value or the last value if none were found.
The rules above are similar to OR. The difference is that AND returns the first falsy value while OR returns the first truthy one.
Examples:
We can also pass several values in a row. See how the first falsy one is returned:
When all values are truthy, the last value is returned:
Precedence of AND &&
is higher than OR ||
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)
.Donât replace if
with ||
or &&
Sometimes, people use the AND &&
operator as a "shorter way to write if
".
For instance:
The action in the right part of &&
would execute only if the evaluation reaches it. That is, only if (x > 0)
is true.
So we basically have an analogue for:
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.
The boolean NOT operator is represented with an exclamation sign !
.
The syntax is pretty simple:
The operator accepts a single argument and does the following:
Converts the operand to boolean type:
true/false
.Returns the inverse value.
For instance:
A double NOT !!
is sometimes used for converting a value to boolean type:
That is, the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again. In the end, we have a plain value-to-boolean conversion.
Thereâs a little more verbose way to do the same thing â a built-in Boolean
function:
The precedence of NOT !
is the highest of all logical operators, so it always executes first, before &&
or ||
.
Interaction: alert, prompt, 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
.
This one weâve seen already. It shows a message and waits for the user to press âOKâ.
For example:
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 function prompt
accepts two arguments:
It shows a modal window with a text message, an input field for the visitor, and the buttons OK/Cancel.title
The text to show the visitor.default
An optional second parameter, the initial value for the input field.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 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.
For instance:
In IE: always supply a default
The second parameter is optional, but if we donât supply it, Internet Explorer will insert the text "undefined"
into the prompt.
Run this code in Internet Explorer to see:
So, for prompts to look good in IE, we recommend always providing the second argument:
The syntax:
The function confirm
shows a modal window with a question
and two buttons: OK and Cancel.
The result is true
if OK is pressed and false
otherwise.
For example:
We covered 3 browser-specific functions to interact with visitors:alert
shows a message.prompt
shows a message asking the user to input text. It returns the text or, if Cancel button or Esc is clicked, null
.confirm
shows a message and waits for the user to press âOKâ or âCancelâ. It returns true
for OK and false
for Cancel/Esc.
All these methods are modal: they pause script execution and donât allow the visitor to interact with the rest of the page until the window has been dismissed.
There are two limitations shared by all the methods above:
The exact location of the modal window is determined by the browser. Usually, itâs in the center.
The exact look of the window also depends on the browser. We canât modify it.
That is the price for simplicity. There are other ways to show nicer windows and richer interaction with the visitor, but if âbells and whistlesâ do not matter much, these methods work just fine.
Nullish coalescing operator '??'
A recent additionThis is a recent addition to the language. Old browsers may need polyfills.
Here, in this article, weâll say that an expression is âdefinedâ when itâs neither null
nor undefined
.
The nullish coalescing operator is written as two question marks ??
.
The result of a ?? b
is:
if
a
is defined, thena
,if
a
isnât defined, thenb
.
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:
The common use case for ??
is to provide a default value for a potentially undefined variable.
For example, here we show Anonymous
if user
isnât defined:
Of course, if user
had any value except null/undefined
, then we would see it instead:
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 undefined, if the user decided not to enter a value.
Weâd like to display the user name using one of these variables, or show âAnonymousâ if all of them are undefined.
Letâs use the ??
operator for that:
The OR ||
operator can be used in the same way as ??
, as it was described in the previous chapter.
For example, in the code above we could replace ??
with ||
and still get the same result:
The OR ||
operator exists since the beginning of JavaScript, so developers were using it for such purposes for a long time.
On the other hand, the nullish coalescing operator ??
was added to JavaScript only recently, and the reason for that was that people werenât quite happy with ||
.
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:
The
height || 100
checksheight
for being a falsy value, and it really is.so the result is the second argument,
100
.
The
height ?? 100
checksheight
for beingnull/undefined
, and itâs not,so the result is
height
âas isâ, that is0
.
If the zero height is a valid value, that shouldnât be replaced with the default, then ??
does just the right thing.
The precedence of the ??
operator is rather low: 5
in the MDN table. So ??
is evaluated before =
and ?
, but after most other operations, such as +
, *
.
So if weâd like to choose a value with ??
in an expression with other operators, consider adding parentheses:
Otherwise, if we omit parentheses, then as *
has the higher precedence than ??
, it would execute first, leading to incorrect results.
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:
The limitation is surely debatable, but it was added to the language specification with the purpose to avoid programming mistakes, when people start to switch to ??
from ||
.
Use explicit parentheses to work around it:
Last updated
Was this helpful?