ES3.1 Object static methods rationale document
Ingvar von Schoultz
ingvar-v-s at comhem.se
Thu Jul 17 17:33:30 PDT 2008
John Resig wrote:
> I wanted to bring up some further evidence for the widespread use of an extend() method.
I always need both these functions. However my ObjectClone
function is just a single statement that calls the other function:
return ObjectMerge (Source, {}). So I see Clone as trivial syntactic
sugar. Merge is necessary and costs work and processing time.
Ingvar
> Here are the top 5 JavaScript libraries and their associated versions of "Object.extend()":
>
>
> == jQuery.js:
>
> (jQuery also does deep extend - but that isn't relevant here.)
>
> jQuery.extend = jQuery.fn.extend = function() {
> var target = arguments[0] || {}, i = 1, length = arguments.length, options;
>
> if ( typeof target != "object" && typeof target != "function" )
> target = {};
>
> if ( length == i ) {
> target = this;
> --i;
> }
>
> for ( ; i < length; i++ ) {
> if ( (options = arguments[ i ]) != null ) {
> for ( var name in options ) {
> target[ name ] = options[ name ];
> }
> }
> }
>
> return target;
> };
>
>
> == Prototype.js:
>
> Object.extend = function(destination, source) {
> for (var property in source)
> destination[property] = source[property];
> return destination;
> };
>
> == Mootools.js:
>
> var $extend = function(){
> var args = arguments;
> if (!args[1]) args = [this, args[0]];
> for (var property in args[1]) args[0][property] = args[1][property];
> return args[0];
> };
>
> == Dojo Toolkit:
>
> dojo._mixin = function(obj, props){
> var tobj = {};
> for(var x in props){
> if(tobj[x] === undefined || tobj[x] != props[x]){
> obj[x] = props[x];
> }
> }
> // IE doesn't recognize custom toStrings in for..in
> if(d["isIE"] && props){
> var p = props.toString;
> if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
> p != "\nfunction toString() {\n [native code]\n}\n"){
> obj.toString = props.toString;
> }
> }
> return obj; // Object
> }
>
> dojo.mixin = function(obj){
> for(var i=1, l=arguments.length; i<l; i++){
> d._mixin(obj, arguments[i]);
> }
> return obj; // Object
> }
>
> == Yahoo UI:
>
> YAHOO.lang.augmentObject = function(r, s) {
> if (!s||!r) {
> throw new Error("Absorb failed, verify dependencies.");
> }
> var a=arguments, i, p, override=a[2];
> if (override && override!==true) { // only absorb the specified properties
> for (i=2; i<a.length; i=i+1) {
> r[a[i]] = s[a[i]];
> }
> } else { // take everything, overwriting only if the third parameter is true
> for (p in s) {
> if (override || !(p in r)) {
> r[p] = s[p];
> }
> }
>
> L._IEEnumFix(r, s);
> }
> };
>
> There are a couple points that are very important here:
> 1) They all extend the base object with the enumerable properties at least one other object.
> 2) There is very little done to prevent properties coming in from [SomeObject].prototype - this is mostly because libraries opt not to use .hasOwnProperty() in favor of speed and/or cross-browser compatibility (older versions of Safari and IE Mac don't have hasOwnProperty).
> 3) A couple of the implementations take multiple source objects with which to extend the base object.
>
> The implementations in the libraries don't deal with nearly as many edge cases as they should (such as the aforementioned hasOwnProperty - or getters and setters) which is something that can be done in a language implementation. A language implementation of .extend() should certainly also allowing non-enumerable properties to be extended, as well (considering that this wont be possible - or will be very difficult to implement - from a pure-script perspective).
>
> While Object.clone will certainly be useful in, and of, itself - it's not a replacement for an extend method.
>
> I have a pure-JavaScript version of Object.extend() that I'm working on - and I'm building a test suite for it, as well (to make sure all edge cases are properly defined and handled):
> http://ejohn.org/files/object-extend.js
>
> I'll be updating this file throughout the day. I'll post back when I feel as if I have a reasonable test suite.
>
> --John
>
> ----- Original Message -----
> From: "Allen Wirfs-Brock" <Allen.Wirfs-Brock at microsoft.com>
> To: "Robert Sayre" <sayrer at gmail.com>, "Mark S. Miller" <erights at google.com>
> Cc: "es3 x-discuss" <es3.x-discuss at mozilla.org>, es4-discuss at mozilla.org
> Sent: Wednesday, July 16, 2008 7:10:21 PM GMT -05:00 US/Canada Eastern
> Subject: RE: ES3.1 Object static methods rationale document
>
> As far as I can recall, we didn't discuss a specific formulation that corresponds to Object.extend but we have considered (and arguably provided) pretty much equivalent functionality in our proposal. I assume that at least Doug, Adam, or Kris were specifically aware of Object.extend and would have broad it up if it was relevant. One reason, it probably wasn't was that the starting point of our design was the full reification and control of properties and their attributes rather than just copying properties. By the time we got around to cloning/copying issues we already had establish some core elements of our overall design.
>
> Doing a bit of search I've found several different variants of the extend function. Some are defined on Object, some on Object.prototype. Some use a single source object and some use multiple source objects. What they all seem to have in common is that they copy the enumerable methods from one (or more) object to another.
>
> The most common use case seems to be the one where the target object is a newly instantiated object without any properties of its own. That use case (at least for variants of extend that only take a single source object) is most directly supported by the Object.clone function in our proposal. However, Object.clone is defined to be a more comprehensive object duplication process than is performed by extend. It duplicates all own properties and their attributes and any internal properties such as its [[Value]] property if it has one.
>
> I have personally considered whether there should be some sort of mechanism to filter the properties copied by Object.clone. For example, you might only copy non getter/setter properties, or only enumerable properties, or perhaps filter out ReadOnly properties. However, I never proposed any of these for the ES3.1 spec. because I have yet to find a use case that was sufficiently compelling or pervasive enough to justify making the interface to Object.clone more complex (in contrast, see the explanation in the rationale document for why we added a second argument to Object.create). If you want to do that sort of filtering you can do it using Object.wontbecalledgetProperty and Object.defineProperty. If you just want a fast and comprehensive copy use Object.clone.
>
> The other obvious use case would seem to be adding some "mix-in" behavior to an object (some of the descriptions of extend on the web call this "inheritance" but it's not how I'd use that term). This use case is fairly directly supported by Object.defineProperties although it is formulated somewhat differently.
>
> As I mention in our rationale document, this design isn't just a set of individual functions but an attempt at a unified design where we have tried to distribute the functional elements across of set of related functions that often have multiple uses. Object.extend is a fine function, particular when viewed from the perspective of what can be accomplished using the available ES3 APIs. However, it isn't something I would simply add as whole cloth to the set of functions we have already worked out. That would mostly just added redundant functionality and in a manner that wasn't particularly consistent with the other functions we have defined. Instead, if we added it we would potentially refactor the functionality of all of the proposed static Object functions to make them stand together as a unit. I'd be happy to discuss additional use cases to see try to see if we can find any significant hole in our proposal.
>
> Finally, I want to say that my approach to a situation like this where there appears to be multiple versions of a similar but not identical function is not necessarily to pick one and make everybody else conform. Instead, I like to approach the problem from the perspective of what would have made these various functions unnecessary and what primitives would have been useful in implementing the assorted variations. If I can provide that then future users are unlikely to need to use the old forms and existing user can migrate by continuing to use their old API but perhaps reimplementing them using the new primitives.
>
> -----Original Message-----
> From: es3.x-discuss-bounces at mozilla.org [mailto:es3.x-discuss-bounces at mozilla.org] On Behalf Of Robert Sayre
> Sent: Wednesday, July 16, 2008 2:17 PM
> To: Mark S. Miller
> Cc: es4-discuss at mozilla.org; es3.x-discuss at mozilla.org
> Subject: Re: ES3.1 Object static methods rationale document
>
> Maybe someone could just give the rationale for leaving out Object.extend?
>
> Douglas Crockford wrote that it was considered, but I'm confused since
> it looks like you haven't even seen a proposal, and didn't participate
> in the discussion to exclude it.
>
> - Rob
>
> 2008/7/16 Mark S. Miller <erights at google.com>:
>> On Wed, Jul 16, 2008 at 10:11 AM, Brendan Eich <brendan at mozilla.org> wrote:
>>> And? The doc gives rationales for design decisions. What's the
>>> rationale for leaving Object.extend out?
>> If the document needs to give rationales for leaving out each thing we did
>> not include, it would be quite a long document. What is the argument for
>> adding Object.extend()? A pointer to Resig's message or a prior discussion
>> is an adequate response.
>>
>> --
>> Cheers,
>> --MarkM
>> _______________________________________________
>> Es3.x-discuss mailing list
>> Es3.x-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es3.x-discuss
>>
>
>
>
> --
>
> Robert Sayre
>
> "I would have written a shorter letter, but I did not have the time."
> _______________________________________________
> Es3.x-discuss mailing list
> Es3.x-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es3.x-discuss
>
> _______________________________________________
> Es3.x-discuss mailing list
> Es3.x-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es3.x-discuss
> _______________________________________________
> Es3.x-discuss mailing list
> Es3.x-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es3.x-discuss
>
--
Ingvar von Schoultz
------- (My quirky use of capitals in code comes from my opinion that
reserved and predefined words should all start with lowercase, and
user-defined should all start with uppercase, because this will easily
and elegantly prevent a host of name-collision problems when things
like programming languages are upgraded with new labels.)
More information about the Es4-discuss
mailing list