JS, from nothing to something
Variables
var, let, const. var isn't used any more.
let myVariableName = "Hi";
myVariableName = "let variables can be reasigned";
// const variables don't change values after assignment
const myOtherVariable = "const variables con NOT be reassigned";
// Uppercase constants
// Widespread practice to make them uppercase when constants
// are 'hard-coded', calculated constant should be lowercase
const POST_ENDPOINT = "https://myapi/com/post";
const COMMENTS_ENDPOINT = "https://myapi/com/comments";
const COLOR_BLUE = "#00f";
const myAge = calculateAge('01/01/1991');
Data Types
number:
let age = 1;
bigint:
let bigNumber = 12345n;
string:
let userName = "User Name";
boolean:
let userIsCool = true; // `false` is the other value possible
null:
let nothingHere = null; // means nothing, empty
undefined:
let notAssigned;
// console.log(notAssigned) prints `undefined`
// means `value not assigned`
object:
let userIndo: {
name: "User Name",
lastName: "User Last Name"
}
symbol
Rarely used.
Note: You can print what type of Data type
variable is with typeof myVariable // "string"
or typeof(myVariable)
Interaction
- alert:
alert("Hi")
simple message to user in a modal way - prompt:
let age = prompt("How old are you", 1)
a modal with question, second parameter, in this case number 1, is optional and it will autofill input with that value, let age will store data user wrote down. - confirm:
let isOk = confirm("Is it okay to show you this modal")
modal with Ok and cancel buttons, isOk will store true if Ok is pressed or false otherwise.
Type Conversions
To String String()
let value = true;
value = String(value); // "true", if null = "null" etc
To Number Number()
let value = "123";
value = Number(value) // 123;
Number("123z"); // NaN, undefined = NaN
Number(true); // 1, false or null = 0
To Boolean Boolean()
Boolean(1); // true
Boolean(0); // false
Boolean(""); // false
Boolean("0"); // true, "string not empty" = true
Operators
- Addition +
- Subtraction -
- Multiplication *
- Division /
- Remainder %
- Exponentiation **
Remainder %
The result of a % b
is the remainder of the division a by b
5 % 2; // 1
8 % 3; // 2
Exponentiation **
2 ** 2; // 2² = 4
2 ** 3; // 2³ = 8
2 ** 4; // 2⁴ = 16
String concatenation with +
"my" + "string"; // "mystring"
"1" + 2; // "12"
2 + "1"; // "21"
// this is because it works from left to right, it does the math
// with two numbs like 2 + 2 and later adds the 1 string
2 + 2 + "1"; // "41" and not "221"
// The 2 gets concatenated to '1', so it’s like '1' + 2 = "12"
// and "12" + 2 = "122".
"1" + 2 + 2); // "122" and not "14"
/*
* so, sum `+` is the only one that works that way
* other arithmetic operators work only with numbers
* and always convert their operands to numbers.
*/
6 - "2"; // 4, converts '2' to a number
"6" / "2"; // 3, converts both operands to numbers
Chaining assignmets
let a, b, c;
a = b = c = 2 + 2; // a = 4, b = 4, c = 4
Modify in place
let n = 2;
n = n + 5; // n = 7
n += 2; // n = 9
n *= 2 + 2; // n = 36 (9*4)
Increment.decrement
let n = 2;
n++; // n = 3
n--; // n = 2 (suppusing it was 3 before)
you can plase operators ++
and --
where you want, before of after variable, but there are diference in returning values since JS works from left to right.
let n = 1;
let m = ++n; // m = 2 (it increments first n and return new n value)
let n = 1;
let m = n++; // m = 1 (it returns n first (1) to m, and increments later, so (n = 2))
let n = 1;
let m = 2 * ++n; // m = 4
let n = 1;
let m = 2 * n++; // m = 2
Comparison
Greater/lest than
a > b
, a < b
Greater/less than or equals
a >= b
, a <= b
Equals/not equals
a === b
, a !== b
Result of a comparison is always a boolean, true
or false
Functions
Function Declaration
function helloWorld (param) {}
helloWorld("My Name");
Function Expression
// The name of the function after = is optional
const myFunction = function myOptionalName(param) {}
myFunction("Parameter");
// Anonymous function
const myOtherFunc = function() {}
const arrowFunc = (param) => {}
arrowFunc("Param");
IIFE (Immediately Invoked Function Expression)
(function () {
let num = 1;
return num;
})()
// 1
Objects
Objects Properties
let customPropertie = 'customObjectProperieName';
let person = {
name: 'Jonny',
age: 28,
partTime: false,
[customPropertie]: 'Custom Value'
}
person.parTime = true;
person['age'] = 0;
person.name; // Jonny
person.parTime; // true
person['age']; // 0
person['customObjectProperieName']; // Custom Value
Objects Methods Attaching functions to objects
let person = {
name: "Jonny",
showName: function (age) {
console.log(`${this.name} is ${age}`);
},
};
person.showName(28); // Jonny is 28
Passing Objects to Functions A function can edit an object property since we are passing the reference of the object
let person = {
age: 27,
};
const incrementAge = (person) => {
person.age++;
};
incrementAge(person);
person.age; // 28
Built-in Objects JS has many built-in object that developers use every day, to modify string (eg: string.startsWith("abc"), string.endsWith("abc"), string.includes("abc")
etc), to do maths, work with numbers (eg: Number.isInteger(123)
) or to get dates, etc. so, you can check the list here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
Document Object Model (DOM) You can check more about this object on: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model
// Get element by ID and change text content
document.getElementById("message").textContent = "New Message";
// Style it
const header = document.getElementById("header");
header.style.color = "#FFF"; // change color to white
header.style.fontWeight = "800"; // font weight bold
// Listener, click
const button = document.getElementById("read-more");
button.addEventListener("click", function () {
const banner = document.getElementById("banner");
// Check if element has class
if (banner.classList.contains("d-none")) {
// Remove class from element
banner.classList.remove("d-none");
} else {
// Add class to element
banner.classList.add("d-none");
}
});
Arrays
Create and initializing arrays
// Create an Array
let values = [];
// Create an Initializing
let moreValues = [1, 2, 3];
// Array.of
let otherValues = Array.of('a', 'b', 'c'); // ['a', 'b', 'c']
// An Array is an object in js
typeof otherValues; // object
// Check if variable is an array
Array.isArray(values); // true
one can find more about arrays in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
Accessing Array Items
let values = ['a', 'b', 'c'];
values[0]; // a
values[1]; //.b
values[2]; // c
values[3]; // undefined
// Edit value
values[0] = 'aaa';
values[0]; // aaa
Manipulating Arrays
// push(), Add item at the end
let values = ['a', 'b', 'c'];
values.push('d'); // you can push more than one value, for example values.push('d', 'e', 'f');
values; // a,b,c,d
// pop(), get latest but removes it from array
const last = values.pop();
last; // d
values; // a, b, c
// shift(), get first and removes it from array
const first = values.shift();
first; // a
values; // b, c
// unshift(), add Item to the beginning of the array
values.unshift('a'); // you can add more thant one, values.unshift('hello', 'world');
values; // a, b, c
// slice(), Creates a new array from another
const values2 = ['a', 'b', 'c'];
const newValues = values2.slice(1, 2); // first argument, where we want to start ('b') and second argument, were we want to finish ('c');
newValues; // b
// slice() without arguments
const newValues2 = values2.slide();
newValues2; // a, b, c
// splice(), delete items from array
values2.splice(1, 1); // first argument, index where we start, second argument, number of items we want to delete
values2; // a, c
// splice to insert item
values2.splice(1, 0, 'foo'); // starts in index 1, deletes 0 elements, inserts foo
values2; // since values 2 was [a,c], then, values2 = a, foo, c
Array Searching and Looping
// indexOf, search index of item in array
const values = ['a', 'b', 'c'];
values.indexOf('c'); // 2
values.indexOf('d'); // -1, when one element is not in array, we don't get undefined, we get -1 instead;
// filter(), create an array with filter condition
const newValues = ['a', 'bbb', 'c'];
const found = newValues.find(item => item.length > 1);
found; // bbb
// forEach, you can also use a for or a while to iterate over a loop
values.forEach((item) => {
console.log(item); // a, - b, - c
});
Scope & Hoisting
Global Scope
A variable, function etc writted outside a function becomes global
and you can access its value inside any function after it.
let id = 12345;
function showId() {
console.log(productId); // 12345
}
showId();
Function Scope A variable inside a function, is only accessible inside it
function showId() {
let id = 12345;
function inside() {
let id = 67890;
console.log(id); // 67890; however if we delete `let id = 67890;` above
// then this id will print 12345 since it will look for variable in the upper scope
}
inside();
console.log(id); // 12345
}
showId();
console.log(id); // ERROR, ReferenceError: id is not defined
Hoisting
You can NOT access a variable before is declared using let
or const
, you can with var
but since var is not used anymore, I'm omitting anything related to that.
console.log(myConstant); // ERROR: ReferenceError: myConstant is not defined
const myConstant = 12345;
HOWEVER, you CAN access a function before is declared, this is called Hoisting
Hoisting: Hoisting is JavaScript's default behavior of moving all declarations to the top of the current scope (to the top of the current script or the current function).
myFunction();
function myFunction() {
console.log(12345); // 12345
}
so, in this case function myFunction()
declaration will be moved at the top, before myFunction()
call.
All about the switch
Switch is recommended when more than two if
conditional are required.
switch(<expression>) {
case <expression 1>:
// statement(s)
break; // exist out of switch
case <expression 2>:
case <expression 3>:
case <expression 4>:
// statement(s)
break;
default: // if no other case is matched
// statement(s)
break;
}
Example
const productId = 2;
switch (productId) {
case 1:
console.log("Product 1");
break;
case 2:
console.log("Product 2"); // this is printed
break;
default:
console.log("Unknown product");
break;
}
Multiple Case Statements
const color = "Blue";
switch (color) {
case "White":
console.log("Color white");
break;
case "Red":
case "Blue":
console.log("Color Blue or Red"); // this is printed
break;
default:
console.log("Unknown Color");
break;
}
Note:
- Don't forget break, if you forget break, it will execute case 1, case 2, case 3 etc until there is a break.
- Switch use stric mode to check condition, if your condition is "2" as string, and your cases are
case 2
as number, it wouldn't work
Block-level Scope In a switch, the swtich itself is a block, but the case aren't, let's see an example:
const productId = 2;
switch (productId) {
case 1:
let message = "My First Message";
console.log(message);
break;
case 2:
let message = "My second Message";
console.log(message);
break;
default:
console.log("Unknown product");
break;
}
this will break and it will say message is already declared
because cases aren't blocks, to make them block, you can use {}
in cases:
const productId = 2;
switch (productId) {
case 1: {
let message = "My First Message";
console.log(message);
break;
}
case 2: {
let message = "My second Message";
...
The difference Between for/in and for/of
for/in
- Iterates over elements of an object(properties and methods)
- Returns key (property/method) name
- object[key] returns value
let user = {
"name": "Jonny",
"age": 28,
"calculateAgeIn100Years": function(){
return this.age * 100;
}
}
//for in loop
for (const key in user) {
console.log(`\'${key}\'= ${user[key]}`);
}
// Result console log
/*
'name'= Jonny
'age'= 28
'calculateAgeIn100Years'= function () {
return this.age * 100;
}
*/
for/of
- Iterates over values in array, string, etc
- Returns object for each iterarion
// Array
let array = [
"string item",
12345,
{
property1: "String",
property1: 123,
},
];
// for of
for (const item of array) {
console.log(item);
}
// Result
/*
new one
12345
{ property1: 123 }
*/
// String
let string = "my text";
// for of
for (const char of string) {
console.log(char);
}
// Result
/*
m
y
t
e
x
t
*/
Break and Continue Break: Leave a loop early
Continue: Next iteration of a loop
// Break
const products = [
{
price: 20,
},
{
price: 30,
},
{
price: 40,
},
];
for (const product of products) {
if (product.price >= 30) {
break;
}
console.log(product);
}
/*
{ price: 20 } // only print this since loop breaked
*/
// Continue
for (const product of products) {
if (product.price === 30) {
continue;
}
console.log(product);
}
/*
// Doesn't print 30 since conditional says that when equal 30 continue and don't
// do the rest of things in loop
{ price: 20 }
{ price: 40 }
*/
Note: Labeled statements
aren't recommended to use anymore to avoid spaghetti code, so, it is not mentioned here
Working with logical operators and short-circuit evaluation
Truthy and Falsy
- Truthy: Any variable with a value ("String", 10, true) is
true
- empty arrays
[]
or objects{}
are truthy too, in that case we have to check in other way if they are empty or not
- empty arrays
- Falsy: Any variable (false, null, undefined, Nan, 0, '') is
false
Logical Operators
let price = 20;
// AND (&&) operator
if (price > 10 && price < 30) {
console.log("true");
}
// OR (||) operator
if (price < 10 || price < 30) {
// First conditional is not true BUT
// second one is and the `or` will enter here
console.log("true");
}
// NOT(!) operator
if( !(price < 10)){
// it entes here, since price is NOT less than 10
console.log("true");
}
Short Circuiting
const isColorRed = (color) => color === "Red";
const isGreaterThan100 = (num) => num > 100;
let result;
// if first is false, the second part is never evaluated
result = isColorRed("Black") && isGreaterThan100(101);
console.log(result); // false
// Each expression is evaluated until one returns true
// the rest are then skipped
result = isColorRed("Red") || isGreaterThan100(101);
console.log(result);
Exception Handling
Always add try...catch around 'dangerous' code
try {
// Some code that could fail
} catch (error) {
// Do something with the error
} finally {
// This code always runs
}
Example:
function simpleTryCatch() {
let result;
try {
console.log("Before error");
result = x / 10;
// after an error, anything else is not run/executed
console.log("This line will not be printed");
} catch (error) {
console.log(error.message);
} finally {
// this always run, not matter if it is successfully or on error
console.log("In the final block");
}
}
simpleTryCatch();
//Before Error
// x is not defined
// In the final block
Throw
- Can throw your own custom error
- Create an object with at least two properties: "message" and "name"
function attemptDivision() {
let result;
try {
result = x / 10;
} catch (error) {
throw {
message: `In the attemptDivision() method the following error occurred: ${error.message}`,
name: "Custom error",
};
}
}
attemptDivision(); // Custom error: In the attemptDivision() method the following error occurred: x is not defined
Detect the Error Type
function checkErrorType() {
let result = 0;
try {
// Reference error because 'x' is not defined
result = x / 10;
// Range error because a number cannot have 200 significant digits
result.toPrecision(200);
// Type error because result is a numeric
result.toUpperCase();
// URI error
let uri = "https://google.com/path%%%/file name";
decodeURI(uri);
// Syntax error because missing a final single quote
let sum = eval("alert('Hello)");
} catch (error) {
handleError(error);
}
}
function handleError(error) {
switch (error.name) {
case "ReferenceError":
console.log("Reference error: " + error.message);
break;
case "RangeError":
console.log("Range error: " + error.message);
break;
case "TypeError":
console.log("Type error: " + error.message);
break;
case "URIError":
console.log("URI error: " + error.message);
break;
case "SyntaxError":
console.log("Syntax error: " + error.message);
break;
case "EvalError":
console.log("Evaluation error: " + error.message);
break;
default:
console.log("Error Type: " + error.name + " - Message: " + error.message);
break;
}
}
checkErrorType();
How to determine variable data types
Primitive Data Types
Bolean
: true or false
null
: no value
undefined
:a varialbe declared, but has no value
number
: integers, decimals, float, etc
string
: a series (array) of characters
Evrything in JS inherits from object data type except the primitives above
Object Data Types
new Array
: A collection of values
new Error
: Contains a name and an error message
new Function
: A block of code
new Object
: A wrapper around any type
new RegExp
: A regular expression
Use primitives boolean
, number
or string
instead of these when possible since these take more memory space and are slower to access
new Boolean
: An object that contains true or false
new Number
: An object that contains numberic value
new String
: An object that contains a character(s)
typeof/constructor/instanceof
To get to know what kind of variable is, we use typeof <variable>
const hi = "my string";
const newDate = new Date();
console.log(typeof hi); // string
console.log(typeof newDate); // object
// Constructor
console.log(hi.constructor.toString()); // function String() { [native code] }
console.log(newDate.constructor.toString()); // function Date() { [native code] }
// instanceof
// this only check for object data types
console.log(hi instanceof String); // false, since strin was declared as primitive
// data type, if we declared it like new String("Hi") it will fire true
console.log(newDate instanceof Date);// true
Understanding 'this' in Javascript
'this' keyword is often used in many object-oriented propgraming languages
- Refers to an object
- That object is typcally in which the current code is running
- Sometimes the object can be changed
Diferent value based on execution context:
- In a method: owner object
- In a function: global object
- In an event: element that received that event
- call()/apply methos refet to object passed in
Global window object:
// Javascript runs within the global window object availiable in every browser
<script>
console.log(this.toString()); // [object Window], this = global window object
console.log((this === window).toString()); // true
// that is not a good convention, and using 'use strict' it will make this undefined
// better use `window` eg: (window.toString()) for example to get global window object
</script>
Object literal:
const person = {
name: "Jonny",
fullName: function () {
console.log(this.name); // Jonny, this = person object literal
},
};
person.fullName();
Constructor function:
function Person(first, last) {
this.firstName = first;
this.lastName = last;
this.fullName = function () {
console.log(this.firstName); // this = current Person Object
console.log(this.lastName);
};
}
const person1 = new Person("Jonny", "Acevedo");
person1.fullName(); // Jonny, Acevedo
'this' in Event Handlers 'this' in the context of this event refers to the html element that it's attached to.
<button onclick="eventHandler(this)">
Pass this to function handler
</button>
<script>
function eventHandler(ctl){
console.log(ctl.toString()); // [object HTMLButtonElement]
}
</script>
Spread Operator
- Expand any 'iterable' sich as a string or array into and array
- For passing multiple arguments to method
- The syntax uses the ellipsis symobl
...
- Always o nthe right-side of an equal sign
String to array
const productSKU = "ABC-12345-67";
const values = [...productSKU];
console.log(values); // [ 'A', 'B', 'C', '-', '1', '2', '3', '4', '5', '-', '6', '7' ]
Copy Array
const arr = [1, 2, 3];
const arr2 = [...arr];
arr2.push(4);
arr2[0] = 90;
console.log(arr); // [ 1, 2, 3 ]
console.log(arr2); // [ 90, 2, 3, 4 ]
Copying and array with object inside it, the spread operator will NOT copy the objects on it by value, it will only copy by reference, so, if you change an object property in the new array IT WILL CHANGE in the old one
const product = [
{
price: 1234,
},
];
const newProduct = [...product];
newProduct[0].price = 1000;
console.log(product[0].price); // 1000
console.log(newProduct[0].price); // 1000
Concatenate two arrays
const IDs1 = [1, 2, 3, 4];
const IDs2 = [5, 6, 7, 8];
const allIds = [...IDs1, ...IDs2]; // [ 1, 2, 3, 4, 5, 6, 7, 8 ]
Using Spread to pass parameters to a constructor or to a function
// constructor
const dt = new Date(2021, 07, 21); // 2021-08-21T
const dataFields = [2021, 07, 21];
const newDt = new Date(...dataFields); // 2021-08-21T
// function
const myFunction = (arg1, arg2, arg3) => {
console.log(arg1); // 2021
console.log(arg2); // 08
console.log(arg3); // 21
};
myFunction(...dataFields);
Shallow copy on object literals
it is very similar to the the javascript object.assign
method, so it does copy property by property from one object to the other
const product = {
price: 1245,
};
const newProduct = { ...product };
newProduct.price = 1000;
console.log(product); // { price: 1245 }
console.log(newProduct); // { price: 1000 }
Using Variables Literals and Assignments
const name = "User's Name";
// ONE LINE TEMPLATE LITERAL
const helloText = `My Hello text ${name} `; // My Hello text User's Name
// MULTIPLE LINES
const multipleLines = `My First Line ${name}
${helloText}
Third Line
`;
// My First Line User's Name
// My Hello text User's Name
// Third Line
Create a tagged Template Literal Adding bold to the values tags inside a template literal:
const name = "User's Name";
const helloText = myTaggedTemplateLiteral`My Hello text ${name}`;
// My Hello text <b>User's Name</b>
function myTaggedTemplateLiteral(strings, ...values) {
let str = "";
for (let i = 0; i < strings.length; i++) {
if (i > 0) {
str += `<b>${values[i - 1]}</b>`;
}
str += strings[i];
}
return str;
}
String.raw
So, template literals don't render backslashes\
for example, so, to do so, you can use String.raw
const newTemplate = `text \ text`; // text text
//String.raw
const anotherTemplate = String.raw`text \ text`; // text \ text
Destructing Arrays and Objects
This allows to unpack and get values from arrays and objects very simple
Array destructuring
const numbers = [1, , 3, 4, 5, 6];
const [number1, number2 = 2, number3, ...moreNumbers] = numbers;
console.log(number1); // 1
console.log(number2); // 2 -> Here, in the array position, it's empty, so, with `number2 = 2` we defined an default value of 2
console.log(number3); // 3
console.log(moreNumbers); // [ 4, 5, 6 ]
Object destructuring
const me = {
name: "Jonny",
lastName: "Acevedo",
skills: ["JS", "React", "Flutter"],
age: 28,
city: "Medellin",
};
const {
name,
lastName,
skills,
undefinedProperty = "Default Value",
...moreProperties
} = me;
console.log(name); // Jonny
console.log(lastName); // Acevedo
console.log(skills); // [ 'JS', 'React', 'Flutter' ]
console.log(undefinedProperty); // Default Value
console.log(moreProperties); // { age: 28, city: 'Medellin' }