9

I'm working on a JavaScript project, and was just wondering why an object instance doesn't inherit the defineProperty() and other methods, rather than having to call the superclass (superobject?) Object method.

I've looked at the MDN docs, and there are in fact "non-standard" property methods.

But those are deprecated. Why would the move be to the Object methods?

It seems to me that something like instance.defineProperty(...) is better than Object.defineProperty(instance, ...). I would say the same about some of the other Object methods as well.

Shmiddty
  • 13,847
  • 1
  • 35
  • 52
Nick
  • 4,901
  • 40
  • 61
  • closely related: [Why were ES5 Object methods not added to Object.prototype?](http://stackoverflow.com/q/9735026/1048572) – Bergi Jul 01 '16 at 12:36

3 Answers3

10

It's to avoid collisions - in general, issues with objects that do not have the property with the value that you expect.
Objects in JS are often used as key-value-maps, and the keys can be arbitrary strings - for example __defineGetter__, hasOwnProperty or something less special. Now when you want to invoke such a function on an unknown object - like hasOwnProperty is often used in generic enumeration functions, where any JSON might be passed in - you can never be sure whether you got a overwritten property (that might not even be a function) or the original which you want, or whether the object inherits the property at all. To avoid this issue (or also this IE bug), you'd have to use Object.prototype.hasOwnProperty.call - that is ugly.

So, namespacing all those functions on Object is only useful, it's a cleaner API that separates the reflection methods from the object's application interface. This also helps optimisation (simplifying static analysis) and makes it easier to restrict access to the reflection API in sandboxes - at least that was the design idea.

You might be happy to have a defineProperty around in the prototype, but you can only use it safely when working with known objects. If you still want it (as you know when to use and when not), you could use

Object.defineProperty(Object.prototype, "defineProperty", {
    writable: true,
    enumberable: false,
    value: function(prop, descr) {
        return Object.defineProperty(this, prop, descr); 
    }
});
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 7
    It's also worth noting that objects don't have to inherit from `Object.prototype` in ES5. They can inherit from nothing via `Object.create(null)`, or they can inherit from an object which inherits from `null`. This is very useful behavior, but if an object doesn't inherit from `Object.prototype`, it won't have methods defined on `Object.prototype`. Any library wanting to use `defineProperty` generically would have to do `var defineProperty = Function.prototype.call.bind(Object.prototype.defineProperty);`, so it makes sense just to define it as a utility function anyway instead of a method. – Nathan Wall Nov 06 '12 at 18:27
  • Actually, the real reason is for sandboxing and a better API - I could prove it but "rationale_for_es3_1_static_object_methodsaug26.pdf" is dead. – Benjamin Gruenbaum Jul 30 '17 at 15:10
  • @BenjaminGruenbaum "better API" is kinda ambiguous - I'd reason it's better because it avoids collisions. What do you mean by sandboxing? – Bergi Jul 30 '17 at 15:12
  • @BenjaminGruenbaum https://web.archive.org/web/20141214082618/http://wiki.ecmascript.org/lib/exe/fetch.php?id=es3.1%3Aes3.1_proposal_working_draft&cache=cache&media=es3.1:rationale_for_es3_1_static_object_methods.pdf – Bergi Jul 30 '17 at 15:18
  • Well, our discussion on https://stackoverflow.com/questions/45401144/why-javascript-committee-decided-to-introduce-object-entries-instead-of-object-p mostly – Benjamin Gruenbaum Jul 30 '17 at 15:31
  • Ah, "*one reason for making these operations "static methods" was to make it easier to control access to them. I[f] you are creating some sort of sandbox, you may not want to make them available within it.*" – Bergi Jul 30 '17 at 15:41
  • @Bergi right, I would expect that to be reflected in your answer here - don't you agree? – Benjamin Gruenbaum Jul 30 '17 at 15:43
  • 1
    @BenjaminGruenbaum I updated the answer, but disagree with the sandbox reason. I think that was an argument for using a `Meta` object - when you are writing a sandbox it's not simpler to restrict access to `Object.defineProperty` *and* `{}.constructor.defineProperty` than to just restrict access to `{}.defineProperty`. – Bergi Jul 30 '17 at 16:01
5

It's done like that to avoid collisions - remember, every method on Object.prototype is a method in every single user-defined object, too.

Imagine an object where you'd want a custom method defineProperty - that would completely break things when Object.defineProperty was on its prototype instead.

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
2

Interesting. The only reason I came up with so far is that people like to rewrite the prototypes and having this method "hidden" like this might help you avoid some bugs. Especially because of the good method name since that is more likely to get rewritten than, for example, __defineGetter__.

It seems that a lot of features depend on this functionality (link), so it makes sense to make it more global and secure in this context.

zpavlinovic
  • 1,507
  • 1
  • 17
  • 36