0% found this document useful (0 votes)
324 views

js (1)

The document provides an overview of JavaScript data types, variable declarations (let, const), and control structures (if statements, loops). It explains function definitions, parameters, arrow functions, and the concept of scope, including recursive functions and classes. Additionally, it covers object manipulation, destructuring, and JSON handling, emphasizing the flexibility and functionality of JavaScript in programming.

Uploaded by

cragnolinitomas
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
324 views

js (1)

The document provides an overview of JavaScript data types, variable declarations (let, const), and control structures (if statements, loops). It explains function definitions, parameters, arrow functions, and the concept of scope, including recursive functions and classes. Additionally, it covers object manipulation, destructuring, and JSON handling, emphasizing the flexibility and functionality of JavaScript in programming.

Uploaded by

cragnolinitomas
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 70

Types and the typeof Operator

Every value in JavaScript is one of the following types:

• A number
• The Boolean values false and true
• The special values null and undefined
• A string
• A symbol
• An object

Let variables

let variables are block scope they can only be accessed inside the block they’ ve been
defined in { }.

Here is what happens with let:

This will produce the following output:

const scope

Constants are block-scoped, just like let.


This will produce the following output:

Global variables
they can be accessed from anywhere in the program

This will output:

If you create a variable with the same name inside a function, that variable's value
will be used whenever you refer to that variable name within the scope of that
particular function. Here you can see an example:
This will output:

The same is also true for parameter names. If you have the same parameter name as
a global variable, the value of the parameter will be used:

if and if else statements

let rain = true;

if(rain){
console.log("** Taking my umbrella when I need to go outside **");
} else {
console.log("** I can leave my umbrella at home **");
}

else if statements
Ternary Operator

Switch Statement

The Default Case


Combining cases

LOOPS

While Loop
Do while loop

for loops

nested for loops

for of loop

The for of loop iterates over the elements of an iterable object, most commonly
an array or string.
There is another loop we can use to iterate over the elements of an array: the for of
loop. It cannot be used to change the value associated with the index as we can do
with the regular loop, but for processing values it is a very nice and readable loop.
Here is what the syntax looks like:
Loops and objects

for in loop

Manipulating objects with loops can also be done with another variation of the for
loop, the for in loop. The for in loop is somewhat similar to the for of loop. Again
here, we need to specify a temporary name, also referred to as a key, to store each
property name in. We can see it in action here:

If we just logged the prop, like this:

This is what our output would look like:


As you can see, all the names of the properties get printed, and not the values. This
is because the for in loop is getting the property names (keys) and not the values.
The for of is doing the opposite; it is getting the values and not the keys.

Looping over objects by converting to an


array

You can use any loop on objects, as soon as you convert the object to an array. This
can be done in three ways:

• Convert the keys of the object to an array


• Convert the values of the object to an array
• Convert the key-value entries to an array (containing arrays with two
elements: object key and object value)

If we want to loop over the keys of the object, we can use the for in loop, as we saw
in the previous section, but we can also use the for of loop if we convert it to an
array first. We do so by using the Object.keys(nameOfObject) built-in function. This
takes an object and grabs all the properties of this object and converts them to an
array.
To demonstrate how this works:

This will output:

We can loop over the properties of this array like this using the for of loop:
And this is what it will output:

Similarly, we can use the for of loop to loop over the values of the object by
converting the values to an array. The main difference here is that we use Object.
values(nameOfObject):

You can loop over these arrays in the same way you loop over any array. You can
use the length and index strategy like this in a regular for loop:

And this will output:

More interesting is how to loop over both arrays at the same time using the for of
loop. In order to do so, we will have to use Object.entries(). Let's demonstrate
what it does:

This will output:


As you can see, it is returning a two-dimensional array, containing key-value pairs.
We can loop over it like this:

And this will output:

Break

We can use break to stop looping through the array of cars when we have
found a car that matches our demands.
continue
break can be used to quit the loop, and continue can be used to move on to the next
iteration of the loop. It quits the current iteration and moves back up to check the
condition and start a new iteration.

Writing functions

calling functions

Parameters

A parameter is defined as the variable listed inside the parentheses of the function
definition, which defines the scope of the function. They are declared like so:

A practical example could be the following, which takes x and y as parameters:


Depending on the arguments you are calling with the function, the outcome of the
function can change, which makes the function a very powerful and flexible building
block. A practical example using our addTwoNumbers() function looks like this:

this will output

Default parameters

Instead, we could tell JavaScript to take different default parameters. And that can
be done like this:
If you call the function with no arguments now, it will automatically assign 2 to x
and 3 to y, unless you override them by calling the function with arguments.

If you call a function with more arguments than parameters, nothing will happen.
JavaScript will just execute the function using the first arguments that can be
mapped to parameters. Like this:

This will output:


Arrow functions

Arrow functions are a special way of writing functions that can be confusing at first.
Their use looks like this:

Or for no parameters:

Spread operator

this becomes :

It can also be used to send multiple arguments to a function


This will log 14 to the console, since it is the same as calling the function with:

You can call a function with multiple spread operators.

This will output 27 to the console, calling the function like this:

Rest parameter

If we use the rest parameter, it allows us to send in any number of


arguments and translate them into a parameter array. Here is an example:

This will log:


Returning function values
return ends the function and sends back whatever value comes after return.
we can store the result and continue working with
the result of this function in the rest of our code

SCOPE

They are out of scope outside the function and in scope inside the function. Let's
have a look at a variable defined inside a function:

This shows the following on the console:

So, the returned value I'll return that was assigned to local variable y gets
returned and stored in variable z.
The output of this code snippet is as follows:

Recursive Functions

This function is going to call itself until the value of the parameter is no longer
bigger than 0. And then it stops.

What happens when we call a function recursively is that it goes one function deeper
every time. The first function call is done last. For this function it goes like this:
• getRecursive(3)
• getRecursive(2)
• getRecursive(1)
• getRecursive(0)
• done with getRecursive(0) execution

• done with getRecursive(1) execution


• done with getRecursive(2) execution
• done with getRecursive(3) execution

The next recursive function will demonstrate that:


It will output:

Classes and objects

Remember we said that classes are just some special function beneath the surface.
We could create the object with a special function like this:

JavaScript objects are very different from those in class-based languages such
as Java and C++. A JavaScript object is simply a set of name/value pairs or
“properties,” like this:

{ name: 'Harry Smith', age: 42 }

Of course, you can store an object in a variable:

const harry = { name: 'Harry Smith', age: 42 }

Once you have such a variable, you can access the object properties with the usual dot
notation:

let harrysAge = harry.age


You can modify existing properties or add new properties:
harry.age = 40
harry.salary = 90000

The harry variable was declared as const, but as you just saw,
you can mutate the object to which it refers. However, you cannot assign a different value to
a const variable.

const sally = { name: 'Sally Lee' }

sally.age = 28 // OK—mutates the object to which sally refers

sally = { name: 'Sally Albright' }

// Error—cannot assign a different value to a const variable

In other words, const is like final in Java and not at all like
const in C++.

Use the delete operator to remove a property:

delete harry.salary

Accessing a nonexistent property yields undefined:

let boss = harry.supervisor // undefined

A property name can be computed. Then, use array brackets to access the property value:

let field = 'Age'


let harrysAge = harry[field.toLowerCase()]
Object Literal Syntax

let harry = {
name: 'Harry Smith',
age: 42, // Add more properties below
}

Quite often, when declaring an object literal, property values are stored in
variables whose names are equal to the property names. For example,

let age = 43
let harry = { name: 'Harry Smith', age: age }
// The 'age' property is set to the value of the age variable

There is a shortcut for this situation:

let harry = { name: 'Harry Smith', age } // The age property is now
43
Use brackets for the computed property names in object literals:

let harry = { name: 'Harry Smith', [field.toLowerCase()] : 42 }

A property name is always a string. If the name doesn’t follow the rules of
an identifier, quote it in an object literal:

let harry = { name: 'Harry Smith', 'favorite beer': 'IPA' }

To access such a property, you cannot use the dot notation. Use brackets
instead:

harry['favorite beer'] = 'Lager'

Note that the element types in an array don’t need to match. The numbers array
contains three numbers and a string.

An array can have missing elements:

const someNumbers = [ , 2, , 9] // No properties '0', '2'

As with any object, a nonexistent property has the value undefined. For example,

someNumbers[0] and someNumbers[6] are undefined.

You can add new elements past the end:

someNumbers[6] = 11 // Now someNumbers has length 7

Note that, as with all objects, you can change the properties of an array that
is referenced by a const variable.

Since arrays are objects, you can add arbitrary properties:

numbers.lucky = true

This is not common, but it is perfectly valid JavaScript.

The typeof operator returns 'object' for an array. To test whether an object is
an array, call Array.isArray(obj).

When an array needs to be converted to a string, all elements are turned


into strings and joined with commas. For example,
'' + [1, 2, 3]
is the string '1,2,3'.

An example of a JSON string is:


{ "name": "Harry Smith", "age": 42, "lucky numbers": [17, 29],
"lucky": false }

The JSON.stringify method turns a JavaScript object into a JSON string, and
JSON.parse parses a JSON string, yielding a JavaScript object. These methods
are commonly used when communicating with a server via HTTP.

Note

JSON.stringify drops object properties whose value is undefined,


and it turns array elements with undefined values to null. For example,

JSON.stringify({ name: ['Harry', undefined, 'Smith'], age: undefined


}) is the string '{"name":["Harry",null,"Smith"]}'.

Or even easier, put them into an object:


Some programmers use the JSON.stringify method for logging. A logging command

console.log(`harry=${harry}`)

gives you a useless message

harry=[object Object]

A remedy is to call JSON.stringify:

console.log(`harry=${JSON.stringify(harry)}`)

Note that this problem only occurs with strings that contain objects. If you log an object by
itself, the console displays it nicely. An easy alternative is to log the names and values
separately:

console.log('harry=', harry, 'sally=', sally)

console.log({harry, sally}) // Logs the object { harry: { . . . },


sally: { . . . } }

Destructuring

Let’s look at arrays first. Suppose you have an array pair with two elements.Of course, you
can get the elements like this:
let first = pair[0]
let second = pair[1]

With destructuring, this becomes:


let [first, second] = pair

This statement declares variables first and second and initializes them with pair[0] and
pair[1].

Consider this more complex case and observe how the variables are matched
with the array elements:

let [first, [second, third]] = [1, [2, 3]]


// Sets first to 1, second to 2, and third to 3

Let’s look at arrays first. Suppose you have an array pair with two elements.
Of course, you can get the elements like this:

let first = pair[0]


let second = pair[1]

With destructuring, this becomes:

let [first, second] = pair

This statement declares variables first and second and initializes them with

pair[0] and pair[1].


The array on the right-hand side can be longer than the pattern on the left-hand side. The
unmatched elements are simply ignored:

let [first, second] = [1, 2, 3]

If the array is shorter, the unmatched variables are set to undefined:

let [first, second] = [1]


// Sets first to 1, second to undefined

If the variables first and second are already declared, you can use destructuring to set them
to new values:

[first, second] = [4, 5]

TIP: To swap the values of the variables x and y, simply use:


[x, y] = [y, x]

Object destructuring
If you use destructuring for an assignment, the left-hand side doesn’t have
to consist of variables. You can use any lvalues—expressions that can be on
the left-hand side of an assignment. For example, this is valid destructuring:
[numbers[0], harry.age] = [13, 42] // Same as numbers[0] = 13;
harry.age = 42

Destructuring for objects is similar. Use property names instead of array


positions:
let harry = { name: 'Harry', age: 42 }
let { name: harrysName, age: harrysAge } = harry

This code snippet declares two variables harrysName and harrysAge and initializes
them with the name and age property values of the right-hand side object.
Keep in mind that the left-hand side is not an object literal. It is a pattern to
show how the variables are matched with the right-hand side.
Destructuring with objects is most compelling when the property has the
same name as the variable. In that case, you can omit the property name
and colon. This statement declares two variables name and age and initializes
them with the identically named properties of the object on the
right-hand side:

let { name, age } = harry

That is the same as:

let { name: name, age: age } = harry

or, of course,

let name = harry.name


let age = harry.age

Note

If you use object destructuring to set existing variables, you


must enclose the assignment expression in parentheses:

({name, age} = sally)

Advanced Destructuring

You can destructure nested objects:

let pat = { name: 'Pat', birthday: { day: 14, month: 3, year: 2000 }
}

let { birthday: { year: patsBirthYear } } = pat

// Declares the variable patsBirthYear and initializes it to 2000


Once again, note that the left-hand side of the second statement is not an object. It is a
pattern for matching the variables with the right-hand side. The statement has the same
effect as:

let patsBirthYear = pat.birthday.year

As with object literals, computed property names are supported:

let field = 'Age'


let { [field.toLowerCase()]: harrysAge } = harry
// Sets value to harry[field.toLowerCase()]

Rest Declarations

When destructuring an array, you can capture any remaining elements into an array. Add a
prefix ... before the variable name.

numbers = [1, 7, 2, 9]
let [first, second, ...others] = numbers
// first is 1, second is 7, and others is [2, 9]

If the array on the right-hand side doesn’t have sufficient elements, then the
rest variable becomes an empty array:
let [first, second, ...others] = [42]
// first is 42, second is undefined, and others is []

A rest declaration also works for objects:

let { name, ...allButName } = harry


// allButName is { age: 42 }

The allButName variable is set to an object containing all properties other than
the one with key name.
Constructors

The constructor method is a special method that we use to initialize objects with
our class blueprint.

function Employee(name, salary) {


this.name = name
this.salary = salary
}

When you call

new Employee('Harry Smith', 90000)

In addition to invoking the constructor function, the new expression carries


out another important step: It sets the object’s [[Prototype]] internal slot.
The [[Prototype]] internal slot is set to a specific object, which is attached to
the constructor function. Recall that a function is an object, so it can have
properties. Each JavaScript function has a prototype property whose value is an
object.

That object gives you a ready-made place for adding methods, like this:

Employee.prototype.raiseSalary = function(percent) {
this.salary *= 1 + percent / 100
}

As you can see, there is a lot going on. Let us have another look at the call:

const harry = new Employee('Harry Smith', 90000)

Here are the steps in detail:

1. The new operator creates a new object.

2. The [[Prototype]] internal slot of that object is set to the Employee.prototype object.
3. The new operator calls the constructor function with three parameters: this
(pointing to the newly created object), name, and salary.

4. The body of the Employee function sets the object properties by using the
this parameter.

5. The constructor returns, and the value of the new operator is the now
fully initialized object.

6. The variable Harry is initialized with the object reference. Figure 4-3 shows
the result.
Here is how you can create a new object from the Person class:

Methods

Functions on a class are called methods.

We can call the greet method on a Person object like this:

We can call the greet method on a Person object like this:


It will output:

Properties

Properties, sometimes also called fields, hold the data of the class. We have seen one
kind of property already, when we created them in our constructors:

private properties

they can only be accessed from inside the class

Right now, the firstname and lastname properties cannot be accessed from outside
the class. This is done by adding # in front of the property. If we try it:

Getters and setters


here is how to retrieve and set the private fields

Inheritance/subclasses

In JavaScript, as in Java, you use the extends keyword to express this


relationship among the Employee and Manager classes:

Behind the scenes, a prototype chain is established—see Figure 4-4. The pro-
totype of Manager.prototype is set to Employee.prototype. That way, any method that
is not declared in the subclass is looked up in the superclass.

For example, you can call the raiseSalary on a manager object:

const boss = new Manager(. . .)


boss.raiseSalary(10) // Calls Employee.prototype.raiseSalary

The instanceof operator checks whether an object belongs to a class or one of


its subclasses. Technically, the operator visits the prototype chain of an object
and checks whether it contains the prototype of a given constructor function.
For example, boss instanceof Employeeis true since Employee.prototype is in the
prototype chain of boss.

classes can have child classes that inherit the properties and methods from the parent class.
Here we have two methods in our Vehicle class: move and accelerate. And this
could be a Motorcyle class inheriting from this class using the extends keyword:

With the extends keyword we specify that a certain class is the child of another class.
In this case, Motorcycle is a child class of Vehicle. This means that we'll have access
to properties and methods from Vehicle in our Motorcycle class. We have added a
special doWheelie() method. This is not something that makes sense to add to the
Vehicle class, because this is an action that is specific to certain vehicles.
The super word in the constructor is calling the constructor from the parent, the
Vehicle constructor in this case. This makes sure that the fields from the parent
are set as well and that the methods are available without having to do anything
else: they are automatically inherited. Calling super() is not optional, you must do
it when you are in a class that is inheriting from another class, else you will get a
ReferenceError.

Because we have access to the fields of Vehicle in Motorcycle, this will work:
And this is what it will output:

We cannot access any Motorcycle specific properties or methods in our Vehicle class.
This is because not all vehicles are motorcycles, so we cannot be sure that we would
have the properties or methods from a child.
Right now, we don't use any getters and setters here, but we clearly could. If there
are getters and setters in the parent class, they are inherited by the child class as well.
This way we could influence which properties could be fetched and changed (and
how) outside our class. This is generally a good practice.

Prototypes

Suppose you have many employee objects similar to the one in the preceding
section. Then you need to make a raiseSalary property for each of them. You
can write a factory function to automate that task:

Still, each employee object has its own raiseSalary property, even though the
property value is the same function for all employees (see Figure 4-1). It would
be better if all employees could share one function.
That is where prototypes come in. A prototype collects properties that are
common to multiple objects. Here is a prototype object that holds the shared
methods:

const employeePrototype = {
raiseSalary: function(percent) {
this.salary *= 1 + percent / 100
}
}

When creating an employee object, we set its prototype. The prototype is an


“internal slot” of the object. That is the technical term used in the ECMAScript
language specification to denote an attribute of an object that is manipulated internally
without being exposed to JavaScript programmers as a property.
You can read and write the [[Property]] internal slot (as it is called in the
specification) with the methods Object.getPrototypeOf and
Object.setPrototypeOf. This function creates an employee object and sets the
prototype:

function createEmployee(name, salary) {


const result = { name, salary }
Object.setPrototypeOf(result, employeePrototype)
return result
}

A prototype is the mechanism in JavaScript that makes it possible to have objects.


Note

In many JavaScript implementations, you can access the prototype of an object as


obj.__proto__. This is not a standard notation, and you should use the
Object.getPrototypeOf and Object.setPrototypeOf methods instead.

Now consider a method call

harry.raiseSalary(5)

When looking up harry.raiseSalary, no match is found in the harry object itself.


Therefore, the property is searched in the prototype. Since harry.[[Prototype]]
has a raiseSalary property, its value is the value of harry.raiseSalary.

As you will see later in this chapter, prototypes can be chained. If the proto-
type doesn’t have a property, its prototype is searched, until the prototype
chain ends.
The prototype lookup mechanism is completely general. Here, we used it to
look up a method, but it works for any property. If a property isn’t found in
an object, then the prototype chain is searched, and the first match is the
property value.

Prototype lookup is a simple concept which it is very important in JavaScript.


Prototypes are used to implement classes and inheritance, and to modify the
behavior of objects after they have been instantiated.

NOTE: Lookup in the prototype chain is only used for reading property
values. If you write to a property, the value is always updated in the
object itself.
For example, suppose you change the harry.raiseSalary method:

harry.raiseSalary = function(rate) { this.salary =


Number.MAX_VALUE }

This adds a new property directly to the harry object. It does not modify
the prototype. All other employees retain the original raiseSalary property.

When nothing is specified when creating a class, the objects inherit from the
Object.prototype prototype. This is a rather complex built-in JavaScript class that
we can use. We don't need to look at how this is implemented in JavaScript, as
we can consider it the base object that is always on top of the inheritance tree and
therefore always present in our objects.
There is a prototype property available on all classes, and it is always named
"prototype." We can access it like this:

Let's give an example of how to add a function to a class using the prototype
property. In order to do so, we'll be using this Person class:

And here is how to add a function to this class using prototype:


prototype is a property holding all the properties and methods of an object. So,
adding a function to prototype is adding a function to the class. You can use
prototype to add properties or methods to an object, like we did in the above
example in our code with the introduce function. You can also do this for properties:

And then you can call them from instances of Person:

It will output:

And it will be as if you had defined the class with a favorite color holding a
default value, and a function, introduce. They have been added to the class and
are available for all instances and future instances.
So the methods and properties defined via prototype are really as if they were
defined in the class. This means that overwriting them for a certain instance doesn't
overwrite them for all instances. For example, if we were to have a second Person
object, this person could overwrite the favoriteColor value and this wouldn't
change the value for our object with firstname as Maria.
This is something you should not be using when you have control over the class
code and you want to change it permanently. In that case, just change the class.
However, you can expand existing objects like this and even expand existing objects
conditionally. It is also important to know that the JavaScript built-in objects have
prototypes and inherit from Object.prototype. However, be sure not to modify this
prototype since it will affect how our JavaScript works.

METHODS

Global methods

The global JavaScript methods can be used without referring to the built-in object
they are part of. This means that we can just use the method name as if it is a
function that has been defined inside the scope we are in, without the "object" in
front of it. For example, instead of writing:
Parsing numbers

parseInt()

With the method parseInt() a string will be changed to an integer.

output :

Making floats with parseFloat()

This will log:

Array methods

You already know how to construct an array with a given sequence of


elements—simply write a literal:

const names = ['Peter', 'Paul', 'Mary']

Here is how to construct an empty array with ten thousand elements, all
initially undefined:
const bigEmptyArray = []
bigEmptyArray.length = 10000

There is a constructor for constructing an array with given


elements that you can invoke with or without new:
numbers = new Array(10000)

The length property is one more than the highest index, converted to a number.

The result is an array of length 10000 and no elements!

you can call Array.from(arrayLike) to place the elements into an array.

const arrayLike = { length: 3 , '0': 'Peter', '1': 'Paul', '2':


'Mary'}

const elements = Array.from(arrayLike)

// elements is the array ['Peter', 'Paul', 'Mary']


// Array.isArray(arrayLike) is false, Array.isArray(elements) is
true

The Array.from method accepts an optional second argument, a function that


is called for all index values from 0 up to length − 1, passing the element (or
undefined for missing elements) and the index. The results of the function are
collected into an array.

For example,

const squares = Array.from({ length: 5 }, (element, index) => index


* index) // [0, 1, 4, 9, 16]

The factory function Array.of doesn’t suffer from the problem of


the Array constructor:

names = Array.of('Peter', 'Paul', 'Mary')


littleArray = Array.of(10000) // An array of length 1, same as
[10000]

But it offers no advantage over array literals either.

The calls

let arr = [0, 1, 4, 9, 16, 25]


const deletedElement = arr.pop() // arr is now [0, 1, 4, 9, 16]
const newLength = arr.push(x) // arr is now [0, 1, 4, 9, 16, x]

delete or add an element at the end of an array, adjusting the length.


NOTE:

Instead of calling pop and push, you could write

arr.length--
arr[arr.length] = x

To delete or add the initial element, call

arr = [0, 1, 4, 9, 16, 25]


const deletedElement = arr.shift() // arr is now [1, 4, 9, 16, 25]
const newLength = arr.unshift(x) // arr is now [x, 1, 4, 9, 16, 25]

The push and unshift methods can add any number of elements at once:

arr = [9]
arr.push(16, 25) // 16, 25 are appended; arr is now [9, 16, 25]
arr.unshift(0, 1, 4) // 0, 1, 4 are prepended; arr is now [0, 1, 4,
9, 16, 25]

Use the splice method to delete or add elements in the middle:

const deletedElements = arr.splice(start, deleteCount, x1,


x2, . . .)

First, deleteCount elements are removed, starting at offset start. Then the
provided elements are inserted at start.

arr = [0, 1, 12, 24, 36]


const start = 2
// Replace arr[start] and arr[start + 1]

arr.splice(start, 2, 16, 25) // arr is now [0, 1, 16, 25, 36]


// Add elements at index start

arr.splice(start, 0, 4, 9) // arr is now [0, 1, 4, 9, 16, 25, 36]


// Delete the elements at index start and start + 1

arr.splice(start, 2) // arr is now [0, 1, 16, 25, 36]


// Delete all elements at index start and beyond
arr.splice(start) // arr is now [0, 1]

If start is negative, it is counted from the end of the array (that is, it is adjusted by adding
arr.length).

arr = [0, 1, 4, 16]


arr.splice(-1, 1, 9) // arr is now [0, 1, 4, 9]
The splice method returns an array of the removed elements.

arr = [1, 4, 9, 16]


const spliced = arr.splice(1, 2) // spliced is [4, 9], arr is [1,
16]
the forEach() method.

It takes the function that needs to be executed for every element as input. Here you can see
an example:

This code snippet will write to the console:


Filtering an array

The filter method takes a function as an argument, and this function should
return a Boolean. If the Boolean has the value true, the element will end up in the
filtered array. If the Boolean has the value false, the element will be left out. You can
see how it works here:

This will log to the console:

Replacing part of an array with another part of the array

The copyWithin() method can be used to replace a part of the array with another
part of the array. In the first example we specify 3 arguments. The first one is the
target position, to which the values get copied. The second one is the start of what
to copy to the target position and the last one is the end of the sequence that will be
copied to the target position; this last index is not included.

arr becomes:

If we specify a range with length 2, the first two elements after the starting position
get overridden:

And now arr becomes:

We can also not specify an end at all; it will take the range to the end of the string:

This will log:

It is important to keep in mind that this function changes the content of the original array, but
will never change the length of the original array.

Mapping the values of an array

This method will return a new array with all the new
values.It is going to execute the function for every element in the
array, so for example:

This is what the console output with the new mapped array looks like:

Using the arrow function, the map() method has created a new array, in which each
of the original array values has been increased by 1.

Finding the last occurrence in an array


We can find occurrences with indexOf() as we have seen already. To find the last
occurrence, we can use the lastIndexOf() method on an array, just as we did for
string.

It will return the index of the last element with that value, if it can find it at all:

This will log 2, because the index 2 holds the last bye variable. What do you think
you'll get when you ask for the last index of something that's not there?

That's right (hopefully)! It's -1.

Converting an array to a string

Template literals are strings that can contain expressions and span multiple
lines. These strings are delimited by backticks (`. . .`). For example,

let destination = 'world' // A regular string


let greeting = `Hello, ${destination.toUpperCase()}!` // A template
literal

The embedded expressions inside ${. . .} are evaluated, converted to a string


if necessary, and spliced into the template. In this case, the result is the string
Hello, WORLD!

You can nest template literals inside the ${. . .} expressions:

greeting = `Hello, ${firstname.length > 0 ? `${firstname[0]}. ` : ''


} ${lastname} `

Any newlines inside the template literal are included in the string. For
example,

greeting = `<div>Hello</div>
<div>${destination}</div>
`
sets greeting to the string '<div>Hello</div>\n<div>World</div>\n' with a
newline after each line.
join() method

With the method you can convert an array to a string. Here is a basic
example:

This will log:

This will use the – instead of the comma. This is the result:

String methods
concat() method.
This does not change the original string(s); it returns the combined result as a string. You will
have to capture the result in a new variable, else it will get lost:

This will log:

Converting a string to an array

split()

With the split() method we can convert a string to an array.


Again, we will have to capture the result; it is not changing the original string. Let's use the
previous result containing Hello JavaScript. We will have to tell the split method on what
string it should split. Every time it encounters that string, it will create a new array item:

This will log:

As you can see, it creates an array of all the elements separated by a space. We can
split by any character, for example a comma:

This will log:


It has now created an array with 3 items. You can split on anything, and the string
you are splitting on is left out of the result.

Working with index and positions

indexOf()

The indexOf() method returns the index, a single number, of the first character of the
substring:

This is logging 7 to the console, because the first occurrence of re is in are, and the re
begins at index 7. When it can't find an index, it will return -1.

search()

An alternative way of searching for a particular substring within a string is to use the
search() method:

This will log 17, because that is the index of lo in fellow. Much like indexOf(), if it
cannot find it, it will return -1.

lastIndexOf() method.

It returns the index where the argument string occurs last. If it cannot find it, it returns -1.
Here is an example:

This returns 24; this is the last time re appears in our poem. It is the second are.

charAt(index)

if you want to know what character is at a certain index position.


This is logging r, because the character at index 10 is the r of red.
If you are asking for the position of an index that is out of the range of the string, it will return
an empty string, as is happening in this example:

Creating substrings

slice(start, end)

This does not alter the original string, but returns a new string with the substring.
It takes two parameters,the first is the index at which it starts and the second is the end
index. If you leave out the second index it will just continue until the end of the string from
the start. The end index is not included in the substring. Here is an example:

This will log:

The first one only has one argument, so it starts at index 5 (which holds an e) and
grabs the rest of the string from there. The second one has two arguments, 0 and 3. C
is at index 0 and a is at index 3. Since the last index is not included in the substring,
it will only return Cre.

Replacing parts of the string

the replace(old, new) method

It takes two arguments, one string to look for in the string and one new
value to replace the old value with. Here is an example:

This will log to the console Hi Pascal. If you don't capture the result, it is gone,
because the original string will not get changed.
changed. If the string you are targeting doesn't appear in the original string, the replacement
doesn't take place and the original string will be returned:
the replaceAll() method.

If we wanted to replace all the occurences, we could use the


replaceAll() method. This will replace all occurrences with the specified new string,
like this:

This logs oh oh.


Uppercase and lowercase

the toUpperCase() and toLowerCase()

We can change the letters of a string with the toUpperCase() and toLowerCase()
built-in methods on string. Again, this is not changing the original string, so we'll
have to capture the result:

This logs:

It converts all the letters to uppercase. We can do the opposite with toLowerCase():

This will log:

Let's make it a bit more complicated and say that we'd like the first letter of the
sentence to be capitalized. We can do this by combining some of the methods we
have seen already right now:

We are chaining the methods here; we first grab the first character of fixed_caps
with charAt(0) and then make it uppercase by calling toUpperCase() on it. We then
need the rest of the string and we get it by concatenating slice(1).

The start and end of a string

startsWith()

want to check what a string starts with

This will log true to the console, because the sentence starts with You. Careful here,
because it is case sensitive.

endswith( )

we can do the same thing for checking whether a string ends with a certain string. You can
see it in action here:

Since it doesn't end with Something else, it will return false.

Number methods

isNaN() method

Checking if something is (not) a number

This will log to the console:


isInteger( ) method

Checking if something is an integer

This will log:

Since the only integer in the list is x.

the toFixed() method.


We can specify the number of decimals here. It doesn't change the original value, so we'll
have to store the result:

This will only leave two decimals, so the value of newX will be 1.23.

There is also a method to specify precision. Again this is different from the rounding
methods in the Math class, since we can specify the total number of numbers to look
at. This comes down to JavaScript looking at the total number of numbers. It is also
counting the ones before the dot:

So the value of newX will be 1.2 here. And also here, it is rounding the numbers:
This will log 1.235.

Math methods

the max() method

to find the highest number among the arguments. It logs 233, because that's the highest
number.

Math.min ( )
In a similar way, we can find the lowest number:

This will log 1, because that is the lowest number.

Square root and raising to the power of

the sqrt() method

The method sqrt() is used to calculate the square root of a certain number.

This will log 8, because the square root of 64 is 8.

the pow(base, exponent) method

In order to raise a number to a certain power


We are raising 5 to the power of 3 here (53), so the result will be 125, which is the

result of 5*5*5.

Turning decimals into integers

There are different ways to turn decimals into integers.

the round() method:


the round method rounds to the closest integer

This will log:

ceil() method

The ceil() method is always rounding up to the first integer it encounters.

This will log:

The floor() method

The floor() method is doing the exact opposite of the ceil() method. It rounds
down to the nearest integer number, as you can see here:

this will log :

the trunc ( ) method

And then one last method, trunc(). This gives the exact same result as floor() for
positive numbers, but it gets to these results differently. It is not rounding down, it is
simply only returning the integer part:

This will log:

When we use negative numbers for trunc() we can see the difference:

Creating dates

There are different ways to create a date. One way to create dates is by using the
different constructors. You can see some examples here:

This will log the current date and time, in this case:
But, this way we are not using the built-in method, but the constructor. There is a
built-in method, now(), that returns the current date and time, similar to what the no
argument constructor does:

Methods to get and set the elements of a date

This will log right now:

Converting a date to a string

We can also convert dates back to strings. For example with these methods:

This will log the day in written format:

This is another method that converts it differently:


It will log:

PROMISES

We first create a Promise. When creating a Promise, we don't know what the value
of the Promise is going to be. This value is whatever is sent as an argument to the
resolve function. It is a sort of placeholder.
So when we call then on the Promise, we basically say: figure out what the value
of the Promise is, and when you know, execute one function if the Promise was
resolved or a different function if it was rejected. When a Promise is neither resolved
nor rejected, we say that the Promise is pending.
then() is a Promise itself, so when it returns we can use the result for the next then()
instance. This means we can chain the then() instances, which can look like this:
The resolve functions are implemented with an arrow function. The return statement
is the value input for the next function. You can see that the last block is a catch()
function. If any of the functions were to result in a rejection and the Promise were
therefore rejected, this catch() block would be executed and print whatever the
reject() function sent to the catch() method. For example:
This will just log oops... because the first Promise was rejected instead of resolved.
This is great for creating asynchronous processes that need to wait till another
process is complete. We can try to do a certain set of actions

async and await

You have just seen how to build pipelines of promises with the then and catch
methods, and how to execute a sequence of promises concurrently with
Promise.all and Promise.any. However, this programming style is not very conve-
nient. Instead of using familiar statement sequences and control flow, you
need to set up a pipeline with method calls.

The await/async syntax makes working with promises much more natural.
The expression

let value = await promise

waits for the promise to settle and yields its value.


But wait. . .didn’t we learn at the beginning of this chapter that it is a terrible
idea to keep waiting in a JavaScript function? Indeed it is, and you cannot
use await in a normal function. The await operator can only occur in a function
that is tagged with the async keyword:

const putImage = async (url, element) => {


const img = await loadImage(url)
element.appendChild(img)
}

The compiler transforms the code of an async function so that any steps that
occur after an await operator are executed when the promise resolves. For
example, the putImage function is equivalent to:

const putImage = (url, element) => {


loadImage(url)
.then(img => element.appendChild(img))
}

Multiple await are OK:

const putTwoImages = async (url1, url2, element) => {


const img1 = await loadImage(url1)
element.appendChild(img1)
const img2 = await loadImage(url2)
element.appendChild(img2)
}

Loops are OK too:

const putImages = async (urls, element) => {


for (url of urls) {
const img = await loadImage(url)
element.appendChild(img)
}
}

As you can see from these examples, the rewriting that the compiler does
behind the scenes is not trivial.
If you forget the await keyword when calling an async function,
the function is called and returns a promise, but the promise just sits
there and does nothing. Consider this scenario, adapted from one of
many confused blogs:

const putImages = async (urls, element) => {


for (url of urls)
putImage(url, element) // Error—no await for async putImage
}

This function produces and forgets a number of Promise objects, then


returns a Promise.resolve(undefined). If all goes well, the images will be
appended in some order. But if an exception occurs, nobody will catch it.

You can apply the async keyword to the following:

• Arrow functions:
async url => { . . . }
async (url, params) => { . . . }

• Methods:

class ImageLoader {
async load(url) { . . . }
}

• Named and anonymous functions:

async function loadImage(url) { . . . }


async function(url) { . . . }

• Object literal methods:

obj = {
async loadImage(url) { . . . },
. . .
}

Accessing elements by the dom


If we want to select the element with an ID of two right away, we could use:

This would return the full HTML element:

Accessing elements by tag name

It will give back:

We can access them using the item() method to access them by index, like this:

This will return:

We can also access them by name, using the namedItem() method, like this:

And this will return:


When there is only one match, it will still return an HTMLCollection. There is only
one h1 tag, so let's demonstrate this behavior:

Since h1 doesn't have an ID or class, it is only h1. And since it doesn't have an ID, it
is not a namedItem and is only in there once.

Using querySelector()

This first option will select the first element that matches the query. So, enter the
following in the console, still using the HTML snippet introduced at the start of the
section:

It should return:

It only returns the first div, because that's the first one it encounters. We could also
ask for an element with the class .something. If you recall, we select classes using dot
notation like this:

This returns:

Using querySelectorAll()

Sometimes it is not enough to return only the first instance, but you want to select all
the elements that match the query. For example when you need to get all the input
boxes and empty them. This can be done with querySelectorAll():
This returns:

As you can see, it is of object type NodeList. It contains all the nodes that match the
CSS selector. With the item() method we can get them by index, just as we did for
the HTMLCollection.

innerHTML property.
to modify the content of an HTML element

changing html attributes

changing style properties


adding html elements
The appendChild() method in the previous example, appended the new element as the last
child of the parent. If you don't want that you can use the insertBefore() method:
removing elements

To replace an element, use the replaceChild() method:


Events

To achieve this we have to add an event listener that fires when a user causes any event
e.g. clicks a button
You can also remove event handlers that have been attached with the addEventListener()
method:

Adding classes to elements

This might sound a bit vague, so let's have a look at an example where we are going
to add a class to an element, which in this case will add a layout and make the
element disappear.

classList.add

removing classes from elements

classList.remove()
Toggling classes
In some cases, you would want to add a class when it doesn't already have that
particular class, but remove it when it does. This is called toggling. There is a special
method to toggle classes. Let's change our first example to toggle the hide class so the
class will appear when we press the button the second time, disappear the third time,
and so on. The blue class was removed to make it shorter; it's not doing anything in
this example other than making the square blue.

Manipulating attributes

The attributes in this example are id, class, and href. Other common attributes are
src and style, but there are many others out there.
You can do this from the console and
see the result easily, or write another HTML file with this built in as a function. In
this HTML snippet, you will see it in action:

Creating new elements

Accessing and setting the Dom

You might also like