Table of Contents

Key Concepts in JavaScript

null vs undefined

let myVariable = null; // Intentionally set to null
let myOtherVariable; // Declared but not assigned, so it's undefined

var vs. let

var

Variables declared with var are either function-scoped or global-scoped. var variable can be used before it is declared.

let

Variables declared with let is block scoped {}.

function myFunction() {
  var x = 10; // Function scope
  let y = 20; // Block scope

  if (true) {
    var z = 30; // Function scope
    let w = 40; // Block scope
  }

  console.log(x); // 10
  console.log(y); // 20
  console.log(z); // 30
  console.log(w); // ReferenceError: w is not defined
}

function vs class

In javascript when keyword function is written, it defines not just a function, but also a class with a constuctor which has body of that function.

// Define class `Foo`
function Foo(value){
    console.log(value);
}

// Define instance `foo1` of the class `Foo`
// and call `empty` constructor of the object
var foo1 = new Foo();

// Call `parameterized` constructor of the object
foo1.constructor(123); // 123
foo1.constructor(567); // 567

// Define instance `foo1` of the class `Foo`
// and call `parameterized` constructor of the object
var foo2 = new Foo(111); // 111

// Call `parameterized` constructor of the object
foo2.constructor(222); // 222

prototype

To define [functions](https://en.wikipedia.org/wiki/Function_(computer_programming) inside of class in javascript used keyword prototype.

This means, that method's of the class could be defined later at "runtime", and behavior of the instance of that class could be changed.

function Foo(value){
    console.log(value);
}
// 
// here can be logic
// var foo = new Foo();
// foo.Bar() // Uncaught TypeError: foo.Bar is not a function
//

// Define `method` `Bar` inside of `class` `Foo` 
Foo.prototype.Bar = function(x, y){
    console.log(x + y);
}

var foo = new Foo();
foo.Bar(1, 2); // 3

Equivalent class Foo definition

function Foo(value){
    // Define `method` `Bar` inside of `class` `Foo` 
    this.Bar = function(x, y){
        console.log(x + y);
    }

    console.log(value);
}

var foo = new Foo();
foo.Bar(1, 2); // 3

class fields

function Foo(){
    // Define fields inside of class `Foo`
    this.id = 1;
    this.name  = "Bob";
}

// Define a method inside of Foo class
Foo.prototype.doSmth = function(){
    console.log("work");
}
var foo = new Foo();
console.log(foo.id); // 1
console.log(foo.name); // Bob
foo.doSmth(); // work

Equivalent class definition

// Define instance `foo` of an anonymous class
var foo = {

    // Define fields inside of class `Foo`
    id: 1,

    name: "Bob",

    // Define a method inside of anonymous class
    doSmth() {
        console.log("work");
    }
};
console.log(foo.id); // 1
console.log(foo.name); // Bob
foo.doSmth(); // work

object inheritance

__proto__

In js keyword __proto__ is used for object inheritance.

Comparing to C#, js use object(prototype-based inheritance), while C# use class(class-based inheritance)

In js object consists of fields and a reference to the type, which can be changed durring code execution and object will aquire new methods. In C# object consists of fields, a reference to the type(virtual method table (VMT)) and SyncBlockIndex.

function Foo(){ }

Foo.prototype.doFooWork = function(){
    console.log("foo work");
}

function Bar(){ 
}

Bar.prototype.doBarWork = function(){
    console.log("bar work");
}

var bar = new Bar();

// Now bar has a reference to `VMT` of `Foo`
bar.__proto__ = Foo.prototype
// Other ways to change `reference` of `type` to another `type`:
// bar.__proto__ = Object.create(Foo.prototype);
// bar.__proto__ = new Foo().__proto__;
//
// Make class `Bar` itself be inherited from `Foo` class
// Object.setPrototypeOf(Bar.prototype, Foo.prototype);

bar.doFooWork(); // foo work
bar.doBarWork(); // TypeError: bar.doBarWork is not a function

Instance __proto__ has same address as class type prototype.

function Foo(){ }

var foo = new Foo();

foo.__proto__ === Foo.prototype; // true

Inheritance in JS

function Foo() { }

function Bar() { }

Object.setPrototypeOf(Bar.prototype, Foo.prototype);

with syntax sugar

class Foo {} 

class Bar extends Foo {}

class Function

In js each class is inherited from Function class.
In C# each class is inherited from Object class.

Function has methods call, bind, apply. Methods like call(), apply(), and bind() can refer this to any object.

call()

call() calls a method from another object.

const person = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}
const person1 = {
  firstName:"John",
  lastName: "Doe"
}

person.fullName.call(person1); // Jonh Doe

apply()

apply() calls a method from another object.

const person = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}

const person1 = {
  firstName: "Mary",
  lastName: "Doe"
}

person.fullName.apply(person1); // Mary Doe
call() vs apply()

The call() method takes arguments separately.
The apply() method takes arguments as an array.

bind()

With the bind() method, an object can borrow a method to another object.

const person = {
  firstName:"John",
  lastName: "Doe",
  fullName: function () {
    return this.firstName + " " + this.lastName;
  }
}

const member = {
  firstName:"Hege",
  lastName: "Nilsen",
}

let fullName = person.fullName.bind(member);
fullName(); // Hege Nilsen

Closures

Variables declared with var are either function-scoped or global-scoped.

function Foo(){
    // function-scoped
    var name = "Bob";

    function Bar(){
        console.log(name);
    }

    Bar();
}

Foo(); // Bob

Callback trick

function Bar(value, callback){
    console.log("Bar enter.. " + value);

    setTimeout(() => {
        value++;
        console.log("Bar: Long running job...");

        callback(value);
    }, "1000");

    console.log("Bar exit.. " + value);
}

function Foo(){
    function CallBack(value){
        console.log("CallBack: " + value);
    }

    let value = 10; 
    let callBack = CallBack;

    console.log("Foo: before `Bar` " + value);
    Bar(value, callBack);
    console.log("Foo: after `Bar` " + value);
}

Foo();
// Foo: before `Bar` 10
// Bar enter.. 10
// Bar exit.. 10
// Foo: after `Bar` 10
// ..
// Bar: Long running job...
// CallBack: 11

The event loop

To execute functions js runtime use Queue. Js runtime puts function's into the queue and executes them one by one. As a result, the next function in the queue does not start until the current one finishes executing.

function Bar() {
    console.log("Bar: ...");
}
function Foo(){
    console.log("Foo: stat..");
    let bar = Bar;

    // Timeout: 0ms
    setTimeout(bar, 0)

    // Intensive work
    for(let i = 0; i < 10000; i++) { }

    console.log("Foo: end..");
}

Foo();
// Foo: stat..
// Foo: end..
// Bar: ...