Skip to main content
JavaScript

JavaScript #

I have not learnt JavaScript properly. Proceed at your own risk.

Why does Swift by Sundell not use any client-side JavaScript? | Swift by Sundell

(Maybe) useful resources #

Exercises #

Operators #

ArithmeticLogicalRelational (numeric and string)
+ addition& and> greater than
- subtraction|| or< less than
* multiplication~ not>= > or equal
/ division^ xor<= < or equal
% remainderc ? t : f ternary== equal
** power!= not equal
+ string concatenation=== strict equal
+ convert to number!== strict not equal

Variables #

Number / string:

"use strict";

let count = 0;
count = count + 1;
console.log(count);
// 1

Array #

Also see: Array methods - javascript.info

let myArray = [1, true, "what"];
// or
let myArray = new Array(1, true, "what");
console.log(myArray[0]);
// 1

Push, pop, shift, unshift:

let myArray = ["this", "is", "life"];
myArray.push("end");          // append to end (-1)
console.log(myArray.pop());   // read and remove from end
// end

myArray.unshift("whether");   // prepend to start (0)
console.log(myArray.shift()); // read and remove from start
// whether

Slice:

let myArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(myArray.splice(3, 2)); // take b indices that are >=a
// 3, 4

console.log(myArray);
// 0, 1, 2, 5, 6, 7, 8, 9

Pop-ups #

Prompt:

let popUp = prompt("Who are you?");
// user is prompted to input

console.log(popUp);
// prints what user has typed

Confirm:

let popUp = confirm("Is this thing on?");
// user is prompted to choose yes or no

console.log(popUp);
// prints true or false

Alert:

let popUp = alert("Hello!");
// user can only click confirm

console.log(popUp);
// prints nothing

Statements #

If #

if () {
  ...
} else if () {
  ...
} else {
  ...
}

Switch #

let variable = 3;
switch(variable) {
  case 1:
    ...
    break;
  case 2:
    ...
    break;
  default:
    ...
    break;
}

Loop #

for (let i = 0; i < 3; i++) {
  ...
}
const array = [1, 2, 3, 4, 5];

for (let item of array) {
  console.log(item);
}
let object = {
  firstName: "John",
  lastName: "Smith",
}

for (let prop in object) {
  console.log(prop);
}
let i = 10;

while (i > 0) {
  ...
  i = i - 1;
}
let i = 10;

do { // is always executed at least once
  ...
  i = i - 1;
} while (i > 0);

Break and continue #

See also Python #break, pass, continue

Break: Stop the whole {...}

for (let i = 1; i < 11; i++) {
  console.log(i);
  break;
}

// 1

Continue: Stop current iteration, start next iteration

for (let i = 1; i < 11; i++) {
  if (1 == i % 2) {
    continue;
  }
  console.log(i);
}

// 2
// 4
// 6
// 8
// 10

Label for break and continue #

Break nested loops:

outer: for (let i = 0; i < 3; i++) {
  ...
  for (let j = 0; j < 3; j++) {
    ...
    if (...) break outer;
  }
}

Continue nested loops:

let n = 16;

outer: for (let i = 2; i <= n; i++) {
  for (let j = 2; j < i; j--) {
    if (i % j === 0) {
      continue outer;
    }
  }
  console.log(i);
}
// 2 3 5 7 11 13

Objects #

let person = {
  firstName: "John",
  lastName: "Smith",
  age: 20,
  employed: true,
  bio() {
    console.log(`${this.firstName} is ${this.age} years old.`);
  },
};

Always check property exists when looping:

for (let char in person) {
  if (person.hasOwnProperty(char)) {
    console.log("The " + char + " of personObject is " + person[char] + ".");
  }
}

Functions #

Ref:

Declaration (named) #

  • Can be called earlier than it is defined
  • Not anonymous
function func(x) {
  // ...
}
async function func(x) {
  // ...
}

Arrow expression (named or unnamed) #

  • return is required for multiple-line arrow functions.
  • Anonymous (even if assigned to a variable name)
(x, y) => x + y;

(x, y) => {return x + y;}

(x) => {
  // ...
  return;
};
const func = (x) => x + y;

const func = (x) => {return x + y;}

const func = (x) => {
  // ...
  return;
};
async (x) => {
  // ...
};

const func = async (x) => {
  // ...
  return;
};

IIFE (Immediately Invoked Function Expression) #

  • Can be anonymous or not
(function () {
  // ...
})();
(async function () {
  // ...
})();

Classes #

Constructor functions #

const Person = function(name, age) {
  this.name = name;
  this.age = age;
  this.describe = function() {
    return this.name + ", " + age + " years old.";
  }
}

let alice = new Person("Alice", 25);
let bob = new Person("Bob", 10);

console.log(alice.describe());  // Alice, 25 years old.
console.log(bob.describe());    // Bob, 10 years old.

Inheritance #

let Person = function() {};

Person.prototype.initialize = function(name, age) {
    this.name = name;
    this.age = age;
}

let Teacher = function() {};
Teacher.prototype = new Person();
Teacher.prototype.teach = function(subject) {
  console.log(this.name + " is now teaching " + subject);
}

let somebody = new Teacher();

somebody.initialize("Jane", 45);
somebody.teach("Inheritance");

Destructuring #

const person = {
    head: {
        eyes: 'x',
        mouth: {
            teeth: 'x',
            tongue: 'x'
        }
    },
    body: {
        shoulders: 'x',
        chest: 'x',
        arms: 'x',
        hands: 'x',
        legs: 'x'
    }   
};

let {legs: myLegs} = person.body;
console.log(myLegs);
// x
const numbers = ['2', '3', '4'];
let [, , thirdPosition] = numbers;
console.log(thirdPosition);
// 4

Context #

What are some use cases for call, apply, and/or bind? : learnjavascript

bind #

Returns a new function

let person = {
    name : "John"
};

function printName() {
    console.log(this.name);
}

let boundPrintName = printName.bind(person);
boundPrintName();      // "John"

call & apply #

Calls the original function with a different this

let person = {
    name : "John"
};

function printName() {
    console.log(this.name);
}

printName.call(person);  // "John"

Events #

Event listener #

const btn = document.querySelector("#btn");
btn.addEventListener("click", () => {
  alert("Hello World");
});

Remove event listener from within:

element.addEventListener("click", function callback(event) {
  ...

  if (condition >= 5 ) {
    element.removeEventListener("click", callback);
  }
};

Other methods #

Inline event handler (not recommended):

<button onclick="alert('Hello World')">Click Me</button>

Event handler property:

const btn = document.querySelector("#btn");
btn.onclick = () => alert("Hello World");

Promise/Async #

Promises #

Refs:

Usage:

  • const promise1 = new Promise((resolve, reject) => { resolve(); return; });
  • promise1.then((result) => { ... });
  • setTimeout(functionToRun, delay)
function upperCaseAsync(s) {
  // 1. the function is executed
  // 2. initialise the promise
  return new Promise((resolve, reject) => {
    // 3. wait 100 ms and then run if (1s = 1000ms)
    setTimeout(() => {
      if (s) {
        // if receive something, then resolve
        resolve(s.toUpperCase());
      } else {
        // if receive null, then reject
        reject("No string received!");
      }
    }, 100);
  });
  // 4. finish promise construction
}

upperCaseAsync("here").then(console.log);

upperCaseAsync("there").then((result) => {
    console.log(result);
}).catch((error) => {
    console.log("Error received:", error);
});

upperCaseAsync(null).catch((error) => {
    console.log("Error received:", error);
});

async & await (implicit Promise) #

function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

async function uppercaseString(s) {
    await sleep(100);
    return s.toUpperCase();
}

uppercaseString("here").then(console.log);

Snippets #

Add line breaks for dummies #

Ref: CSS word wrap / line break on underscores in addition to whitespace and hyphens - Stack Overflow

(function() {
  var i, text, code, codes = document.getElementsByTagName('code');
  for (i = 0; i < codes.length;) {
    code = codes[i];
    if (code.parentNode.tagName !== 'PRE' && code.childElementCount === 0) {
      // add line break before
      code.innerHTML = code.innerHTML.replace(/(?<!^|\.|\s)(\.|\(|{|\\|@)/g, '<wbr />\$1');
      // add line break after
      code.innerHTML = code.innerHTML.replace(/(,|})(?!$|\s)/g, '\$1<wbr />');
      // add line breaks around
      code.innerHTML = code.innerHTML.replace(/(?<!^|-|\.|\s)(_|-|=|\/)(?!$|\s)/g, '<wbr />\$1<wbr />');
    }
    i++;
  }
})();

Button #

index.html html
<button id="increment-btn" onclick="increment()">INCREMENT</button>
<script src="index.js"></script>
index.js js
function increment() {
    console.log("The button was clicked.");
}

Delay #

// send notification after 5 sec
var notify = function() {
    console.log("Done!");
}
setTimeout(notify, 5000);

// or

setTimeout(function() {
    console.log("Done!");
}, 5000);

Dialog (Modal) on-load #

Ref: Modals Will Never Be The Same - HTML dialog Element

HTML:

<dialog id="dialog" class="modal">
  <form method="dialog">
    <p>This is a modal which appears immediately at page loading.</p>
    <button type="button" id="dialog--confirm">Confirm</button>
    <button type="button" onclick="location.href='javascript:history.back()'">Go Back</button>
  </form>
<hr />
</dialog>

JS:

document.addEventListener('DOMContentLoaded', function(event) {
  const body = document.body;
  body.classList.add("modal-open");
  const dialog = document.getElementById("dialog");
  dialog.show();

  const button = document.getElementById("dialog--confirm");
  button.addEventListener("click", function(event) {
    dialog.close();
    body.classList.remove("modal-open");
  });
});

Inject CSS #

Ref: Inject CSS stylesheet as string using Javascript - Stack Overflow

/**
 * Utility function to add CSS in multiple passes.
 * @param {string} styleString
 */
function addStyle(styleString) {
  const style = document.createElement('style');
  style.textContent = styleString;
  document.head.append(style);
}

addStyle(`
  body {
    color: red;
  }
`);

addStyle(`
  body {
    background: silver;
  }
`);

javascript - How to copy a HyperText link into clipboard without losing the link properties - Stack Overflow

Tooltip #

Ref: Building a fully-accessible help tooltip – Sara Soueidan, inclusive design engineer

TBA.