1

Say I change the object prototype like so:

Object.prototype.test = {val: 5, abc: 8};

Then I change a property of test for Array:

Array.prototype.test.abc = 20;

Then if I print the base test variable:

console.log(Object.prototype.test); // {val: 5, abc: 20}
console.log(({}).test);        // {val: 5, abc: 20}
console.log(([]).test);       // {val: 5, abc: 20}

How do I still have arrays inherit val as 5, but have an abc value of 20 without affecting Object's prototype

kepe
  • 282
  • 1
  • 18
  • 1
    You have a single object set as the `test` property; if you want different objects you'd need to clone and modify. – Dave Newton Dec 03 '18 at 20:18
  • Nota Bene: you should never *ever* actually do this. Ever. Don't modify prototypes you don't own. – Jared Smith Dec 03 '18 at 20:31
  • @JaredSmith A lot of libraries do it, but yes. I read [this](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) which doesn't give a reason not to – kepe Dec 03 '18 at 20:32
  • 1
    @FireCubez No library modifies `Array.prototype` or `Object.prototype` :-) – Bergi Dec 03 '18 at 20:33
  • At least not much since the aptly named `prototype.js`. What libraries do occasionally do is conditionally add standard features that are missing in the current environment. Polyfilling standardized properties is different than adding random stuff because reasons. – Jared Smith Dec 03 '18 at 20:35
  • @FireCubez Read more. Specifically https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Bad_practice_Extension_of_native_prototypes. Which pretty much states flat out you shouldn't do this, and explains why. I would call that a "reason not to". – Dave Newton Dec 03 '18 at 20:37
  • ~~@DaveNewton I read it. It just says "dont do it" without giving a reason~~ Nevermind, it breaks encapsulation – kepe Dec 03 '18 at 20:38
  • 1
    @FireCubez ... What is "This technique is called monkey patching and breaks encapsulation." if not a reason?! It gives an example of the "only good reason" (back-porting now-standard functionality), meaning reasons that are *not* that are not good reasons, so any other reason you can think of almost certainly falls under the "not a good reason" category. I don't think it could be any clearer, really, but YMMV. – Dave Newton Dec 03 '18 at 20:38

1 Answers1

1

In your example Array.protoype does not have its own test property. So when you try to access it with Array.prototype.test.abc = 20; it looks up the prototype chain and find the .test object on Object.prototype and sets its .abc value to 20.

You can give Array.prototype it's own property test with something like:

Object.prototype.test = {val: 5, abc: 8};

Array.prototype.test = Object.assign({}, Object.prototype.test)
Array.prototype.test.abc = 20;

console.log(({}).test.abc);       // 8
console.log(([]).test.abc);       // 20

You could also link the test object from Array to Object so properties not found on Array.prototype.test will defer up the chain to Object.prototype.test, although this starts to get confusing:

Object.prototype.test = {val: 5, abc: 8};

Array.prototype.test = Object.create(Object.prototype.test)
Array.prototype.test.abc = 20;

console.log(([]).test.abc);      // shadows with it's own abc
Object.prototype.test.abc = 500  // changes in object have no effect
console.log(([]).test.abc);      // still 20

console.log(([]).test.val);      // no val on Array's test so it defers to object prototype
Object.prototype.test.val = 100  // changing object changes array
console.log(([]).test.val); 

…not that I really recommend any of this beyond test and exploring the ecosystem.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Mark
  • 90,562
  • 7
  • 108
  • 148
  • Instead of `Array.prototype.test = Object.create(Object.prototype.test)` I could do `Array.prototype.test = Object.create(Array.prototype.__proto__.test)` right? More generally I can just do `ABC.prototype.test = Object.create(ABC.prototype.__proto__.test)`? – kepe Dec 03 '18 at 20:37
  • Sure @FireCubez since `Array.prototype.__proto__ === Object.prototype` – Mark Dec 03 '18 at 20:39