Some older discussions on Javascript prototypal inheritance & delegation can be found below:
- Benefits of prototypal inheritance over classical?
- classical inheritance vs prototypal inheritance in javascript
I am curious about the current (2018) recommendations for using prototypes / prototypal inheritance in JavaScript.
It seems that newer versions of JavaScript (ES6) and TypeScript lean more towards traditional class-based inheritance. (I have yet to use ES6 or TS in practice.) Is this observation correct?
The class-based code example provided is straightforward and easy to grasp:
class A { a: "a" }
class B extends A { b: "b" }
let a = new A(), b = new B();
EDIT 2: In TypeScript, it would look like this:
class A { a = "a" }
class B extends A { b = "b" }
let a = new A(), b = new B();
EDIT: The ES6 syntax is slightly more complex:
class A { constructor() { this.a = "a"; } }
class B extends A { constructor() { super(); b = "b"; } }
let a = new A(), b = new B();
For using prototypes, there are more options available but finding one as simple and clean as class-based inheritance proves challenging.
EDIT: My goal is to create an instance of B with prototype A in a way that updates to A dynamically reflect in B:
A basic approach is shown here:
var A = { a: "a" }
var B = Object.create(A, {b: {value: "b"}});
var a = Object.create(A), // direct instance of A
b = Object.create(B); // indirect instance of A
console.log(b.a); // "a"
A.a = "a++";
console.log(b.a); // "a++"
An improvement could be simplifying the object creation process by allowing key-value pairs instead of property descriptors.
Typically, constructor functions are used for prototypal inheritance as outlined in this article.
function A() { this.a = "a"; }
function B() { this.b = "b"; }
B.prototype = new A();
var a = new A(), b = new B();
console.log(b.a); // "a"
A.a = "a++";
console.log(b.a); // return "a" instead of "a++" as b.a is overwritten in constructor
Unfortunately, this method does not allow changes to A.a to automatically update B.a, which is crucial in prototypal inheritance. Perhaps this alternative could work:
function A() {}
A.prototype.a = "a";
function B() {}
B.prototype = Object.create(A.prototype);
B.prototype.b = "b";
var a = new A(), b = new B();
This also falls short of expectations. It's evident that such manual manipulation is not ideal.
One option is to encapsulate these behaviors in constructor functions, as discussed in this post. However, it still lacks the simplicity and elegance of the class syntax. I'm searching for a solution akin to Kotlin's object declaration:
object A { a: "a" }
object B extends A { b: "b" }
let a = new A(), b = new B();
What approach do you suggest? Is there a better alternative out there?
Especially for those seeking encapsulation and private object members inaccessible to cloned objects?
Does TypeScript offer a viable solution?
Should we consider Kotlin as a potential alternative?
Or is reverting back to class-based inheritance due to its wider acceptance and understanding the best course of action?