John,

Thanks for pulling together all the various versions of Object.extend.  It's 
useful to have them in one place.

There are a couple of things you mentioned that I wanted to clarify.

Neither Object.create nor Object.clone was not intended to be a directly 
replacement for Object.extend.  The more direct comparable would be 
Object.defineProperties.  Object.create's heritage is Doug Crockford's beget 
function and its primary purpose is to provide a more direct way to create an 
object with an explicitly specified prototype.  Other than for atomicity and 
any optimization that an implementation might be able to perform 
Object.create(parent,properties) is exactly equivalent to 
Object.defineProperties(Object.create(parent), properties). Object.clone is 
just a "shallow copy" and its primary use case is exact copies of objects.

Object.defineProperties is comparable to Object.extend in the sense that it 
injects a set of properties into an already existing object.  It is different 
from Object.extend in that rather than copying the injected property directly 
from a source object, it uses a meta level description of the properties to be 
injected.  It is more general, in that it can inject properties with any 
attribute settings and allows control of attribute values at the per attribute 
per property level.

It may be useful to think of defineProperties as defining a mechanism for 
copying properties but without defining a fixed policies concerning which 
properties to copy.  In contrast, Object.extend applies a specific policy for 
copying.

Collectively, 
getOwnProperty,defineProperties/defineProperty,getOwnPropertyNames,getPrototypeOf
 are intended to provide all the mechanisms necessary to build any of these 
variants to extent or any other model of property manipulation using whatever 
policies for property selection that might be desired by the designer.

I'll exit with three essay questions:

Is the formulation and policies of Object.extend the ideal, or is it simply the 
best that could be accomplished given the available reflective capabilities of 
ES3 (or extended ES3 in the case of getter/setter properties)?

Are there any essential meta-level function that would be needed to implement 
anything like Object.extend that are missing from the proposed set of 3.1 meta 
operations?

Let's assume that defineProperties was available and we have a  green-field 
situation where somebody is creating a framework that needs to use some sort of 
property mix-in process. Do you think its developer would still implement their 
own version of Object.extend and specify their mix-ins as conventional objects, 
or would they just use defineProperties and specify their mix-ins as property 
descriptor sets?

-----Original Message-----
From: John Resig [mailto:[EMAIL PROTECTED]
Sent: Thursday, July 17, 2008 8:38 AM
To: Allen Wirfs-Brock
Cc: es3 x-discuss; es4-discuss@mozilla.org; Robert Sayre; Mark S. Miller
Subject: Re: ES3.1 Object static methods rationale document


I wanted to bring up some further evidence for the widespread use of an 
extend() method. 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" <[EMAIL PROTECTED]>
To: "Robert Sayre" <[EMAIL PROTECTED]>, "Mark S. Miller" <[EMAIL PROTECTED]>
Cc: "es3 x-discuss" <[EMAIL PROTECTED]>, es4-discuss@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: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Robert Sayre
Sent: Wednesday, July 16, 2008 2:17 PM
To: Mark S. Miller
Cc: es4-discuss@mozilla.org; [EMAIL PROTECTED]
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 <[EMAIL PROTECTED]>:
> On Wed, Jul 16, 2008 at 10:11 AM, Brendan Eich <[EMAIL PROTECTED]> 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
> [EMAIL PROTECTED]
> 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
[EMAIL PROTECTED]
https://mail.mozilla.org/listinfo/es3.x-discuss

_______________________________________________
Es3.x-discuss mailing list
[EMAIL PROTECTED]
https://mail.mozilla.org/listinfo/es3.x-discuss

_______________________________________________
Es4-discuss mailing list
Es4-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es4-discuss

Reply via email to