Guest User

JS Prototype-Based Inheritance

a guest
Oct 10th, 2019
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. class Parent {
  2.   constructor() {
  3.     this.value = 1;
  4.   }
  5.  
  6.   print() {
  7.     console.log('Parent.print', this);
  8.     this.printImpl(this.value);  
  9.   }
  10.  
  11.   printImpl(text) {   // just so that there's a method called by print to override
  12.     console.log('Parent.printImpl', this);
  13.     console.log(text);
  14.   }
  15.  
  16.   transform(x) {   // crashes if a child doesn't implement doTransform
  17.     console.log('Parent.transform', this);
  18.     console.log(this.doTransform(x));      // 'this' late bound
  19.   }
  20. }
  21.  
  22. class ChildA extends Parent {
  23.   constructor(id) {
  24.     super();
  25.     this.value = 2;       // override field
  26.     this.id = id;
  27.   }
  28. }
  29.  
  30. class ChildB extends Parent {
  31.   constructor(id) {
  32.     super();
  33.     this.id = id;
  34.   }
  35.  
  36.   printImpl(text) {            // override method
  37.     console.log('ChildB.printImpl', this);
  38.     console.log(`The value is ${text}`);
  39.   }
  40.    
  41.   doTransform(x) {
  42.     console.log('ChildB.doTransform', this);
  43.     return x * x;
  44.   }
  45. }
  46.  
  47. console.log('---------- a -----------');
  48. a = new ChildA('a');
  49. a.print();   // Prints 'ChildA: 2'
  50. // Note that the call to this.printImpl in Parent.print goes through the a instance
  51. // but ends up calling Parent.printImpl with 'this' bound to a
  52.  
  53. //a.transform(2);   // TypeError: this.doTransform is not a function
  54.  
  55. console.log('---------- b -----------');
  56. b = new ChildB('b');
  57. b.print();   // prints 'The value is ChildB: 1'
  58.  
  59. b.transform(2);  // prints 4
  60.  
  61.  
  62. // Side Note: The overall behavior seems consistent with delegation,
  63. // but there some JS-specific details when it comes to how it's implemented.
  64. // (1) Fields are owned by the child instances - looks like when you call super,
  65. // 'this' in the base constructor is bound to the child instance, so fields are added there.
  66. // (2) Methods defined in the child class (objects own class) are tucked into a "private" prototype object: '__proto__'
  67. // (3) Inherited methods are on the the prototype of the prototype: '__proto__.__proto__'
  68.  
  69. console.log('----------- a.value ----------');
  70. console.log("a.hasOwnProperty('value')", a.hasOwnProperty('value'));
  71. console.log("a.__proto__.hasOwnProperty('value')", a.__proto__.hasOwnProperty('value'));
  72. console.log("a.__proto__.__proto__.hasOwnProperty('value')", a.__proto__.__proto__.hasOwnProperty('value'));
  73.  
  74. console.log('----------- b.value ----------');
  75. console.log("b.hasOwnProperty('value')", b.hasOwnProperty('value'));
  76. console.log("b.__proto__.hasOwnProperty('value')", b.__proto__.hasOwnProperty('value'));
  77. console.log("b.__proto__.__proto__.hasOwnProperty('value')", b.__proto__.__proto__.hasOwnProperty('value'));
  78.  
  79. console.log('----------- a.printImpl ----------');
  80. console.log("a.hasOwnProperty('printImpl')", a.hasOwnProperty('printImpl'));
  81. console.log("a.__proto__.hasOwnProperty('printImpl')", a.__proto__.hasOwnProperty('printImpl'));
  82. console.log("a.__proto__.__proto__.hasOwnProperty('printImpl')", a.__proto__.__proto__.hasOwnProperty('printImpl'));
  83. console.log("a.__proto__.__proto__.constructor.name", a.__proto__.__proto__.constructor.name);
  84.  
  85. console.log('----------- b.printImpl ----------');
  86. console.log("b.hasOwnProperty('printImpl')", b.hasOwnProperty('printImpl'));
  87. console.log("b.__proto__.hasOwnProperty('printImpl')", b.__proto__.hasOwnProperty('printImpl'));
  88. console.log("b.__proto__.__proto__.hasOwnProperty('printImpl')", b.__proto__.__proto__.hasOwnProperty('printImpl'));
  89. console.log("b.__proto__.constructor.name", b.__proto__.constructor.name);
  90. console.log("b.__proto__.__proto__.constructor.name", b.__proto__.__proto__.constructor.name);
  91.  
  92. console.log("Calling b.__proto__.printImpl('test')");
  93. b.__proto__.id = 'b.__proto__';
  94. b.__proto__.printImpl('test');             // calls the override  (with 'this' bound to b.__proto__)
  95.  
  96. console.log("Calling b.__proto__.__proto__.printImpl('test')");
  97. b.__proto__.__proto__.id = 'b.__proto__.__proto__';
  98. 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