Study

JavaScript Tutorial

Credits / Notes taken from:

Contents

Where can I run JavaScript code?

  1. Download a code editor (Sublime, VSCode, Brackets, Atom, Notepad++, WebStorm, etc), create file index.html, open it in browser (Chrome), and press CTRL+SHIFT+J to open the console:
    <!-- index.html -->
    <script>
     console.log("hello, world");
    </script>
    
  2. Download and install Node.js, install + open Sublime Text, go to Tools->Build System->New build system, paste this this and save it as nodejs.sublime-build:
    {
      "cmd": ["C:/Program Files/nodejs/node.exe", "$file"],
      "selector": "source.js"
    }
    

    Select Tools->Build System->nodejs and now you can run your .js file inside SublimeText by pressing CTRL+B

  3. Use Codepen.io, Create->Pen->JS Windows.

  4. Use Scrimba.com, Create account, Log in, press + button, select javascript template and playground.

  5. Use Stackblitz, Create account, Log in, Create new project in JavaScript.

  6. Install + Open Visual Studio Code and install Live Server Extension.

Declaring variables with var, let, const

ES2015 introduced two important new JavaScript keywords: let and const, before that only var was availale to use.

Variable names that starts with $ or _

JavaScript treats $ and _ as if they were letters of the alphabet, so identifiers containing $ are valid variable names.
Now multiple libraries are providing their own version of the $() function, so many now provide the option to turn off that definition in order to avoid clashes. Using the dollar sign is not very common in JavaScript, but professional programmers often use it as an alias for the main function in a JavaScript library. In the JavaScript library jQuery, for instance, the main function $ is used to select HTML elements. In jQuery $("p"); means “select all p elements”.

Of course, you don’t need to use a library to be able to use $(). All you need to substitute $() for document.getElementById() is to add a definition of the $() function to your code as follows:

function $(x) {return document.getElementById(x);}
$("demo").innerHTML = "My First JavaScript";

// instead of
// document.getElementById("demo").innerHTML = "My First JavaScript";

And the HTML part:

<body>
    <p id="demo"></p>
</body>

Since JavaScript treats underscore as a letter, identifiers containing _ are valid variable names. Using the underscore is not very common in JavaScript, but a convention among professional programmers is to use it as an alias for “private (hidden)” variables (objects or methods). This is a quick and easy way to immediately identify a private class member, and it is so widely used, that almost every programmer will recognize it.

Note that again, as with $, the use of _ is merely a convention and is not enforced by JavaScript itself.

JS Data Types and Operators

JavaScript has dynamic types. This means that the same variable can be used to hold different data types.

var x;           // Now x is undefined
x = 5;           // Now x is a Number
x = "John";      // Now x is a String
  1. Strings
var str1 = "It's a string";   // Using double quotes
var str2 = 'Hello "Anne"';   // Using single quotes
let phrase = `can embed another ${str1} using $`;

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 ${…}.

let name = "John";
alert( `Hello, ${name}!` ); // Hello, John!
alert( `the result is ${1 + 2}` ); // the result is 3
  1. Numbers (There’s only one data type for numbers: float)
var x1 = 34.00;     // float with decimals
var x2 = 34;        // float without decimals
var y = 123e5;      // 12300000
var z = 123e-5;     // 0.00123
  1. BigInt in JavaScript, the “number” type cannot represent integer values larger than 2^53-1 (that’s 9007199254740991), or less than -2^53-1 for negatives.
// the "n" at the end means it's a BigInt
const bigInt = 1234567890123456789012345678901234567890n;
  1. Booleans: true or false (not capitalized)
let nameFieldChecked = true; // yes, name field is checked
let ageFieldChecked = false; // no, age field is not checked
let isGreater = 4 > 1;
  1. null value. More info here

  2. undefined value More info here

  3. Arrays and Arrays methods JavaScript arrays are written with square brackets. Array items are separated by commas.

var cars = ["Saab", "Volvo", 23];
var myNestedArray = [["universe", 42], ["everything", 7.2]]
  1. symbol 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.

  2. JavaScript Objects JavaScript objects are written with curly braces {}. Object properties are written as name:value pairs, separated by commas.

var personObj = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};
// The object (person) in the example above has 4 properties: firstName, lastName, age, and eyeColor.

// Check if object has a specific property
personObj.hasOwnProperty("age"); // true
personObj.hasOwnProperty("address"); // false
  1. typeoff operator More info here You can use the JavaScript typeof operator to find the type of a JavaScript variable. 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.
typeof undefined // "undefined"
typeof 0 // "number"
typeof 10n // "bigint"
typeof true // "boolean"
typeof "foo" // "string"
typeof Symbol("id") // "symbol"

typeof {name:'John', age:34} // "object"
typeof Math // "object"  (1)
typeof null // "object"  (2) 
// Unfortunately, in JavaScript, the data type of null is an object

typeof alert // "function"  (3)
typeof function myFunc(){}   // "function"

typeof typeof 123 // "string"
typeof NaN // "number"
typeof [1,2,3] // "object"
// In JavaScript, arrays are technically objects; just with special behaviours and abilities
typeof class Foo {} // "function"

Before Classes, to make an inheritable object, we would have to use a function

function Dog() { }
Dog.prototype.bark = function() {
    alert("woof!");
}
const snoopy = new Dog();
snoopy.bark() // alert("woof!")

With Classes, we can create the same object this way

class Dog {
    bark() {
        alert("woof!");
    }
}
const snoopy = new Dog();
snoopy.bark() // alert("woof!")


Check data types in JS

/* Undefined */
typeof undefined === 'undefined'; // true
typeof declaredButUndefinedVariable === 'undefined'; // true
typeof undeclaredVariable === 'undefined'; // true

/* Numbers */
typeof 4.42 // 'number'
typeof 5 === "number" // true
typeof(42) === 'number' // true
typeof Infinity === 'number' // true
typeof NaN === 'number'; // true, despite being "Not-A-Number"

/* Strings */
typeof 'Hello' // 'string'
typeof 'Hello' === 'string' // true
typeof '' === 'string' // true
typeof '1' === 'string'; // true, note that a number within a string is still typeof string
typeof String(1) === 'string'; // true, String converts anything into a string, safer than toString

/* Booleans */
typeof true // "boolean"
typeof false === "boolean" // true
typeof Boolean(1) === 'boolean'; // Boolean() will convert values based on if they're truthy or falsy
typeof !!(1) === 'boolean'; // two calls of the ! (logical NOT) operator are equivalent to Boolean()
typeof null === 'object' // true

More examples here.

JS Operators + - * ** / % ++ -- and Comparisons

x = 10 + 5;// x = 10
x = 5 + '5'; // x = 55
x = '5' + 6 + 7; // x = 567
x = 5 + 6 + '7'; // x = 117
x = 5 + '6' + 7; // x = 567 
x = 10 - 5; // x = 5
x = 5 - '5'; // x = 0
x = '5' - 6 - 7; // x = -8
x = 5 - 6 - '7'; // x = -8
x = 5 - '6' - 7; // x = -8 
x = 5 - '6' - '7'; // x = -17 ..Nice 
x = 5 * 10; // x = 50
x = '5' * 5; // x = 25 lol ok... expected `55555` but ok..
x = 5 * '10'; // x = 50
2 * [1, 2]; // NaN
2 * ['7']; // 14 ..Nice

2.0 * 2.5; // 5
5 ** 2; // 25
5 ** 3; // 125
5 ** '3'; // 125
'5' ** 3; // 125 I'm doing this just to be sure...
2 ** [4]; // 16
8 / 2; // 4
8 / 3; // 2.6666666666666665
10 / '2' // 5
10 / '3' // 3.3333333333333335
4.4 / 2 // 2.2
4.4 / 2.0 // 2.2
12 % 3 // 0
'10' % 3 // 1
JavaScript Assignment Operators
Operator Example Same As
= x = y x = y
+= x += y x = x + y
-= x -= y x = x - y
*= x *= y x = x * y
/= x /= y x = x / y
%= x %= y x = x % y
**= x **= y x = x ** y
Operator Description
== equal to
=== equal value and equal type
!= not equal
!== not equal value or not equal type
> greater than
< less than
>= greater than or equal to
<= less than or equal to
? ternary operator
Operator Description
&& logical and
|| logical or
! logical not

Strings, Strings methods and Template Literals

CODE OUTPUT
' or " escape single or double quote
\\ escape backslash
\n newline
\r carriage return
\t tab (horizontal tabulator lel)
\v tab (vertical tabulator)
\b backspace
\f form feed
// Strings Can be Objects
// strings can also be defined as objects with the keyword new:
var x = "John";
var y1 = new String("John");
var y2 = new String("John");
// typeof x will return string
// typeof y1 will return object

// However, don't create strings as objects. It slows down execution speed.
// The new keyword complicates the code and can produce some unexpected results:
// (y1 === y2) is false because x and y are different objects
  1. String length
var txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
console.log(txt.length); // 26
console.log('aaa'.length); // 3
  1. indexOf() method returns the index of (position of) the first occurrence of a specified text in a string. Returns -1 if no occurence is found.
"Phonenumber1,Phonenumber2".indexOf(',') // 12
"Phonenumber1".indexOf(',') // -1

Manual implementation of indexOf() (source)

function indexOfAlternative(str, query) {
  for(var i = 0; i < str.length; i++) {
    for(var q = 0; q < query.length; q++) {
      if (str[i+q] !== query[q]) { break; }
      if (q === query.length - 1) { return i; }
    }
  }
  return -1;
}

Random application for indexOf - split a string by the first occurence of a character into an array that contains 2 elements:

var splitStringInArrByFirstMatch = function(str, characterToMatch) {
    characterToMatchIdx = str.indexOf(characterToMatch)
    if (characterToMatchIdx === -1) {
        return [str]
    } else {
        return [str.slice(0, characterToMatchIdx), str.slice(characterToMatchIdx)];
    }
}

console.log(splitStringInArrByFirstMatch("075123", ",")); // [ '075123' ]
console.log(splitStringInArrByFirstMatch("075123,1123", ",")); // [ '075123', ',1123' ]
console.log(splitStringInArrByFirstMatch("075123,1123,12345", ",")); // [ '075123', ',1123,12345' ]

console.log(splitStringInArrByFirstMatch("prefix-phone-number-digits", "-")); // [ 'prefix', '-phone-number-digits' ]
console.log(splitStringInArrByFirstMatch("+41-075-123-1234", "-")); // [ '+41', '-075-123-1234' ]
  1. lastIndexOf() method returns the index of the last occurrence of a specified text in a string
"Please locate where 'locate' occurs!".indexOf("locate"); // 7
"Please locate where 'locate' occurs!".lastIndexOf("locate"); // 21

// Both indexOf(), and lastIndexOf() return -1 if the text is not found.
"Please locate where 'locate' occurs!".lastIndexOf("NotInString"); // -1

// Both methods accept a second parameter as the starting position for the search:
"Please locate where 'locate' occurs!".indexOf("locate", 15); // 21
  1. search() method searches a string for a specified value and returns the position of the match
console.log("Please locate where 'locate' occurs!".search("locate")); // 7 
// search() seems to be the same as indexOf()

console.log("Please locate where 'locate' occurs!".search("banana")); // -1
// Returns -1 if substring is not found in string
  1. Extracting String Parts: slice(start, end), substring(start, end), substr(start, length)
    • slice() extracts a part of a string and returns the extracted part in a new string.
var str = "0123456789012345678";
var str = "Apple, Banana, Kiwi";
var res = str.slice(7, 13); // 'Banana'
// In Python, we would use str[7:13]

// If a parameter is negative, the position is counted from the end of the string
str.slice(-12, -6); // 'Banana'

// If you omit the second parameter, the method will slice out the rest of the string
str.slice(7); // 'Banana, Kiwi'
// In Python, we would use str[7:]

// Counting from the end:
str.slice(-12); // 'Banana, Kiwi'
str.slice(-4); // 'Kiwi'
var str = "Apple, Banana, Kiwi";
str.substring(0, 5); // 'Apple'
str.substring(12, 7); // 'Banan' .. interesting
var str = "0123456789012345678";
var str = "Apple, Banana, Kiwi";
str.substr(7, 6); // 'Banana'
str.substr(15, 4); // 'Kiwi'

// If you omit the second parameter, substr() will slice out the rest of the string

// If the first parameter is negative, the position counts from the end of the string.
str.substr(-4); // Kiwi
  1. replace() method replaces a specified value with another value in a string. By default, the replace() method replaces only the first match
let str = "Hi Adam. Adam?";
str.replace("Adam", "Louis"); // "Hi Louis. Adam?"

replace() method is case sensitive, but you can use a regular expression with an /i flag (insensitive). Regular expressions are written without quotes!

str = "visit Google!";
var n = str.replace(/GOOGLE/i, "W3Schools");

To replace all matches, use a regular expression with a /g flag (global match):

let str = "Hi Adam. Adam?";
str.replace(/Adam/g, "Louis"); // "Hi Louis. Louis?"

More on regular expressions here, but it’s not the time yet, so don’t click it.

  1. toUpperCase(), toLowerCase()
"HELLO CAN YOU HEAR ME?".toLowerCase() // 'hello can you hear me?'
"no?".toUpperCase() // 'NO?'
  1. concat() joins two or more strings
var text1 = "Hello";
var text2 = "World";
var text3 = text1.concat(" ", text2); // 'Hello World'
var text4 = text1.concat(" ", text2, ' ', "I guess"); // "Hello World I guess"

var text = "Hello" + " " + "World!";
var text = "Hello".concat(" ", "World!"); // will do the same

All string methods return a new string. They don’t modify the original string.
Formally said: Strings are immutable: Strings cannot be changed, only replaced.

  1. trim() method removes whitespace from both sides of a string
var str = "       Hello World!        ";
console.log(str.trim()); // Hello World!

// The trim() method is not supported in Internet Explorer 8 (2009) or lower
  1. Extracting String Characters: charAt(), charCodeAt() or [ ] (Property access)
    • charAt() returns the character at a specified index (position) in a string
    • charCodeAt() returns the unicode of the character at a specified index in a string
    • [ ] property access on strings is available from ECMASCript 5 (2009)
var str = "HELLO WORLD";
str.charAt(0); // 'H'
str.charCodeAt(0); // returns 72
str[0]; // 'H'
str[str.length - 1]; // last letter 'D'

// If no character is found, [ ] returns undefined, while charAt() returns an empty string
// It is read only. str[0] = "A" gives no error (but does not work!).. strings are immutable
// [ ] does not work in Internet Explorer 7 or earlier (2006)
// If you want to work with a string as an array, you can convert it to an array (like in Python)
  1. split() Convert a String to an Array
var txt = "a,b,c,d,e";   // String
txt.split(",");          // Split on commas [ 'a', 'b', 'c', 'd', 'e' ]
"a b c d".split(" ");    // Split on spaces [ 'a', 'b', 'c', 'd' ]

var txt = "abcdef";
txt.split('b'); // [ 'a', 'cdef' ]

// If the separator is "", the returned array will be an array of single characters
txt.split(''); // [ 'a', 'b', 'c', 'd', 'e', 'f' ]

// If the separator is omitted, the returned array will contain the whole string in index [0].
txt.split(); // [ 'abcdef' ]
  1. repeat(nr_of_times) returns the string repeated
let str = "Hello";
str.repeat(3); // 'HelloHelloHello'
  1. String includes, match
var str = "Hello world, welcome to the universe.";
str.includes("world"); // true
var str = "The rain in SPAIN stays mainly in the plain"; 
str.match(/ain/g); // [ 'ain', 'ain', 'ain' ]

Note: If the regular expression does not include the g modifier (to perform a global search), the match() method will return only the first match in the string. This method returns null if no match is found.

const person = {
  name: "Ben",
  age: 37
};
const greeting = `Hello, ${person.name}!
Your age is ${person.age}.`; // Note the use of backticks

// With backticks, we can put variables right in the string using $
// We can also make multi-line strings without using / as separator
// Also. you don't have to escape any quotation marks ' ', " "

One more example using Template Literals vs. not using them:

const count = 3
const user = 'Benny Doe'
const span = 2

function pluralize(text, count) {
    if (count === 1) {
        return text
    }
    return text + 's'
}

// WITHOUT Template Literals:
const result = count + ' ' + pluralize('blog post', count)  
                     + ' were written by ' + name
                     + ' in a span of ' + span 
                     + ' ' + pluralize('week', span) + '.';

// WITH Template Literals:
const result = `${count} ${pluralize('blog post', count)} were written by ${name} in a span of ${span} ${pluralize('week', span)}.`

Another example using Template Literals:

const result = {
  success: ["max-length", "no-amd", "prefer-arrow-functions"],
  failure: ["no-var", "var-on-top", "linebreak"],
  skipped: ["no-extra-semi", "no-dup-keys"]
};

function makeList(arr) {
  const failureItems = [];
  for (let i = 0; i < arr.length; i++) {
    failureItems.push(`<li class="text-warning">${arr[i]}</li>`)
  }
  return failureItems;
}

const failuresList = makeList(result.failure);
/*
  ['<li class="text-warning">no-var</li>',
  '<li class="text-warning">var-on-top</li>',
  '<li class="text-warning">linebreak</li>']
*/

Numbers: Decimal, Hexadecimal, Octal, Binary, Infinity and Number Methods toFixed/toPrecision

JavaScript interprets numeric constants as:

// toString() method can be used only with a DEFINED variable!!!
// 54.toString() will give SyntaxError: Invalid or unexpected token

// Convert DEC -> BIN
var x = 17; x.toString(2) // '10001'
// Convert DEC -> HEX
var x = 17; x.toString(16) // '11'
// Convert DEC -> OCT
var x = 17; x.toString(8) // '21'

// Convert BIN -> DEC
var y = 0b110; y.toString(10) // '6'
// Convert BIN -> HEX
var y = 0b1110; y.toString(16) // 'e' (why lowercase tho)

// Convert HEX -> DEC
var z = 0xF; z.toString(10) // '15'
// Convert HEX -> BIN
var z = 0xF; z.toString(2) // '1111'

We can also convert using parseInt():

// Another method to convert BIN -> DEC using parseInt()
var x = parseInt("11", 2); // x = 3
var x = parseInt("110", 2); // x = 6

// HEX -> DEC
console.log(parseInt("f", 16));// x =  15

Differences between parseInt() and Number() to convert String->Int

var myNumber = 2;
while (myNumber != Infinity) {   // Execute until Infinity
  myNumber = myNumber * myNumber;
}

// Division by 0 (zero) also generates Infinity:
var x =  2 / 0;       // x will be Infinity
var y = -2 / 0;       // y will be -Infinity

// Infinity is a number:
typeof Infinity;     // returns "number"... Weirdly enough...

Oook, infinity, best desigh choice ever you’d say. But how do you actually catch division by zero then?

// check with an if statement
if (n === 0 || isNaN(n)) {
    vax result = number / n;
}

// or check with isFinite(), if return false, then handle it appropriately

// or...
function notZero(n) {
  n = +n;  // Coerce to number.
  if (!n) {  // Matches +0, -0, NaN
    throw new Error('Invalid dividend ' + n);
  }
  return n;
}
var result = numerator / notZero(denominator)
var x = 123;
var y = new Number(123);
// typeof x returns number
// typeof y returns object

// However, do not create Number objects. It slows down execution speed
var x = 9.656;
console.log(x.toFixed(0)); // returns 10
console.log(x.toFixed(2)); // returns 9.66
console.log(x.toFixed(3)); // returns 9.656
console.log(x.toFixed(6)); // returns 9.656000
var x = 9.656;
x.toPrecision();        // 9.656
x.toPrecision(2);       // 9.7
x.toPrecision(3);       // 9.66
x.toPrecision(6);       // 9.65600

In short: toFixed(n) provides n length after the decimal point; toPrecision(x) provides x total length of number.

Math.PI.toFixed(2); // "3.14"
Math.PI.toPrecision(2); // "3.1"

// Furthermore, toPrecision will yield scientific notation if there are more integer digits in the number than the specified precision.
(Math.PI * 10).toPrecision(2); // "31"
(Math.PI * 100).toPrecision(2); // "3.1e+2"
var x = 0.1;
var y = 0.2;
var z = x + y // the result in z will not be 0.3 but 0.30000000000000004

To solve this we use:

var z = (x * 10 + y * 10) / 10; // z will be 0.3

// or if we know what result to expect:
var z = (x + y).toFixed(1); 
var x = Number.MAX_VALUE; // 1.7976931348623157e+308
var x = Number.MIN_VALUE; // 5e-324
var x = Number.POSITIVE_INFINITY; // Infinity

// Number Properties Cannot be Used on Variables
var x = 6; var y = x.MAX_VALUE;    // y becomes undefined

JavaScript if else, switch, for, for in, for of loop, while, do/while loop, break

if else

if (condition1) {
  //  code
} else if (condition2) {
  //  code
} else {
  //  code
}

Inline if (or Ternary Operator):

a ? b : c // is rougly the same as if (a) { b; } else { c; }
// and
(a && b) || c // is rougly the same as a ? b : c

// Eg
var c = (a < b) ? "a is less than b"  : "a is not less than b";
// condition ? codeblock_if_condition_is_met : codeblock_if_condition_is_not_met;

// for more statements: if elseif else
var variable = (condition) ? (true block) : ((condition2) ? (true block2) : (else block2))
// same as
  a === "a" ? do something
: a === "b" ? do something
: do something

// another eg.
function checkSign(num) {
  return num > 0 ? "positive" : num < 0 ? "negative" : "zero";
}

switch

switch(expression) {
  case x:
    // code block
    break;
  case y:
    // code block
    break;
  default:
    // code block
}

// In this example case 4 and 5 share the same code block, and 0 and 6 share another code block:
switch (new Date().getDay()) {
  case 4:
  case 5:
    text = "Soon it is Weekend";
    break;
  case 0:
  case 6:
    text = "It is Weekend";
    break;
  default:
    text = "Looking forward to the Weekend";
}
<body>
<p id="demo"></p>

<script>
var x = 0; // will show Off
var x = '0'; // will show No value found

switch (x) {
  case 0:
    text = "Off";
    break;
  case 1:
    text = "On";
    break;
  default:
    text = "No value found";
}
document.getElementById("demo").innerHTML = text;
</script>

</body>

Loops

for loop

for (statement 1; statement 2; statement 3) {
  // code block to be executed
}

// <p id="demo"></p>
var text = "";
for (let i = 0; i < 8; i++) {
  text += "The number is " + i + "<br>";
}
document.getElementById("demo").innerHTML = text;
var cars = ["BMW", "Volvo", "Saab", "Ford"];
var len, text;
for (let i = 0, len = cars.length, text = ""; i < len; i++) {
  text += cars[i] + "<br>";
}
document.getElementById("demo").innerHTML = text;
// Looping over an array
var myArr = [9, 10, 11, 12];
var mySum = 0;

for (let i = 0; i < myArr.length; i++) {
  mySum += 0 myArr[i];
}


Example: Solving FizzBuzz:

const FizzBuzzBazz = (num) => {
  for (let i = 0; i <= num; i++) {
    let output = "";
    if (i % 3 === 0) {
      output += "Fizz";
    }
    if (i % 5 === 0) {
      output += "Buzz";
    }
    if (i % 7 === 0) {
      output += "Bazz";
    }
    if (output == "") {
      output = i;
    }
    console.log(output);
  }
}

FizzBuzzBazz(18);

for...in loops through the properties of an object

var txt = "";
var person = {fname:"John", lname:"Doe", age:25}; 
var x;
for (x in person) {
  txt += person[x] + " ";
}
document.getElementById("demo").innerHTML = txt; // John Doe 25
var txt = "";
var persons = [
    {fname:"Jane", lname:"Doe", age:23},
    {fname:"John", lname:"Doe", age:27},
    {fname:"Albert", lname:"Doa", age:24}
]; 
var x;
for (x in persons) {
  txt += persons[x].fname + " " + persons[x].lname + " " + persons[x].age + "<br>";
}
document.getElementById("demo").innerHTML = txt; // Jane Doe 23 John Doe 27 Albert Doa 24

for...of loops through the values of an iterable objects

var cars = ['BMW', 'Volvo', 'Mini'];
var x;

for (x of cars) {
  document.write(x + "<br >"); // BMW Volvo Mini
}

// using for x IN cars
for (x in cars) {
  document.write(x + "<br >"); // 0 1 2
}

// looping over a String
var txt = 'JavaScript';

for (let x of txt) {
  document.write(x + "<br >");
}

while loop, do while loop

var text = "";
var i = 0;
while (i < 10) {
  text += "<br>The number is " + i;
  i++;
}
document.getElementById("demo").innerHTML = text;
// If you forget to increase the variable used in the condition, the loop will never end. 
// This will crash your browser.. yep I can confirm, chrome tab freezes.

var myArray = [];
var i = 0;
while (i < 5) {
  myArray.push(i);
  i++;
}

do {} while ();

do {
  text += "The number is " + i;
  i++;
}
while (i < 10);

A while loop is much the same as a for loop, with statement 1 and statement 3 omitted:

var cars = ["BMW", "Volvo", "Saab", "Ford"];
var i = 0;
var text = "";

for (;cars[i];) {
  text += cars[i] + "<br>";
  i++;
}
// same as
while (cars[i]) {
  text += cars[i] + "<br>";
  i++;
}

break and continue statement

The break statement can also be used to jump out of a loop and continues executing the code after the loop (if any).

for (i = 0; i < 10; i++) {
  if (i === 3) { break; }
  text += "The number is " + i + "<br>";
}

The continue statement breaks one iteration (in the loop), if a specified condition occurs, and continues with the next iteration in the loop.

for (i = 0; i < 6; i++) {
  if (i === 3) { continue; }
  text += "The number is " + i + "<br>";
}
// This example skips the value of 3: will show 0 1 2 4 5

More on objects:

let foods = {
  apples: 25,
  oranges: 32,
  plums: 28
}
console.log(foods['apples']); // 25
console.log(foods.apples); // 25
let userActivity = {
  id: 23894201352,
  date: 'January 1, 2017',
  data: {
    totalUsers: 51,
    online: 42
  }
};
userActivity.data.online = 45;
userActivity['data']['online'] = 45;
// Both methods work
let foods = {
  apples: 25,
  oranges: 32,
  plums: 28,
  bananas: 13,
  grapes: 35,
  strawberries: 27
};

delete foods.oranges;
delete foods.plums;
delete foods.strawberries;
console.log(foods); // { apples: 25, bananas: 13, grapes: 35 }

delete foods;
console.log(foods); // { apples: 25, bananas: 13, grapes: 35 } IT DOESN'T DELETE THE OBJECT
true + true // 2

users = {
  Alan: {
    online: false
  },
  Jeff: {
    online: true
  },
  Sarah: {
    online: false
  }
}

function countOnline(usersObj) {
  let cnt = 0;
  for (let user in usersObj) {
    cnt += (usersObj[user]['online'])
  }
  return cnt;
}

console.log(countOnline(users)) // 1
let users = {
  Alan: {
    age: 27,
    online: false
  },
  Jeff: {
    age: 32,
    online: true
  },
  Sarah: {
    age: 48,
    online: false
  }
};

console.log(Object.keys(users));// [ 'Alan', 'Jeff', 'Sarah' ]
let user = {
  name: 'Kenneth',
  age: 28,
  data: {
    username: 'kennethCodesAllDay',
    joinDate: 'March 26, 2016',
    organization: 'freeCodeCamp',
    friends: [
      'Sam',
      'Kira',
      'Tomo'
    ],
    location: {
      city: 'San Francisco',
      state: 'CA',
      country: 'USA'
    }
  }
};

function addFriend(userObj, friend) {
  userObj.data.friends.push(friend);
  return userObj.data.friends
}

console.log(addFriend(user, 'Pete')); // [ 'Sam', 'Kira', 'Tomo', 'Pete' ]
let duck = {
  name: "Aflac",
  numLegs: 2,
  sayName: function() {return "The name of this duck is " + this.name + ".";}
  sayLegs: () => {return `This duck has ${this.numLegs} legs.`;}
};
duck.sayName(); // "The name of this duck is Aflac."
function Dog() {
  this.name = "Albert";
  this.color = "brown";
  this.numLegs = 3;
  // "this" inside the constructor always refers to the object being created
}

let whiteDoggie = new Dog();
whiteDoggie.color = 'white';

Ofc we can extend our constructors to receive argument and pass values while we creating a new object:

function Dog(name, color) {
  this.name = name;
  this.color = color;
}
let terrier = new Dog('Coco', 'white');

// We can also verify an object's constructor with instanceof (name without with camelCase...)
console.log(terrier instanceof Dog); // => true
function Bird(name) {
  this.name = name;
  this.numLegs = 2;
}
let canary = new Bird("Tweety");

let ownProps = [];
for (let property in canary) {
  if(canary.hasOwnProperty(property)) {
    ownProps.push(property);
  }
}
console.log(ownProps); // [ 'name', 'numLegs' ]
console.log(duck.numLegs);  // prints 2
console.log(canary.numLegs);  // prints 2
// We can solve with prototype
function Bird(name) {
  this.name = name; // own property
  Bird.prototype.numLegs = 2; // Note we don't use this (that's a own property, not a prototype)
}
Bird.prototype.numLegs = 2; // We can also define our prototype property outside our constructor

/* Extract an object "own properties" and "prototype properties" */
let ownProps = [];
let prototypeProps = [];
for (let property in duck) {
  if(duck.hasOwnProperty(property)) {
    ownProps.push(property);
  } else {
    prototypeProps.push(property);
  }
}
console.log(ownProps); // prints ["name"]
console.log(prototypeProps); // prints ["numLegs"]

We can also find out what kind of object we have using myNewObj.constructor === ObjectConstructorFunction..

let duck = new Bird();
let beagle = new Dog();

console.log(duck.constructor === Bird);  //prints true
console.log(beagle.constructor === Dog);  //prints true
function Dog(name) {
  this.name = name;
}

Dog.prototype = {
  constructor: Dog, // we also need to define the constructor property
  numLegs: 2, 
  eat: function() {
    console.log("nom nom nom");
  },
  describe: function() {
    console.log("My name is " + this.name);
  }
};

Arrays and Array methods: shift/unshift, push/pop, splice/slice, includes:

cars.length; // 3
cars[length - 1]; // 23 last element of array

console.log(myNestedArray[0]); // [ 'universe', 42 ]
console.log(myNestedArray[0][1]); // 42

myNestedArray[0] = "not anymore"; // [ 'not anymore', [ 'everything', 7.2 ] ]



var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.shift();          // Removes the first element "Banana" from fruits
console.log(fruits)      // ["Orange", "Apple", "Mango"]

fruits.unshift("Lemon"); // Adds a new element "Lemon" to fruits as first element
console.log(fruits)      // [ 'Lemon', 'Orange', 'Apple', 'Mango' ]


fruits.pop();         // Removes the last element ("Mango") from fruits
// Also, you can store the value of popped element: "Mango"
// var x = fruits.pop();

fruits.push("Kiwi");  // Adds a new element ("Kiwi") to end of fruits ['Orange', 'Kiwi']
// Also: The push() method returns the new array length, interesting feature.
// var x = fruits.push("Kiwi"); 

delete fruits[0];     // Changes the first element in fruits to undefined

fruits.splice(2, 0, "Lemon", "Kiwi");
// first parameter (2) defines the position where new elements should be added (spliced in).
// second parameter (0) defines how many elements should be removed.
// rest of the parameters ("Lemon" , "Kiwi") define the new elements to be added.
/* NOTE: splice method modifies the array after execution, and returns the removed elements*/

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(0, 1);        // Removes the first element of fruits



var cars_fruits = cars.concat(fruits); // Concatenates (joins) two arrays
var arr1_arr2_arr3 = arr1.concat(arr2, arr3, "Peter");   // Concatenates arr1 with arr2 and arr3 and "Peter"


var fruits = ["Banana", "Orange", "Lemon", "Apple"];
var citrus = fruits.slice(1, 3); // ["Orange", "Lemon"]
fruits_str = fruits.toString(); // 'Banana,Orange,Lemon,Apple', doesn't change fruits array
const values = [2, 3, 4];
values.includes(1); // false
values.includes(2); // true

Array sort()

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();        // Sorts array alphabetically
fruits.reverse();     // Then reverse the order of the elements

By default, the sort() function sorts values as strings (JavaScript’s default sorting method is by string Unicode point value, which may return unexpected results). This works well for strings (“Apple” comes before “Banana”). However, if numbers are sorted as strings, “25” is bigger than “100”, because “2” is bigger than “1”. Because of this, the sort() method will produce incorrect result when sorting numbers.

We can fix this by providing a compare function:

var numArray = [140000, 104, 99];
numArray.sort(function(a, b) { return a - b; }); // ascending

// Or, with ES6, you can use arrow functions
numArray.sort((a, b) => a - b); // For ascending sort
numArray.sort((a, b) => b - a); // For descending sort

With a comparing function, we can also sort an array of strings from Z to A (unalphabetical) without using reverse()

// Sort an array from Z to A (unalphabetical) without using reverse()
arr = ['Zach', 'Adrian', 'John', 'A', 'B', 'C', 'D'];
arr.sort(function(a, b) {
    return a === b ? 0 : a < b ? 1 : -1;
});
console.log(arr); // [ 'Zach', 'John', 'D', 'C', 'B', 'Adrian', 'A' ]

Sort a numeric array in random order:

var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return 0.5 - Math.random()});

Find the max/min number in an Array using Math.max():

Math.max.apply(null, numArray);
// Math.max.apply(null, [1, 2, 3]) is equivalent to Math.max(1, 2, 3)
var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
];

function compare( a, b ) {
  if ( a.last_nom < b.last_nom ){
    return -1;
  }
  if ( a.last_nom > b.last_nom ){
    return 1;
  }
  return 0;
}

objs.sort(compare);

Another example:

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'The', value: -12 },
];

// sort by value
items.sort(function (a, b) {
  return a.value - b.value;
});

// sort by name
items.sort(function(a, b) {
  var nameA = a.name.toUpperCase(); // ignore upper and lowercase
  var nameB = b.name.toUpperCase(); // ignore upper and lowercase
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }

  // names must be equal
  return 0;
});

Or inline:

objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0)); 

Or you can use inline arrow functions and localCompare (ES6/ES2015):

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));

// prior to 
objs.sort(function(a, b) {
    return a.last_nom.localeCompare(b.last_nom)
});

Note on .sort() method: sort() method changes the order of the elements in the original array (it mutates the array in place).

JavaScript Functions, Returning values and Function Hoisting

function myFunctionName(p1, p2) {
  return p1 * p2;
}
let result = myFunctionName(2, 5); // 10
function toCelsius(fahrenheit) {
  return (5/9) * (fahrenheit-32);
}
document.getElementById("demo").innerHTML = toCelsius(80);
// Accessing a function without () will return the function object instead of the function result.
// function toCelsius(f) { return (5/9) * (f-32); }
function getValues() {
    return [getFirstValue(), getSecondValue()];
}
var values = getValues(); var first = values[0]; var second = values[1];
// or Access them with (ECMAScript 6)
var [first, second] = getValues();


// OR you can return an object with "labels"
function getValues() {
    return {
        first: getFirstValue(),
        second: getSecondValue(),
    };
}
var values = getValues(); var first = values.first; var second = values.second;
// or Access them with (ECMAScript 6)
var {first, second} = getValues();
// Other way of looking at it:
var [x, y] = [1, 2];
x; // 1
y; // 2

// or
[x, y] = (function(){ return [3, 4]; })();
x; // 3
y; // 4

// or
let {x, y} = (function(){ return {y: 3, z: 500, x: 40} })();
x; // 40
y; // 3
// JavaScript Hoisting
myFunction(5);

function myFunction(y) {
  return y * y;
}

Arrow functions

Arrow functions allows a short syntax for writing function expressions. You don’t need the function keyword, the return keyword or the curly brackets.

function hello() {
    return "Hello World"
}

var hello = function() {     // this is also called anonymous function 
  return "Hello World!"; // (function without a name that is asigned to var hello)
}                        // which can be written as an arrow function

// With arrow function
var hello = () => {
  return "Hello World!";
}

// With arrow function that returns only a single value by default and without parameters
var hello = () => "Hello World!";

// Arrow function with parameters
var hello = (val, val2) => "Hello " + val + val2;
var hello = e => "Hello " + e; // usually people use 'e' instead of 'val'
// ES5
var x = function(x, y = 5) { // You can make y = 5 as default
  return x * y;
}

// ES6
const x = (x, y) => x * y;

// call it
x(5, 5)

this operator

/* Both examples call a method twice:
first when the page loads, and once again when user clicks a button */

/* EXAMPLE WITH REGULAR FUNCTION */
// With a regular function this represents THE OBJECT THAT CALLS the function:
hello = function() { document.getElementById("demo").innerHTML += this; }

window.addEventListener("load", hello); // The window object calls the function
document.getElementById("btn").addEventListener("click", hello); // A button object calls the function

// => on first page reload will show [object Window]
// => after pressing button will show [object HTMLButtonElement]
/* EXAMPLE WITH ARROW FUNCTION */
// With an arrow function this represents the owner of the function:
hello = () => { document.getElementById("demo").innerHTML += this; }

window.addEventListener("load", hello); // The window object calls the function
document.getElementById("btn").addEventListener("click", hello); // A button object calls the function

// => on first page reload will show [object Window]
// => after pressing button will show [object Window]
// The owner is the Global object, so this refers to the Global object
// That's because in a browser window the Global object is [object Window]

More on this here

// this in a method within an object
var person = {
  firstName: "John",
  lastName : "Doe",
  id       : 5566,
  fullName : function() {
    return this.firstName + " " + this.lastName;
  }
};
console.log(person.fullName()) // John Doe
// Or, more specific:
var person = {
  firstName  : "John",
  lastName   : "Doe",
  id         : 5566,
  myFunction : function() {
    return this;
  }
};
document.getElementById("demo").innerHTML = person.myFunction(); // [object Object]
console.log(person.myFunction()); // will show all the definiton with properties and methods of object person
<!-- In HTML event handlers, this refers to the HTML element that received the event: -->
<button onclick="this.style.display='none'">
  Click to Remove Me!
</button>

Making a simple counter function with a button

<!DOCTYPE html>
<html>
<body>

<p>The counter is: <span id="demo"></span></p>
<button id="btnAdd">Count</button>

<script>
var counter = 0; // global variable, can be used (and changed) by all scripts in the page

function addCnt() {
    counter += 1;
    document.getElementById("demo").innerHTML = counter;
}
document.getElementById("btnAdd").addEventListener("click", addCnt);
</script>

</body>
</html>
<!-- However, there is a problem with the solution above: Any code on the page can change the counter, without calling add(). -->

JavaScript function closures

Another example on function closures here or here.

<!DOCTYPE html>
<html>
<body>

<p id="demo">0</p>
<button type="button" onclick="myFunction()">Count</button>

<script>
var add = (function () {
  var counter = 0;
  return function () {counter += 1; return counter;}
})();

function myFunction(){
  document.getElementById("demo").innerHTML = add();
}
</script>

</body>
</html>

The variable add is assigned the return value of a self-invoking function.
The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression.
This way add becomes a function. The “wonderful” part is that it can access the counter in the parent scope.
This is called a JavaScript closure. It makes it possible for a function to have “private” variables.
The counter is protected by the scope of the anonymous function, and can only be changed using the add function.

<!-- Add parameter to functions closures -->
<!DOCTYPE html>
<html>
<body>

<button type="button" onclick="myFunctionInc()">Increment</button>
<button type="button" onclick="myFunctionDec()">Decrement</button>
<p id="demo">0</p>

<script>
var add = (function () {
  var counter = 0;
  return function (param) {
    if (param === 'add') {
      counter += 1; 
    } else {
      counter -= 1;
    }
    return counter;
  }
})();

function myFunctionInc(){
  document.getElementById("demo").innerHTML = add('add');
}
function myFunctionDec(){
  document.getElementById("demo").innerHTML = add('sub');
}
</script>

</body>
</html>

The Rest operator (...) on Function Parameters and Spread (...) operator to Evaluate Arrays In-Place

The Rest operator allows a function to take a variable number of arguments

/* This function takes 3 parameters and returns their sum */
const sum = (function() {
  return function sum(x, y, z) {
    const args = [x, y, z];
    return args.reduce((a, b) => a + b);
  };
})();
console.log(sum(1, 2, 3)); // 6
/* This function takes any number of parameters using Rest operator and returns their sum */
const sum = (function() {
  return function sum(...args) {
    // The Rest operator (...) wil convert the argumets into an array called args
    return args.reduce((a, b) => a + b);
  };
})();
console.log(sum(1, 2, 3, 4)); // 10

The Spread operator expands an already existing array (spreads out an array into its individual elements)

By default, copying an array uses pass-by-reference values.

const arr1 = ['JAN', 'FEB', 'MAR', 'APR'];
let arr2 = arr1;
arr1[0] = 'potato';
console.log(arr2); // [ 'potato', 'FEB', 'MAR', 'APR' ]
console.log(arr1); // [ 'potato', 'FEB', 'MAR', 'APR' ]

Using the Spread operator, we will “copy” the array using pass-by-value:

const arr1 = ['JAN', 'FEB', 'MAR', 'APR'];
let arr2 = [...arr1];
arr1[0] = 'potato';
console.log(arr2); // [ 'JAN', 'FEB', 'MAR', 'APR' ]
console.log(arr1); // [ 'potato', 'FEB', 'MAR', 'APR' ]

In Python we would use the Unpack * operator:

# In Python we use the * operator
# Example 1 (pass-by-reference)
a = [1, 2, 3]
b = a
b[0] = 'changed'
print(a) # ['changed', 2, 3]
print(b) # ['changed', 2, 3]

# Example 2 (pass-by-value)
a = [1, 2, 3]
b = [*a]
b[0] = 'changed'
print(a) # [1, 2, 3]
print(b) # ['changed', 2, 3]
const numbers = [1, 2, 3, 4, 5, 6, 7];
const [ , , ...arr] = numbers;
console.log(arr); // [3, 4, 5, 6, 7]

Arrays and Array iteration methods: forEach, map, filter, reduce, every, some, indexOf, find, findIndex

JavaScript Array Methods

Array.forEach() method calls a function (a callback function) once for each element

var txt = "";
var numbers = [45, 4, 9, 16, 25];
numbers.forEach(myFunction);

function myFunction(value, index, array) {
  txt = txt + value + "<br>";
}
console.log(txt) // 45<br>4<br>9<br>16<br>25<br>

// or using js arrow function
numbers.forEach((value) => {txt += value + "<br>";});


// In Python we would use list comprehension and join
txt = "".join([str(_)+"<br>" for _ in x])

Note that the function takes 3 arguments, some can be optional but must respect the same name:

Array.map() method creates a new array by performing a function on each array element

var numbers1 = [45, 4, 9, 16, 25];
var numbers2 = numbers1.map(myFunction);

function myFunction(value, index) {
  return value * 2;
}
console.log(numbers2) // [ 90, 8, 18, 32, 50 ]

// or using js arrow function
var numbers2 = numbers1.map((value) => {return 2 * value});
# In Python we would use list comprehension:
numbers2 = [2 * _ for _ in numbers1]
# or map and lambda function
numbers2 = list(map(lambda _: 2 * _, numbers1))

Another example of using map to convert strings numbers to numbers:

['1', '7', '11'].map(n => parseInt(n)) // [1, 7, 11]

// WRONG Method of doing it:
['1', '7', '11'].map(parseInt) // [1, NaN, 3]

// And also, we need to use Number() or parseFloat() for numbers that are not integers
console.log(['1', '7.2', '11.98', '3.1415'].map(n => parseInt(n))); // [ 1, 7, 11, 3 ]
console.log(['1', '7.2', '11.98', '3.1415'].map(n => Number(n))); // [ 1, 7.2, 11.98, 3.1415 ]
console.log(['1', '7.2', '11.98', '3.1415'].map(n => parseFloat(n))); // [ 1, 7.2, 11.98, 3.1415 ]

Note: See the difference between Number() and parseFloat()

Note: The differences between forEach and map are:

let arr = [1, 2, 3, 4, 5];
let doubled = arr.forEach((num, index) => {
    return arr[index] = num * 2;
});
console.log(arr); // [2, 4, 6, 8, 10]
console.log(doubled); // undefined

// NOTE: We can't use forEach() with an arrow function that receives the element directly
let arr = [1, 2, 3, 4, 5];
arr.forEach(value => value * 2);
console.log(arr); // returns [ 1, 2, 3, 4, 5 ] !!!
let arr = [1, 2, 3, 4, 5];
let doubled = arr.map(num => {
    return num * 2;
});
console.log(arr); // [1, 2, 3, 4, 5]
console.log(doubled); // [2, 4, 6, 8, 10]

Array.filter() method creates a new array with array elements that passes a test

var numbers = [45, 4, 9, 16, 25];
var over18 = numbers.filter(myFunction);

function myFunction(value, index, array) {
  return value > 18;
}
console.log(over18) // [ 45, 25 ]

// or using js arrow function
var over18 = numbers.filter((value) => {return value > 18;});
# In Python we could use list comprehension:
over18 = [_ for _ in numbers if _ > 18]

Another example:

// Compute the square root of integers only (not floats)
var numbers = [4, 5.6, -9.8, 3.14, 12, 6, 8.34, -2];
var squareNumbers = numbers.filter(val => Number.isInteger(val)).map(x => x ** 2);
console.log(squareNumbers); // [ 16, 144, 36, 4 ]
// Same example but in 2 methods:
arr.filter(val => Number.isInteger(val) && val >= 0)
   .map(val => val**2);

// is the same as (here we use curly brackets and return)
arr.filter((val) => {return Number.isInteger(val) && val >= 0})
   .map((val) => {return val ** 2});

Array.reduce() method runs a function on each array element to produce (reduce it to) a single value

var numbers = [45, 4, 9, 16, 25];
var nrSum = numbers.reduce(myFunction);

function myFunction(total, value, index, array) {
  return total + value;
}
console.log(nrSum); // 99

// or using js arrow function
var nrSum = numbers.reduce((total, value) => {return total + value});
# In Python, we can use sum(Array)
nrSum = sum(numbers) 

Soo, if we want to add only the numbers that are >18?

var numbers = [45, 4, 9, 16, 25];
var sumOver18 = numbers.filter((value) => {return value > 18;})
                        .reduce((total, value) => {return total + value}); // 70
// or
var sumOver18 = numbers.filter(e => e > 18)
                        .reduce((total, value) => {return total + value});
# or in Python using list comprehension and sum()
sumOver18 = sum([_ for _ in numbers if _ > 18])

What if we want sum of even numbers?

var numbers = [45, 4, 9, 16, 25];
var sumEven = numbers.filter(e => !(e % 2))
                      .reduce((total, value) => {return total + value}); // 20
# and Python?
sumEven = sum([_ for _ in numbers if _ % 2 == 0])


Sum of all prices of an Array with objects that have a “price” property:

let arr = [
  { name: "Banana", price: 2 },
  { name: "Chia seeds", price: 5 },
  { name: "Milk" },
  { name: "Potatoes", price: 1.5 }
];

// Also check if object has a price property, if not, map as 0 (zero)
let totalPrice = arr.map(item => item.price || 0)
					.reduce((total, price) => {return total + price}, 0);

console.log(totalPrice); // 8.5
# Python3
arr = [
  {'name': "Banana", 'price': 2},
  {'name': "Chia seeds", 'price': 5},
  {'name': "Milk"},
  {'name': "Potatoes", 'price': 1.5}
]

# Also check if item (dict) has a price attribute/key
totalPrice = sum([item['price'] for item in arr if 'price' in item])
print(totalPrice) # 8.5


Array.every() method check if all array values pass a test

var numbers = [45, 4, 9, 16, 25];
var allOver18 = numbers.every((value, index, array) => {return value > 18});
console.log(allOver18) // false
# In Python we would use all() and list comprehension
allOver18 = all([_ > 18 for _ in numbers]) # False
# all() returns True if every element in the list is True
# [_ > 18 for _ in numbers] returns [True, False, False, False, True]

Array.some() method check if some array values pass a test

var numbers = [45, 4, 9, 16, 25];
var someOver18 = numbers.some((value) => {return value > 18}); // true
# In Python we would use any() and list comprehension
someOver18 = any([_ > 18 for _ in numbers]) // True

Array.indexOf(item[, start]) method searches an array for an element value and returns its position

var fruits = ["Kiwi", "Apple", "Orange", "Apple", "Mango"];
var a = fruits.indexOf("Apple"); // 1

// in Python we would use index
fruits.index('Apple') // 1
fruits.index('Orange') // 2
fruits.indexOf('dates'); // returns -1 if element is not present in array

function quickCheck(arr, elem) {
  return (arr.indexOf(elem) != -1) ? true : false
}
console.log(quickCheck(['squash', 'onions', 'shallots'], 'mushrooms')); // false

Array.find() returns the value of the first array element that passes a test function

var numbers = [4, 9, 16, 25, 29];
var first = numbers.find(myFunction); // 25
function myFunction(value, index, array) {
  return value > 18;
}

// or with js arrow function
var first = numbers.find(e => e > 18); // 25

Array.findIndex() method returns the index of the first array element that passes a test function

var numbers = [4, 9, 16, 25, 29];
var first = numbers.findIndex(myFunction); // 3 (index)

function myFunction(value, index, array) {
  return value > 18;
}

Using Destructuring Assignment to Assign Variables from Objects

var voxel = {x: 3.6, y: 7.4, z:6.54};
// Method 1 [old way]:
var x = voxel.x; // x = 3.6
var y = voxel.y; // y = 7.4
var z = vozel.z; // x = 6.54

// Method 2 [new way]:
const {x: a, y: b, z: c} = voxel; // a = 3.6, b = 7.4, c = 6.54
const localForecast = {
  today: {min: 17, max: 25},
  tomorrow: {min: 15, max: 21}
};

const {tomorrow: { max: maxOfTomorrow}} = localForecast; 
console.log(maxOfTomorrow) // 21

Why don’t we use object property access instead?: because when destructuring the object you can list several variables to assign whilst = assignment is 1-to-1 where right part is being assigned to the left.

const maxOfTomorrow = localForecast.today.max;
console.log(maxOfTomorrow) // 21
var a = 3, b = 7;
[b, a] = [a, b]; // a = 7, b = 3
const source = [1,2,3,4,5];

const [, , ...arr] = source; // arr = [3,4,5]
const [a, b, ...arr] = source; // a = 1, b = 2, arr = [3,4,5]
/* Instead of passing the whole object like this: */
const stats = {
  max: 56.78,
  standard_deviation: 4.34,
  median: 34.54,
  mode: 23.87,
  min: -0.75,
  average: 35.85
};

// const half = (function() {
//   return function half(stats) {
//     return (stats.max + stats.min) / 2.0;
//   };
// })();

const half = (stats) => (stats.max + stats.min) / 2.0; // 28.015

console.log(stats);
console.log(half(stats));
/* We can pass only the parameters we need */
const stats = {
  max: 56.78,
  standard_deviation: 4.34,
  median: 34.54,
  mode: 23.87,
  min: -0.75,
  average: 35.85
};

// const half = (function() {
//   return function half( {min, max} ) {
//     return (max + min) / 2.0;
//   };
// })();

const half = ({max, min}) => (max + min) / 2.0; // 28.015

Create Concise Object Literal Declarations using Simple Fields

const createPerson = (name, age, gender) => {
  return {
    name: name,
    age: age,
    gender: gender
  };
};
console.log(createPerson("Anna", "27", "female")); // { name: 'Anna', age: '27', gender: 'female' }

If we create objects where the keys are the exact same name as the variables (arrow function’s parameters), we can rewrite our function as:

const createPerson = (name, age, gender) => ( {name, age, gender} );

Write Concise Declarative Functions

The long way of puting a function into an object:

const bicycle = {
  gear: 2,
  setGear: function(newGear) {
    "use strict";
    this.gear = newGear;
  }
};

bicycle.setGear(6);
console.log(bicycle.gear); // 6

The simpler method:

const bicycle = {
  gear: 2,
  setGear(newGear) {
    "use strict";
    this.gear = newGear;
  }
};

JavaScript Generator Function* (yield)

The yield keyword is used to pause and resume a generator function (function*). Syntax: [retrievedValue] = yield [expression]

function* foo(index) {
  while (index < 2) {
    yield index;
    index++;
  }
}

const iterator = foo(0);

console.log(iterator.next().value); // expected output: 0
console.log(iterator.next().value); // expected output: 1
/* Another example */
function* countAppleSales () {
  let saleList = [3, 7, 5];
  for (let i = 0; i < saleList.length; i++) {
    yield saleList[i];
  }
};

let appleStore = countAppleSales()  // Generator { }
console.log(appleStore.next())      // { value: 3, done: false }
console.log(appleStore.next())      // { value: 7, done: false }
console.log(appleStore.next())      // { value: 5, done: false }
console.log(appleStore.next())      // { value: undefined, done: true }

JavaScript Classes

JavaScript is object-oriented, but is not a class-based object-oriented language like Java, C++, C#. Class-based OOP languages are a subset of the larger family of OOP languages which also include prototype-based languages like JavaScript. JavaScript is both an object-oriented as well as a functional programming language.

Class Syntax:

class ClassName {
  constructor(parameters) { ... }
  get getter() { ... }
  set setter(parameter) { ... }
  method_1() { ... }
  method_2() { ... }
  method_3() { ... }
}

Using class Syntax to Define a Constructor Function

It should be noted that the class syntax is just syntax, and not a full-fledged class-based implementation of an object-oriented paradigm, unlike in languages such as Java, Python, Ruby, etc.

In ES5, we usually define a constructor function and use the new keyword to instantiate an object:

var SpaceShuttle = function(targetPlanet){
  this.targetPlanet = targetPlanet;
}
var zeus = new SpaceShuttle('Jupiter');

The class syntax simply replaces the constructor function creation:

class SpaceShuttle {
  constructor(targetPlanet) {
    this.targetPlanet = targetPlanet;
  }
}
const zeus = new SpaceShuttle('Jupiter');
console.log(zeus); // SpaceShuttle { targetPlanet: 'Jupiter' }

^^ The class keyword declares a function, to which a constructor is added. This constructor is invoked when new is called to create a new object.

One more example:

class Vegetable {
  constructor(name) {
    this.name = name;
  }
}

const carrot = new Vegetable('carrot');
console.log(carrot.name); // will display 'carrot'

Mooore examples:

class Car {
  constructor(name, year) {
    this.name = name;
    this.year = year;
  }
  age() {
    let date = new Date();
    return date.getFullYear() - this.year;
  }
}

myCar = new Car("Ford", 2014);
document.getElementById("demo").innerHTML =
"My car is " + myCar.age() + " years old.";

Using getters and setters to Control Access to an Object

You can obtain values from an object (get) and set the value of a property within an object.

/* Example 1 */
class Book {
  constructor(author) {
    this._author = author;
  }
  // getter
  get writer() {
    return this._author;
  }
  // setter
  set writer(updatedAuthor) {
    this._author = updatedAuthor;
  }
}
const novel = new Book('anonymous');
console.log(novel.writer);  // anonymous
novel.writer = 'newAuthor';
console.log(novel.writer);  // newAuthor

Note: It is convention to write the name of a private variable with an underscore (_). However, that doesn’t make a variable private.

/* Example 2 */
class Thermostat {
    constructor(fahrenheit_temp) {
        this._temp = fahrenheit_temp;
    }
    get temperature() {
        return 5/9 * (this._temp - 32);
    }
    set temperature(new_temp) {
        this._temp = new_temp;
    }
}

const thermos = new Thermostat(76); // Setting in Fahrenheit scale
let temp = thermos.temperature; // 24.44 in Celsius
thermos.temperature = 26;
temp = thermos.temperature; // 26 in Celsius

JavaScript Class Inheritance

To create a class inheritance, use the extends keyword. A class created with a class inheritance inherits all the methods from another class:

class Car {
  constructor(brand) {
    this.carname = brand;
  }
  present() {
    return 'I have a ' + this.carname;
  }
}

class Model extends Car {
  constructor(brand, mod) {
    super(brand);
    this.model = mod;
  }
  show() {
    return this.present() + ', it is a ' + this.model;
  }
}

mycar = new Model("Ford", "Mustang");
document.getElementById("demo").innerHTML = mycar.show(); // I have a Ford, it is a Mustang

^^ The super() method refers to the parent class. By calling the super() method in the constructor method, we call the parent’s constructor method and gets access to the parent’s properties and methods.

Inheritance is useful for code reusability: reuse properties and methods of an existing class when you create a new class.

Class Hoisting

Unlike functions, and other JavaScript declarations, class declarations are not hoisted. That means that you must declare a class before you can use it:

// !! You cannot use the class yet. !!
// mycar = new Car("Ford")
// This would raise an error.

class Car {
  constructor(brand) {
    this.carname = brand;
  }
}

//Now you can use the class:
mycar = new Car("Ford")

Find me on Social

My portfolio: radubulai.com

radualexandrub   radu-alexandru-bulai   radualexandrub   RaduAlexandruB