JavaScript notes

Scope

  • Hoisted mean the declaration is effectively at the beginning of the scope, so it can even be accessed before its declaration. However the value relies on the definition. Both variable and function declarations are hoisted.
function test() {
  console.log(a);
  console.log(foo());
  var a = 1;
  function foo() {
    return 2;
  }
}
test();

is equivalent to:

function test() {
  var a;
  function foo() {
    return 2;
  }
  console.log(a);
  console.log(foo());
  a = 1;
}
test();
  • Function declarations are hoisted.
  • Class declarations are hoisted.
  • If no semicolon at the end of the line, one will be added automatically.

Data Type

  • Primitive
    • Boolean
    • Null
      • typeof null === 'object'
    • Undefined
    • Number
      • type of NaN === 'number'
      • Use Number.isNaN instead of isNaN, as the latter coerces the type of argument
      • Convert variable to a Number object: Number(var)
      • As numbers are all double-precision floating point, to achieve accurate result, scaling numbers with fractions to integers. Because integer arithmetic is accurate.
      • Use parseInt / Number.parseInt (ES6+) to convert number of another radix to decimal.
    • String
    • Symbol (ES6)
  • Object
    • Array
      • Array.isArray
    • Function
  • Equality
    • Primitives like strings and numbers are compared by their value, while objects like arrays, dates, and plain objects are compared by their reference.

Function

  • An arrow function does not have its own this; the this value of the enclosing lexical context is used i.e. Arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope they end up finding this from its enclosing scope .

Class

ES5

/*
 * Parent class, should be abstract
 */
function PageElement() {
  this._$loadingIndicator = null;
  this._disabled = false;
}
// instance methods, _ prefix by convention means private
PageElement.prototype._showLoading = function ($element) {
  this._$loadingIndicator = IU.addWaitingIndicatorToElement($element);
  return this._$loadingIndicator;
};
PageElement.prototype._createIndicator = function (id) {
  this._$loadingIndicator = IU.createWaitingIndicator(id);
  return this._$loadingIndicator;
};
PageElement.prototype._hideLoading = function () {
  if (this._$loadingIndicator) {
    IU.removeIndicator(this._$loadingIndicator);
  }
};
PageElement.prototype._toggle = function ($element, state) {
  $element.prop("disabled", !state);
};
 
/*
 * Child class, should be abstract
 */
function Button(selector, container) {
  // Constructor
  this._selector = selector; // fields
  this._$container = container;
  this._$btn = this._$container.find(this._selector);
}
Button.prototype = Object.create(PageElement.prototype);
var ub = Button.prototype;
ub.constructor = Button; // correct the constructor property
 
// instance methods
ub.hide = function () {
  this._$container.hide();
};
ub.show = function () {
  this._$container.show();
};
ub.disable = function () {
  this._toggle(this._$btn, false);
};
ub.enable = function () {
  this._toggle(this._$btn, true);
};
 
/*
 * Grand-child class, concrete class
 */
AddCommentBtn.prototype = Object.create(Button.prototype);
var ap = AddCommentBtn.prototype;
ap.constructor = AddCommentBtn;
ap._onClick = function () {
  this.hide();
  this._expandedSection.showCommentTextInput();
};
ap.freeze = function () {
  this._$btn.toggleClass("disabled", true);
  this._disabled = true;
};
ap.unfreeze = function () {
  this._$btn.toggleClass("disabled", false);
  this._disabled = false;
};

ES6

class PageElement {
  constructor() {
    this._$loadingIndicator = null;
    this._disabled = false;
  }
 
  _showLoading($element) {
    this._$loadingIndicator = IU.addWaitingIndicatorToElement($element);
    return this._$loadingIndicator;
  }
 
  _createIndicator(id) {
    this._$loadingIndicator = IU.createWaitingIndicator(id);
    return this._$loadingIndicator;
  }
 
  _hideLoading() {
    if (this._$loadingIndicator) {
      IU.removeIndicator(this._$loadingIndicator);
    }
  }
 
  _toggle($element, state) {
    $element.prop("disabled", !state);
  }
}
 
class Button extends PageElement {
  constructor(selector, container) {
    super();
    this._selector = selector; // fields
    this._$container = container;
    this._$btn = this._$container.find(this._selector);
  }
 
  hide() {
    this._$container.hide();
  }
 
  show() {
    this._$container.show();
  }
 
  disable() {
    this._toggle(this._$btn, false);
  }
 
  enable() {
    this._toggle(this._$btn, true);
  }
}
 
class AddCommentBtn extends Button {
  _onClick() {
    this.hide();
    this._expandedSection.showCommentTextInput();
  }
 
  freeze() {
    this._$btn.toggleClass("disabled", true);
    this._disabled = true;
  }
 
  unfreeze() {
    this._$btn.toggleClass("disabled", false);
    this._disabled = false;
  }
}

Iterable

  • Iterator: has a next method, which returns an iteratorResult object with two properties value and done
  • Iterable: has a method with Symbol.iterator as the key
  • All iterators created by generators are also iterables
  • Three types in TypeScript syntax
interface Iterable {
  [Symbol.iterator](): Iterator;
}
interface Iterator {
  next(): IteratorResult;
}
interface IteratorResult {
  value: any;
  done: boolean;
}

Generator

  • Call it once and get the handle to operate upon it
  • Generating iterables
let o = {};
o[Symbol.iterator] = function* () {
  yield* [1, 2, 3, 4, 5];
};
for (let e of o) {
  info(e);
}

ESM

Destructuring

  • Assign Variables from Objects

    const user = { name: "John Doe", age: 34 };
    const { name: userName, age: userAge } = user;
    // userName = 'John Doe', userAge = 34
  • Assign Variables from Nested Objects

    const user = {
      johnDoe: {
        age: 34,
        email: "johnDoe@freeCodeCamp.com",
      },
    };
    const {
      johnDoe: { age, email },
    } = user;
  • Assign Variables from Arrays

    • In the order of array elements, unneeded elements omitted
    const [a, b, , , c] = [1, 2, 3, 4, 5, 6];
    console.log(a, b, c); // 1, 2, 5
    • Swap variable values:
    let a = 8;
    let b = 6;
    [b, a] = [a, b];
    console.info(a, b); // 6, 8
    • Use Rest Parameter
    const [a, b, ...arr] = [1, 2, 3, 4, 5, 7];
    console.log(a, b); // 1, 2
    console.log(arr); // [3, 4, 5, 7]
  • Pass an Object as a Function's Parameters

    // No Destructuring
    const profileUpdate = (profileData) => {
      const { name, age, nationality, location } = profileData;
      // do something with these variables
    };
    // Destructuring
    const profileUpdate = ({ name, age, nationality, location }) => {
      /* do something with these fields */
    };

Asynchronous Programming

Async/Await

API

Object

Array

  • array.sort()
    • Algorithm of array.sort() is implementation dependent.
    • compareFunction if omitted, the array is sorted according to each character's Unicode code point value, according to the string conversion of each element.
  • array.splice()
    • array.splice(startIndex, [deleteCount]), if deleteCount is omitted, all elements starting from startIndex will be deleted.
    • The method has side effects on the array, therefore indices of elements are subject to change after the method call.

string

  • convert to an array of characters

    • ES6

      • Spread operator

        [...'hello']

      • Array.from()

        Array.from('hello')

DOM

Resources