• https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors
  • https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS
  • https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
  • http://crockford.com/javascript/prototypal.html
  • http://javascript.info/class-patterns
  • https://dmitripavlutin.com/gentle-explanation-of-this-in-javascript/
  • http://crockford.com/javascript/private.html
  • https://www.gamedev.net/blogs/entry/2265481-oop-is-dead-long-live-oop/
function Runner(name) {
  console.log(this instanceof Rabbit); // => true
  this.name = name;
}
function Rabbit(name, countLegs) {
  console.log(this instanceof Rabbit); // => true
  // Indirect invocation. Call parent constructor.
  Runner.call(this, name);
  this.countLegs = countLegs;
}
var myRabbit = new Rabbit('White Rabbit', 4);
myRabbit; // { name: 'White Rabbit', countLegs: 4 }

function Vehicle(type, wheelsCount) {
  if (!(this instanceof Vehicle)) {
    throw Error('Error: Incorrect invocation');
  }
  this.type = type;
  this.wheelsCount = wheelsCount;
  return this;
}
// Constructor invocation
var car = new Vehicle('Car', 4);
car.type               // => 'Car'
car.wheelsCount        // => 4
car instanceof Vehicle // => true
// Function invocation. Generates an error.
var brokenCar = Vehicle('Broken Car', 3);
function Foo () {
  console.log(this instanceof Foo); // => true
  this.property = 'Default Value';
}
// Constructor invocation
var fooInstance = new Foo();
fooInstance.property; // => 'Default Value'
function Foo () {
  console.log(this instanceof Foo); // => true
  this.property = 'Default Value';
}
// Constructor invocation
var fooInstance = new Foo();
fooInstance.property; // => 'Default Value'

vs.

class Bar {
  constructor() {
    console.log(this instanceof Bar); // => true
    this.property = 'Default Value';
  }
}
// Constructor invocation
var barInstance = new Bar();
barInstance.property; // => 'Default Value'
function multiply(number) {
  'use strict';
  return this * number;
}
// create a bound function with context
var double = multiply.bind(2);
// invoke the bound function
double(3);  // => 6
double(10); // => 20

Contrary to .apply() and .call() methods (see 5.), which invokes the function right away, the .bind() method only returns a new function that it supposed to be invoked later with a pre-configured this. .bind() makes a permanent context link and will always keep it. A bound function cannot change its linked context when using .call() or .apply() with a different context, or even a rebound doesn’t have any effect.

var numbers = {
  array: [3, 5, 10],
  getNumbers: function() {
    return this.array;
  }
};
// Create a bound function
var boundGetNumbers = numbers.getNumbers.bind(numbers);
boundGetNumbers(); // => [3, 5, 10]
// Extract method from object
var simpleGetNumbers = numbers.getNumbers;
simpleGetNumbers(); // => undefined or throws an error in strict mode

Because the function invocation has the biggest impart on this, from now on do not ask yourself:

Where is this taken from?

but do ask yourself:

How is the function invoked?

For an arrow function ask yourself:

What is this where the arrow function is defined?

JavaScript is kind of funny.

See you next time!

Unless otherwise mentioned in the post, those projects are side projects which I work on on weekends and evenings, and are not affiliated with my work or employer.