9

ES5 added a number of methods to Object, which seem to break the semantic consistency of JavaScript.

For instance, prior to this extension, the JavaScript API always revolved around operarting on the object itself;

var arrayLength = [].length;
var firstPosInString = "foo".indexOf("o");

... where as the new Object methods are like;

var obj = { };
Object.defineProperty(obj, {
    value: 'a',
    writable: false
});

... when the following would have been much more conformative:

var obj = { };
obj.defineProperty({
    value: 'a',
    writable: false
});

Can anyone cool my curiosity as to why this is? Is there any code snippets that this would break? Are there any public discussions made by the standards committee as to why they chose this approach?

Isaac
  • 1,677
  • 3
  • 15
  • 22

2 Answers2

8

This is all explained very nicely in "Proposed ECMAScript 3.1 Static Object Functions: Use Cases and Rationale" document (pdf) by Allen Wirfs-Brock himself (editor of ES5 spec, and a member of TC39).

I would suggest to read all of it. It's pretty short, easily digestible, and gives a nice glimpse of the thought process behind these ES5 additions.

But to quote relevant section (emphasis mine):

A number of alternatives API designs were considered before the proposed API was chosen. In the course of considering alternatives we developed a set of informal guidelines that we applied when considering the alternatives. These guidelines are:

  • Cleanly separate the meta and application layers.
  • Try to minimize the API surface area (i.e., the number of methods and the complexity of their arguments).
  • Focus on usability in naming and parameter design.
  • Try to repeatedly apply basic elements of a design.
  • If possible, enable programmers or implementations to statically optimize uses of the API.

[...]

Here are some of the alternatives that were considered that lead to the selected design.

The obvious initial idea, following the example of the already existing standard method Object.prototype.propertyIsEnumerable, was to add additional “propertyIs...” query methods on Object.prototype for the other attributes and a parallel set of attribute changing methods.

[...]

As we considered this approach there were a number of things about it that we didn’t like and that seemed contrary to the above API design guidelines:

  • It merges rather than separates the meta and application layers. As methods on Object.prototype the methods would be part of the public interface of every application object in a program. As such, they need to be understood by every developer, not just library designers.

[...]

kangax
  • 38,898
  • 13
  • 99
  • 135
  • Interesting... do you know how this lined up with `Object.create`? Did Crockford propose it as `Object.create` after these decisions had been made, or before that? – Dagg Nabbit Mar 17 '12 at 01:01
  • Good question. I have no idea :) I think Crockford renamed his `Object.beget` to `Object.create` at about the same time when these API were discussed. FWIW, the doc says: _'Note that Object.create without its optional second argument is essentially the same operation as the beget function that was been widely promoted. We (perhaps not surprisingly) agree with the utility of this function but felt that the word “beget” is probably confusing to many non-native English speakers.'_ – kangax Mar 17 '12 at 11:36
  • 3
    Crockford was directly involved in the ES5 design and originally proposed "beget". "create" emerged as the preferred name during the subsequent design discussions. He renamed "beget" in his book to reflect the ES design decision. – Allen Wirfs-Brock Mar 17 '12 at 15:13
  • Thanks for providing the link to such a relevant resource! – Isaac Mar 17 '12 at 18:05
  • Thanks for the very informative passage! The link to the complete document is dead however. Does anyone know if it is still possible to read this document somewhere? – Oliver Sieweke May 24 '19 at 07:45
  • 1
    I found that document [here](http://archives.ecma-international.org/2008/misc/rationale_for_es3_1_static_object_methodsaug26.pdf), @OliverSieweke – Peter Alfvin Nov 24 '21 at 14:54
1

the JavaScript API always revolved around operarting on the object itself;

This is not correct. E.g. JSON and Math always had own methods. Nobody does such things:

var x = 0;
x.cos(); // 1.0
({"a":[0,1],"p":{"x":3,"y":4}}).toJSON();

There are numerous articles on the web about why extending Object.prototype is a bad thing. Yes, they're about client code, but maybe this is bad for build-in methods also for some points.

Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
kirilloid
  • 14,011
  • 6
  • 38
  • 52
  • 1
    I take your point about `Math`... but the differences between extending `Object.prototype` as a *client* and as the language itself are completely different; extensions by the *language* don't show up in `for ( in )`, where as *client* extensions do: http://jsfiddle.net/mDfCe/1/ – Isaac Mar 16 '12 at 10:17
  • ... which is because those properties (`.constructor`, `.hasOwnProperty` etc.) are natively defined with the "enumerable" attribute set to false. As of ES5 we can also create our own properties that don't show up in `for in` loops (with `Object.defineProperty` and `Object.create`'s second argument) – Timo Tijhof Dec 17 '12 at 03:55
  • Also I'm wrong about "nobody does". In prototype they use `toJSON` for Arrays and this breaks `JSON.stringify([])` in Prototype 1.6 – kirilloid Dec 17 '12 at 16:18