Skip to content

Instantly share code, notes, and snippets.

@jooeycheng
Last active February 11, 2021 06:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jooeycheng/78f80cc8c6d0a8db4e2096d902f69301 to your computer and use it in GitHub Desktop.
Save jooeycheng/78f80cc8c6d0a8db4e2096d902f69301 to your computer and use it in GitHub Desktop.
My JavaScript notes, excerpts from https://javascript.info/

Import/Export

export let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

export const MODULES_BECAME_STANDARD_YEAR = 2015;

export function sayHi() { ... }

export class User {
  constructor(name) {
    this.name = name;
  }
}

// named export
export class User {...}
import {User} from ...

// default export
export default class User {...}
import User from ...
import {sayHi, sayBye} from './say.js';
sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!

import * as say from './say.js';
say.sayHi('John');
say.sayBye('John');

Data Types

number
bigint
string
boolean
null
undefined
object
symbol
function

Exception Handling

try {
  // stuff
} catch(err) {
  // stuff
  if (err instanceof ValidationError) {
    // stuff
  } else {
    throw err // re-throw it
  }
} finally {
  // stuff
}

// generic error with custom message
throw new Error("Negative water")

// custom error class
class ValidationError extends Error {
  constructor(message) {
    super(message)
    this.name = "ValidationError"
  }
}

JSDoc

/**
 * Returns x raised to the n-th power.
 *
 * @param {number} x The number to raise.
 * @param {number} n The power, must be a natural number.
 * @return {number} x raised to the n-th power.
 */
function pow(x, n) {
  ...
}

Functions

function sayHi() {
  alert("Hello")
}

sayHi() // "Hello"

let sayHi2 = sayHi
sayHi2() // "Hello"
function Calculator() {

  this.read = function() {
    this.a = +prompt('a?', 0);
    this.b = +prompt('b?', 0);
  };

  this.sum = function() {
    return this.a + this.b;
  };

  this.mul = function() {
    return this.a * this.b;
  };
}

let calculator = new Calculator();
calculator.read();

alert( "Sum=" + calculator.sum() );
alert( "Mul=" + calculator.mul() );
  • Constructor functions • Link

Array

  • push(...items) adds items to the end.
  • pop() removes the element from the end and returns it.
  • shift() removes the element from the beginning and returns it.
  • unshift(...items) adds items to the beginning.

Destructuring Assignment

let [firstName, surname] = "Ilya Kantor".split(' ')

// unwanted elements of the array can be discarded via an extra comma
let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]

// works with any iterable on the right-side
let [a, b, c] = "abc" // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3])

// default values
let [name = "Guest", surname = "Anonymous"] = ["Julius"];
let options = {
  title: "Menu",
  width: 100,
  height: 200
};

let {title, width, height} = options;

// default values
let {width = 100, height = 200, title} = options;

// rest pattern "..."
let {title, ...rest} = options;
title // "Menu"
rest // { height: 200, width: 100 }


// nested
let options = {
  size: {
    width: 100,
    height: 200
  },
  items: ["Cake", "Donut"],
  extra: true
};

let {
  size: { // put size here
    width,
    height
  },
  items: [item1, item2], // assign items here
  title = "Menu" // not present in the object (default value is used)
} = options

alert(title)  // Menu
alert(width)  // 100
alert(height) // 200
alert(item1)  // Cake
alert(item2)  // Donut
// functions
function({
  incomingProperty: varName = defaultValue
  ...
})

// example
let options = {
  title: "My menu",
  items: ["Item1", "Item2"]
}

function showMenu({
  title = "Untitled",
  width: w = 100,  // width goes to w
  height: h = 200, // height goes to h
  items: [item1, item2] // items first element goes to item1, second to item2
}) {
  alert( `${title} ${w} ${h}` ) // My Menu 100 200
  alert( item1 ) // Item1
  alert( item2 ) // Item2
}

Loops

// 1. while
while (condition) {
  // stuff
}

// 2. do..while
do {
  // stuff
} while (condition)

// 3. for (;;)
for (let i = 0; i < 3; i++) {
  i // 0, then 1, then 2
}

// 4a. for..in (with array)
let arr = ["Apple", "Orange", "Pear"]
for (let i in arr) {
  i // 0, then 1, then 2
  alert( arr[i] ) // Apple, Orange, Pear
}

// 4b. for..in (with object)
let user = { name: "John" }
for (let key in user) {
  key // "name"
  user[key] // "John"
}

// 5a. for..of (with array or string)
for (let char of "Hello") {
  alert(char); // "H", then "e", then "l", etc
}

// 5b. for..of (with object)
for (const [k, v] of Object.entries(obj)) {
  console.log(k, v);
}

// 6. forEach (with array)
let arr = ["Apple", "Orange", "Pear"]
arr.forEach((item, index, arr) => {
  item // 65, then 44, then 12
  index // 0, then 1, then 2
  arr // ["Apple", "Orange", "Pear"]
});

// break, continue
break
continue

// loop labelling for specific break/continue
outer: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {

    if (!input) break outer;
  }
}

Objects

let user = {
  name: "John",
  age: 30,
  "likes birds": true
}

/**
 * Set
 */
user.name = "Jane"
user["likes birds"] = false

/**
 * Set key via variable (method 1)
 */
let fruit = "apple"
let bag = {}
bag[fruit] = 5

bag // { apple: 5 }

/**
 * Set key via variable (method 2)
 */
let bag = {
  [fruit]: 5
}

bag // { apple: 5 }

/**
 * Set key and value directly (shorthand syntax)
 */
let name = "John", age = 1;
let user = {
  name,
  age
}

user // { name: "John", age: 1 }

/**
 * Set key to a function (method 1)
 */
user = {
  sayHi: function() {
    alert("Hello")
  }
}

/**
 * Set key to a function (method 2, shorthand)
 */
user = {
  sayHi() {
    alert("Hello")
  }
}

/**
 * Get
 */
user.name    // "John"
user["name"] // "John"

/**
 * Using `this` within an object
 * Note:
 *   Arrow functions have no `this`, it will reference the outer "normal" function
 */
let user = {
  name: "John",
  age: 30,

  sayHi() {
    alert(this.name) // `this` is the "current object"
  }
}
user.sayHi() // "John"

/**
 * Check if key exists (method 1)
 * Use triple equal, bcos double equal will match against null (false positive)
 */
object.exampleKey === undefined // true|false

/**
 * Check if key exists (method 2)
 */
"exampleKey" in object // true|false

/**
 * Delete
 */
delete user.name
delete user["likes birds"]

/**
 * Iterate through keys with for..in loop
 */
let user = { name: "John" }
for (let key in user) {
  key // "name"
  user[key] // "John"
}
  • Object keys are "ordered in a special fashion". Integer keys are sorted, others appear in creation order • Link
  • When an object variable is copied - the reference is copied, the object is not duplicated • Link
  • Clone and merge objects with Object.assign. If object contains nested objects, must "deep clone", or use lodash.cloneDeep library • Link
  • Two objects are equal only if they are the same object • Link
  • Understanding this in methods and objects • Link

Symbols

Symbol is a primitive type for unique identifiers. Link

JavaScript symbols are entirely different from Ruby. Don't confuse them.

/**
 * Symbols are guaranteed to be unique.
 * Even if we create many symbols with the same description, they are different values.
 * The description is just a label that doesn’t affect anything.
 */
let id1 = Symbol("id")
let id2 = Symbol("id")
alert(id1 == id2) // false

/**
 * Symbols don’t auto-convert to a string
 */
let id = Symbol("meow")
alert(id) // TypeError: Cannot convert a Symbol value to a string
alert(id.toString())  // "Symbol(meow)"
alert(id.description) // "meow"

/**
 * Global symbols
 */
// read from the global registry
let id = Symbol.for("id") // if the symbol did not exist, it is created

// read it again (maybe from another part of the code)
let idAgain = Symbol.for("id")

// the same symbol
alert( id === idAgain ) // true

// reverse of `Symbol.for(key)`
let sym = Symbol.for("id")
alert( Symbol.keyFor(sym) ) // "id"
  • Symbols allow us to create “hidden” properties of an object, that no other part of code can accidentally access or overwrite Link
  • Symbol keys in object are skipped by for..in loop Link

Decorators

Decorator is simply a way of wrapping one piece of code with another - literally “decorating” it. Guide

class Example {
  @log
  sum(a, b) {
    return a + b;
  }
}

const e = new Example();
e.sum(1, 2);
// Arguments: 1,2
// Result: 3
function log(target, name, descriptor) {
  const original = descriptor.value;
  if (typeof original === 'function') {
    descriptor.value = function(...args) {
      console.log(`Arguments: ${args}`);
      try {
        const result = original.apply(this, args);
        console.log(`Result: ${result}`);
        return result;
      } catch (e) {
        console.log(`Error: ${e}`);
        throw e;
      }
    }
  }
  return descriptor;
}

Rest Parameters, Spread Operator

Guide

function(...args) {
  console.log(`Arguments: ${args}`);
}

(draft) Making Functions Private

When importing in ES6, all functions become available by default. To make a function private to prevent importing, use the “function-as-variable” hack, because variables cannot be imported.

// assigning function definition to a variable.
// same outcome, same usage, but sort of like a "private method", instead of "public method".
let myFunc = () => {}

Others

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment