Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Parent {
- constructor() {
- this.value = 1;
- }
- print() {
- console.log('Parent.print', this);
- this.printImpl(this.value);
- }
- printImpl(text) { // just so that there's a method called by print to override
- console.log('Parent.printImpl', this);
- console.log(text);
- }
- transform(x) { // crashes if a child doesn't implement doTransform
- console.log('Parent.transform', this);
- console.log(this.doTransform(x)); // 'this' late bound
- }
- }
- class ChildA extends Parent {
- constructor(id) {
- super();
- this.value = 2; // override field
- this.id = id;
- }
- }
- class ChildB extends Parent {
- constructor(id) {
- super();
- this.id = id;
- }
- printImpl(text) { // override method
- console.log('ChildB.printImpl', this);
- console.log(`The value is ${text}`);
- }
- doTransform(x) {
- console.log('ChildB.doTransform', this);
- return x * x;
- }
- }
- console.log('---------- a -----------');
- a = new ChildA('a');
- a.print(); // Prints 'ChildA: 2'
- // Note that the call to this.printImpl in Parent.print goes through the a instance
- // but ends up calling Parent.printImpl with 'this' bound to a
- //a.transform(2); // TypeError: this.doTransform is not a function
- console.log('---------- b -----------');
- b = new ChildB('b');
- b.print(); // prints 'The value is ChildB: 1'
- b.transform(2); // prints 4
- // Side Note: The overall behavior seems consistent with delegation,
- // but there some JS-specific details when it comes to how it's implemented.
- // (1) Fields are owned by the child instances - looks like when you call super,
- // 'this' in the base constructor is bound to the child instance, so fields are added there.
- // (2) Methods defined in the child class (objects own class) are tucked into a "private" prototype object: '__proto__'
- // (3) Inherited methods are on the the prototype of the prototype: '__proto__.__proto__'
- console.log('----------- a.value ----------');
- console.log("a.hasOwnProperty('value')", a.hasOwnProperty('value'));
- console.log("a.__proto__.hasOwnProperty('value')", a.__proto__.hasOwnProperty('value'));
- console.log("a.__proto__.__proto__.hasOwnProperty('value')", a.__proto__.__proto__.hasOwnProperty('value'));
- console.log('----------- b.value ----------');
- console.log("b.hasOwnProperty('value')", b.hasOwnProperty('value'));
- console.log("b.__proto__.hasOwnProperty('value')", b.__proto__.hasOwnProperty('value'));
- console.log("b.__proto__.__proto__.hasOwnProperty('value')", b.__proto__.__proto__.hasOwnProperty('value'));
- console.log('----------- a.printImpl ----------');
- console.log("a.hasOwnProperty('printImpl')", a.hasOwnProperty('printImpl'));
- console.log("a.__proto__.hasOwnProperty('printImpl')", a.__proto__.hasOwnProperty('printImpl'));
- console.log("a.__proto__.__proto__.hasOwnProperty('printImpl')", a.__proto__.__proto__.hasOwnProperty('printImpl'));
- console.log("a.__proto__.__proto__.constructor.name", a.__proto__.__proto__.constructor.name);
- console.log('----------- b.printImpl ----------');
- console.log("b.hasOwnProperty('printImpl')", b.hasOwnProperty('printImpl'));
- console.log("b.__proto__.hasOwnProperty('printImpl')", b.__proto__.hasOwnProperty('printImpl'));
- console.log("b.__proto__.__proto__.hasOwnProperty('printImpl')", b.__proto__.__proto__.hasOwnProperty('printImpl'));
- console.log("b.__proto__.constructor.name", b.__proto__.constructor.name);
- console.log("b.__proto__.__proto__.constructor.name", b.__proto__.__proto__.constructor.name);
- console.log("Calling b.__proto__.printImpl('test')");
- b.__proto__.id = 'b.__proto__';
- b.__proto__.printImpl('test'); // calls the override (with 'this' bound to b.__proto__)
- console.log("Calling b.__proto__.__proto__.printImpl('test')");
- b.__proto__.__proto__.id = 'b.__proto__.__proto__';
- b.__proto__.__proto__.printImpl("test"); // calls the inherited version (with 'this' bound to 'b.__proto__.__proto__')
Advertisement
Add Comment
Please, Sign In to add comment