In js functions are high order function and objects at the same time.

Closures

Example:

function a() {
  let grandpa = 'grandpa';
  return function () {
    let father = `father`;
    return function () {
      let son = 'son';
      return `${grandpa} > ${father} > ${son}`;
    };
  };
}

console.log(a()()());

Closures allow function to access to the variables from the lexical scope even when they are called outside of this lexical scope.

Consider the following piece of code:

const array = [1, 2, 3, 4];
for (var i = 0; i < array.length; i++) {
  setTimeout(function () {
    console.log("I'm at index " + i);
  }, 10);
}

It returns 4 times 'I'm at index 4'. The easiest way to fix it is to change var to let i = 0. Because let works with block scopes. The another solution (if we can’t use let for some reason), we can use closure with IIEF:

const array = [1, 2, 3, 4];
for (var i = 0; i < array.length; i++) {
  (function(c) {
    setTimeout(function () {
      console.log("I'm at index " + c);
    }, 10);
  })(i);
}

Prototypes

We can get an access to base object (prototype) by obj.__proto__.

See on the following code:

let dragon = {
  name: 'Tanya',
  fire: true,
  fight() {
    return 5;
  },
  sing() {
    let message = this.fire
      ? `I'm ${this.name}, the breather of fire`
      : `I'm ${this.name}`;
    console.log(message);
    return message;
  },
};

let lizard = {
  name: 'Kiki',
};

dragon.sing();

We can make dragon object to be the base object of a lizard the following way:

lizard.__proto__ = dragon;

But we shouldn’t use it, because of bad performance.

We can check if one object is prototype of another we can use isPrototypeOf function:

dragon.isPrototypeOf(lizard)

We can check if property is own by lizard.hasOwnPropery(prop):

for (let prop in lizard) {
  if (lizard.hasOwnProperty(prop)) {
    console.log('Prop: ', prop);
  }
}

Ways to inherit

First:

let lizard = Object.create(dragon);

Prototype property

Only functions have a prototype property.

Object is a function. Object.prototype is a base object.

How we can modify existing functionalty:

Date.prototype.lastYear = function () {
  return this.getFullYear() - 1;
};

let date = new Date('1900-10-10');
console.log(date.lastYear());