Javascript is a language having a form of inheritance which is called prototypal inheritance.
The idea behind it is that given an object, it has an hidden property called prototype which is a reference to another object, which is said to be the prototype object.
This relationship is important when you ask the javascript engine to give you the value of an object property, let's call it foo just to fix the idea. The javascript engine will first check your object to see if it has a property called foo: if the property is defined on your object its value is returned and the search completes. If, otherwise, your object doesn't have a property called foo then its prototype object is searched and the same process is repeated again.
This procedure is repeated recursively until all the so called prototype chain has been explored. The root of the prototype chain is a built-in javascript object that you can reference with the expression Object.prototype and is the object from which all the other javascript objects derive. Notice that, if the foo property is missing in all the objects composing the entire prototype chain, then the value undefined is returned.
This is the real form of inheritance built into javascript and it's the business which really seats behind the ES6 class keywork which is a convenience which hides this mess and gives you the impression that javascript has a form of class inheritance (class inheritance is more widely known and most of programmers find it easier to think of than prototypal inheritance).
The bare minimum that you can do in order to take an object and decide that it should behave like an array is the following:
const myArray = [];
const myObject = { foo: "bar" }
Object.setPrototypeOf(myObject, myArray);
myObject.push("hello");
myObject.push("world");
console.log(myObject.length); // prints 2
This book is the best reference that I know for the javascript language. This is good too, but nowdays is a bit outdated and it's not as easy to follow along as the previous.
An example a bit more involved than the previous one can be implemented by using a function as a constructor. This is actually the ES5 old-school way to implement class-like inheritance, the thing that you did at the time of ES5 in order to mimic classes:
function SpecialArray(name) {
this.name = name;
}
SpecialArray.prototype = [];
// fix the constructor property mess (see the book linked above)
Object.defineProperty(SpecialArray.prototype, "constructor", {
value: SpecialArray,
enumerable: false,
writable: true
});
SpecialArray.prototype.getSalutation = function() {
return "Hello my name is " + this.name;
};
const mySpecialArray = new SpecialArray("enrico");
// you can call the methods and properties defined on Array.prototype
mySpecialArray.push("hello");
mySpecialArray.push("world");
console.log(mySpecialArray.length); // prints 2
// you can use the methods and properties defined on SpecialArray.prototype
console.log(mySpecialArray.name); // prints enrico
console.log(mySpecialArray.getSalutation()); // prints Hello my name is enrico
// important sanity checks to be sure that everything works as expected
console.log(mySpecialArray instanceof Array); // prints true
console.log(mySpecialArray instanceof SpecialArray); // prints true
console.log(mySpecialArray.constructor === SpecialArray); // prints true
// you can iterate over the special array content
for (item of mySpecialArray){
console.log(item);
}
// you can read special array entries
console.log(mySpecialArray[1]); // prints world