1

Trying to define a hashCode method on Object.prototype as well as String.prototype and Number.prototype. I'm defining the prototype methods using:

Object.defineProperty(Object.prototype, 'hashCode', {
  value:function() {/*code*/},
  enumerable:false
});

String.prototype.hashCode = function() {/*code*/};
Number.prototype.hashCode = function() {/*code*/};

When I create a number or string with any of ('', new String(), 3, new Number()), and call hashCode on the instance, the Object.prototype.hashCode method always runs instead of String.prototype.hashCode or Number.prototype.hashCode.

What's wrong?

Triynko
  • 18,766
  • 21
  • 107
  • 173
  • FYI, if I also define the String and Number prototype methods using `Object.defineProperty(String.prototype...` then it works as expected. The fact that it doesn't work the same way as using `String.prototype.hashCode = function() ...` has me confused. – Triynko Nov 07 '16 at 19:05
  • 4
    Make the property descriptor `writable: true` or it will be inherited as non-writable when writing that property on objects that inherit it. https://jsfiddle.net/5ox1a0f2/ –  Nov 07 '16 at 19:10
  • 1
    Oh, cool. I didn't realize it was not writable by default . Thanks! – Triynko Nov 07 '16 at 19:13
  • 1
    Closely related discussion of this `writable` behavior: [Does Javascript writable descriptor prevent changes on instances?](http://stackoverflow.com/questions/35177663/does-javascript-writable-descriptor-prevent-changes-on-instances) – apsillers Nov 07 '16 at 19:13
  • Indeed. It's also interesting that if I set String.prototype.hashCode and Number.prototype.hashCode *before* I call `Object.defineProperty(Object.prorotype...` the functions work as expected, so if you create them, then make them non-writable on Object.prototype, they've already been written and don't lose their values. – Triynko Nov 07 '16 at 19:17

2 Answers2

1

Make the property descriptor writable: true or it will be inherited as non-writable when writing that property on objects that inherit it. http://jsfiddle.net/5ox1a0f2 – squint

Object.defineProperty(Object.prototype, 'hashCode', {
  value:function() {console.log('object')},
  enumerable:false,
  writable:true
});

String.prototype.hashCode = function() {console.log('string')};
Number.prototype.hashCode = function() {console.log('number')};

4..hashCode()
georg
  • 211,518
  • 52
  • 313
  • 390
  • Note `String.prototype.hashCode` and `Number.prototype.hashCode` will be enumerable. – Oriol Nov 07 '16 at 19:55
  • Love the double-dot call on the number literal. I was getting syntax errors in testing when trying to call '3.hashCode()' but '3..hashCode()' is a nice trick. – Triynko Nov 07 '16 at 20:11
1

Mixing property definitions and property assignments can lead to this kind of problems.

It works if you also use property definition in String.prototype and Number.prototype:

Object.defineProperty(Object.prototype, 'hashCode', {
  value: function() {console.log('object')},
  enumerable: false
});
Object.defineProperty(String.prototype, 'hashCode', {
  value: function() {console.log('string')},
  enumerable: false
});
Object.defineProperty(Number.prototype, 'hashCode', {
  value: function() {console.log('number')},
  enumerable: false
});
(4).hashCode(); // "number"
('').hashCode(); // "string"

However, if you are only using property definitions because you don't want enumerability, but don't care about configurability nor writability, it may be more convenient to define the methods via assignment, and then redefine the enumerability:

Object.prototype.hashCode = function() {console.log('object')};
String.prototype.hashCode = function() {console.log('string')};
Number.prototype.hashCode = function() {console.log('number')};
Object.defineProperty(Object.prototype, 'hashCode', {enumerable: false});
Object.defineProperty(String.prototype, 'hashCode', {enumerable: false});
Object.defineProperty(Number.prototype, 'hashCode', {enumerable: false});
(4).hashCode(); // "number"
('').hashCode(); // "string"
Oriol
  • 274,082
  • 63
  • 437
  • 513