In object oriented programming, a private field is a field that can only be altered by methods of a its class. although JavaScript does not have a working private keyword, to achieve this, we can hide a variable inside a closure preventing its use from the outside.
function counter(start) { return { get next() { return start++; } }; } var id = counter(0); console.log(id.next); console.log(id.next); console.log(id.next);
Monkey patching is when you replace a function with a function that runs some code before and or after calling the original function. The following example is a function that is able to patch other functions to log each call.
function log(f) { return function () { var args = [].slice.call(arguments); var result = f.apply(null, args); console.log(f.name + '(' + args.join(', ') + ') = ' + result); return result; } } function fibonacci(n) { if (n == 0) return 0; if (n == 1) return 1; return fibonacci(n - 1) + fibonacci(n - 2); } fibonacci = log(fibonacci); fibonacci(5);
There wasn't a super keyword in JavaScript until ES6, but we could still call the method of the parent class using monkey patching or using the prototype of the parent class.
function Counter(start) { this.start = start; } Counter.prototype.count = function () { return this.start++; } function DoubleCounter(start) { // Calling the constructor of the super class Counter.call(this, start); } DoubleCounter.prototype = Object.create(Counter.prototype); DoubleCounter.prototype.constructor = DoubleCounter; DoubleCounter.prototype.count = function () { // Calling method of the super class return 2 * Counter.prototype.count.call(this); } var doubleCounter = new DoubleCounter(1); console.log(doubleCounter.count()); console.log(doubleCounter.count());
class Counter { constructor(start) { this.start = start; } count() { return this.start++; } } class DoubleCounter extends Counter { constructor(start) { super(start); } count() { return 2 * super.count(); } } var doubleCounter = new DoubleCounter(1); console.log(doubleCounter.count()); console.log(doubleCounter.count());
function counter(start) { function count() { return start++; } return {count: count}; } function doubleCounter(start) { var simple = counter(start); function count() { return 2 * simple.count(); } return {count: count}; } var doubleCounter = doubleCounter(1); console.log(doubleCounter.count()); console.log(doubleCounter.count());
Inheritance allows us to share code between classes. If two classes have many common features and we can say that one class is a type of another class, then we can use inheritance to make the more specific class use code from the more generic class.
As an example think about the classes bird and duck. Duck is a type of bird and we expect that a duck can do everything that a bird can do like flying. So we make the class duck inherit the class bird. By doing that we need to write the method fly only once.
Composition is an alternative to inheritance. Instead of sharing fields with the super class we instead add an instance of the super class as a new field. This allows us to not worry about having fields of the super and sub classes with the same name.
function Bird() {} Bird.prototype.fly = function () { console.log("Zoom!"); }; function Duck() {} Duck.prototype = Object.create(Bird.prototype); Duck.prototype.construtcor = Duck; Duck.prototype.swim = function () { console.log("Splash!"); }; var donald = new Duck(); donald.swim(); donald.fly();
class Bird { fly() { console.log("Zoom!"); } } class Duck extends Bird { swim() { console.log("Splash!"); } } var donald = new Duck(); donald.swim(); donald.fly();
function bird() { function fly() { console.log("Zoom!"); } return {fly: fly}; } function duck() { function swim() { console.log("Splash!"); } return {swim: swim, bird: bird()}; } var donald = duck({}); donald.swim(); donald.bird.fly();
Mixins are multiple inheritances, it happens when a class is a type of two other classes, and those two other classes are not a type of each other.
As an example think of the Pooh bear. It is a talking bear. Since not all bears talk, and not all taking things are bears, we can't just use simple inheritance because Pooh needs to inherit from both classes.
In my personal approach I used composition instead of inheritance. Polymorphism in JavaScript makes little sense, since variables are not locked to a type. And composition allows me to avoid name clashes that happens when the sub class has fields named after the super classes.
function union(a, b) { var c = {}; for (var i in a) c[i] = a[i]; for (var i in b) c[i] = b[i]; return c; } function Bear() {} Bear.prototype.eat = function (food) { console.log(food + ", yummy!"); }; function Talking() {} Talking.prototype.say = function (message) { console.log(message); }; function TalkingBear() {} TalkingBear.prototype = Object.create(union(Bear.prototype, Talking.prototype)); TalkingBear.prototype.constructor = TalkingBear; var pooh = new TalkingBear(); pooh.eat("Honey"); pooh.say("Hello");
function bear() { function eat(food) { console.log(food + ", yummy!"); } return {eat: eat}; } function talking() { function say(message) { console.log(message); } return {say: say}; } function TalkingBear() { return {bear: bear(), talking: talking()}; } var pooh = TalkingBear(); pooh.bear.eat("Honey"); pooh.talking.say("Hello");
Since JavaScript is single threaded most API is asynchronous. In this case, the result of the API is not ready in the line following the call, it is only ready in the callback function you pass to the API.
A common problem with callbacks arises when you try to access data inside the callback or pass some specific data for each callback.
var array = [1, 2, 3, 4]; for (var i = 0; i < array.length; ++i) { setTimeout(function () { console.log(array[i]); }); }
Here, only undefined
is printed, because all functions have
a reference to the variable i
with the value after the end
of the loop. Callbacks rarely run immediately, and in this case, all
callbacks are run after the loop.
var array = [1, 2, 3, 4]; array.forEach(function (i) { setTimeout(function () { console.log(i); }); });
Here, for each element of the array a new function is called with the
value of the array as argument. The variable is always called
i
, but each i
is unique since it holds a
different value.
var array = [1, 2, 3, 4]; for (var i = 0; i < array.length; ++i) { setTimeout(function (i) { return function () { console.log(array[i]); } }(i)); }
Another way to solve this problem is to use a function that takes the argument that we want to pass to our callback and returns a newly created callback. The callback can access the variable of its parent function because it is in its closure.
var array = [1, 2, 3, 4]; for (var i = 0; i < array.length; ++i) { setTimeout(function (i) { console.log(array[i]); }.bind(null, i)); }
Partial application is the process of fixing the value of some argument
to a function reducing its arity (number of arguments it takes). In this
example the argument i
is fixed by bind
to the
value of each iteration.
var array = [1, 2, 3, 4]; for (let i = 0; i < array.length; ++i) { setTimeout(function () { console.log(array[i]); }); }
The keyword var
in JavaScript defines variables in lexical
scope, they are available everywhere in the function. The keywords
let
and const
in the other hand define
variables with block scope, so they are only available inside the block.
function Bear(color) { this.color = color; } Bear.prototype.eat = function (food) { var self = this; // warning: easy to forget. setTimeout(function () { // this.color won't have the string here without bind. console.log("A " + self.color + " bear ate " + food + "."); }, 3000); return this; }; (new Bear("gray")).eat("honey");
this
is a reference to an instance of Bear
only if the function is called from the object, but the callback is
called in a different context usually not as a method, so the value of
this
is the global object.
class Bear { constructor(color) { this.color = color; } eat(food) { setTimeout(() => { console.log("A " + this.color + " bear ate " + food + "."); }, 3000); } } (new Bear("gray")).eat("honey");
Different than functions, lambdas use the value of this
of
its parent. In this case the parent of our callback is a regular method
with the proper value of this
set.
function bear(color) { function eat(food) { setTimeout(function () { // color is available here via closure console.log("A " + color + " bear ate " + food + "."); }, 3000); } return {eat: eat}; } bear('gray').eat('honey');
It is not always necessary to use this
to access the state
of your objects. Another way to create objects is to keep the state in
the closure, this way the keyword this
is not necessary and
the state of the object becomes private.