defineProperty/getProperty design sketch

John Resig jresig at mozilla.com
Wed Apr 23 08:36:53 PDT 2008


I'm confused as to why an API is being proposed which clashes with existing JavaScript-style APIs. The one case that I had seen previously, at least related to the implementation within Mozilla, is that it would look something like:

  Object.defineProperty(obj, name, value,
    Object.NOT_WRITABLE | Object.NOT_ITERABLE | Object.NOT_DELETABLE)

Which makes much more sense than the proposal (not forcing the user to create temporary objects just to insert values).

We're tracking this issue for implementation in the next version of Firefox:
https://bugzilla.mozilla.org/show_bug.cgi?id=430133

--John

----- "Mark S. Miller" <erights at google.com> wrote:

> The following are comments I sent Allen on a slightly earlier draft. I
> think all these are still applicable.
> 
> 
> ---------- Forwarded message ----------
> From: Mark S. Miller < erights at google.com >
> Date: Tue, Apr 22, 2008 at 4:32 PM
> Subject: Re: define/getProperty meta operations
> To: Allen Wirfs-Brock < Allen.Wirfs-Brock at microsoft.com >
> 
> 
> 
> 
> 
> 
> 
> 
> Problem: Design Pattern for Supporting Meta Operations Upon Objects --
> Design Sketch & Notes
> 
> Not Yet Spec. or Proposal
> 
> Allen Wirfs-Brock
> 
> 
> 
> ECMAScript needs to support an enhanced API for manipulating and query
> the structural and behavior definition of dynamic objects. Example of
> such operations include the definition of setter/getter properties and
> the setting of property attributes such as [[dontenum]]. A single
> design pattern needs to be established to guide the design of these
> new functions.
> 
> General Approach
> 
> Add new static functions as ReadOnly, DontDelete properties of Object
> constructor. Parameterize with literal arguments enable possible
> analysis and static implementation of complex objects. Minimize number
> of entry points using complex patterns of optional arguments. Use
> JSON-style object-literal to implement object pattern. Use same object
> pattern for both property definition/query.
> 
> Hi Allen,
> 
> As discussed on the phone, I like a lot of this! However, I would like
> to use a nested object literal to describe a set of properties, and I
> want to avoid using a function's declared name as a way to cutely
> specify the corresponding property name. Below each of your use cases,
> I'll show the alternative I have in mind.
> 
> 
> 
> 
> 
> 
> 
> 
> 
> Define/Modify a property and/or property attributes
> 
> Object.defineProperty(obj, descriptor)
> Object.defineProperties(<obj>, <multiDescriptor>)
> 
> <multiDescriptor> = { (<propertyName>: <descriptor>)* }
> 
> 
> 
> 
> 
> 
> 
> 
> Add to obj the property described by descriptor. Set properties of the
> attribute as described by descriptor . Return false if is not
> successful.
> throws if not successful.
> 
> 
> 
> 
> 
> 
> 
> 
> Use case: modify attributes of an existing property.
> 
> Descriptor = { name: string , [, writable: boolean ] [, enumerable:
> boolean ] [, deletable: boolean ]}
> Without the "name: string" part, since that comes from the
> multiDescriptor.
> 
> 
> 
> 
> 
> 
> 
> 
> If obj has a local property whose name is the value of the name
> element of the descriptor set the attributes of the property according
> to the values of the writable, enumerable, and deletable elements of
> the descriptor. Fail if the property does not exist (or add
> fixed/frozen attribute)
> If the property does not yet exist, then all unenumerated attributes
> of an explicitly defined property should default to false. If the
> property already exists, then unenumerated attributes should default
> to their existing value.
> 
> 
> 
> 
> 
> 
> 
> 
> Example:
> 
> Object.defineProperty(Array.prototype, {name: "some", enumerable:
> false});
> Object.defineProperties(Array.prototype, {some: {enumerable: false}});
> 
> 
> 
> 
> 
> 
> 
> 
> Use case: add a data property to an object.
> 
> Descriptor = { name: string , value: object [, writable: true ] [,
> enumerable: false ] [, deletable: false ]}
> 
> Add to obj a property whose name is the value of the name element of
> the descriptor and whose initial value is the value of the value
> element of the descriptor. Set the attributes to the specified or
> default values according to the elements of the descriptor. Fail if
> the property already exists and is not writeable (or add fixed
> attribute)
> 
> Example:
> 
> var obj = new Object();
> 
> Object.addProperty(obj, {name: "x", value: 0});
> 
> Object addProperty(obj, {name: "y", value: 0});
> 
> Object.addProperty(obj, {name: "pi", value: 3.14159, writable:
> false});
> 
> Object.defineProperties(obj, {x: {value: 0}, y: {value: 0}, {pi:
> {writable: false}});
> 
> 
> 
> 
> 
> 
> Use case: add a method property to an object.
> 
> Descriptor = { name: string , method: function [, writable: false ] [,
> enumerable: false ] [, deletable: false ]}
> 
> 
> 
> Add to obj a property whose name is the value of the name element of
> the descriptor and whose value is the value of the method element of
> the descriptor. Set the attributes of the specified or default values
> according to the elements of the descriptor. Fail if the property
> already exists and is not writeable (or add fixed attribute) or if the
> value of the method element is not a function.
> 
> Notes: The primary difference from the data property use case is that
> the writable attribute defaults to false rather than true.
> Unenumerated attributes of newly defined properties should always
> default to false. Are there other reasons to distinguish methods from
> values? I will proceed for now assuming not.
> 
> 
> 
> 
> 
> 
> 
> 
> 
> Examples:
> 
> Object.addProperty(obj, {name: doSomeWork, method: function ()
> {this.work()});
> 
> Aternative form assuming existence of Function.prototype.name :
> 
> Object.addProperty(obj, {method: function doSomeWork ()
> {this.work()});
> Object.defineProperties(obj, {doSomeWork: {value: function()
> {this.work();}}});
> 
> 
> 
> 
> 
> 
> 
> 
> Use case: add a getter/setter property to an object.
> 
> Descriptor = { name: string , getter: function [, writable: false ] [,
> enumerable: false ] [, deletable: false ]}
> 
> Or
> 
> Descriptor = {name: string , getter: function , setter: function
> 
> [, writable: true ] [, enumerable: false ] [, deletable: false ]}
> 
> 
> But without the "name: string" part again.
> 
> 
> 
> 
> 
> 
> Add to obj a property getter (and setter) whose name is the value of
> the name element of the descriptor and whose value is the value of the
> getter (and setter ) element(s) of the descriptor. Set the attributes
> of the specified or default values according to the elements of the
> descriptor. Fail if the property already exists and is not writeable
> (or add fixed attribute) or if the value of the getter or setter
> element is not a function.
> 
> Examples:
> 
> var privateprop_y = new Object();
> 
> var obj = new Object();
> 
> Object.addProperty(obj, {name: privateprop_y, value: 0});
> 
> Object addProperty(obj, {name: "y",
> 
> getter: function () {return this[privateprop]},
> 
> setter: function (arg) {this[privateprop] = arg} });
> 
> Whoa! In ES3, all property names are strings. Above, you seem to
> suggest allowing first class anon object refs as keys. This is
> eventually attractive on many grounds, but is *way* too big a step for
> ES3.1. Below, I will assume instead the property name "privateprop_y",
> which, of course, isn't private at all.
> 
> 
> 
> 
> 
> 
> 
> 
> Alternative form assuming existence of Function.prototype.name :
> 
> Object addProperty(obj, { getter: function y() {return
> this[privateprop]},
> 
> setter: function y(arg) {this[privateprop] = arg} });
> 
> Object.defineProperties(obj, {
> privateprop_y: {value: 0, writable: true},
> y: {getter: function() {return this.privateprop_y;},
> setter: function(arg) {this.privateprop_y = arg;}}
> });
> 
> 
> 
> 
> 
> 
> Query existence and attributes of an object's properties
> Object.getProperties(obj) => <multiDescriptor>
> 
> 
> 
> 
> 
> 
> 
> 
> Object.getProperty(obj, name)
> 
> If obj has a locally defined property whose name is name return a
> fully populated proper descriptor object as used with
> Object.defineProperty. Return undefined if the named property does not
> exist.
> As if defined by
> 
> Object.getProperty = function(obj, name) { return
> Object.getProperties(obj)[name]; };
> 
> 
> 
> 
> 
> 
> 
> 
> Other possible object constructor functions:
> 
> Object.freeze(obj)
> as well as Object.seal(obj) which seals without freezing. A sealed
> object is non-dynamic -- new properties cannot be added to it, and its
> existing properties become {deletable: false}. A frozen object is a
> sealed object with the additional constraint that all its existing
> properties become {writable: false}.
> 
> 
> 
> 
> 
> 
> 
> 
> Object.defineProperties(obj, {[ { descriptor }, propName2: {
> descriptor },…])
> 
> Object.getProperties(obj)
> 
> Crock's beget function, etc.
> 
> Create object with properties
> 
> 
> 
> Sketch: Defining a "fixture"
> 
> var fixture = new Object();
> 
> Object.defineProperty(fixture, {method: function method1 (…) {…}});
> 
> Object.defineProperty(fixture, {method: function method2 (…) {…}});
> 
> Object.defineProperty(fixture, {getter: function prop3 () {…}, setter:
> function (arg) {…}});
> 
>> 
> Object.freeze(proto)
> var fixture = new Object();
> Object.defineProperties(fixture, {
> method1: {value: function(...){...}},
> method2: {value: function(...){...}},
> prop3: {getter: function(){...}, setter: function(arg){...}}
> });
> Object.seal(fixture); // for the last line above, is this what you
> meant?
> 
> 
> 
> 
> 
> 
> 
> 
> var template = new Object();
> 
> Object.defineProperty(template, {name: "var1", value: undefined});
> 
> Object.defineProperty(template, {name: "var2", value: undefined});
> 
>> 
> Object.freeze(template);
> 
>> 
> return Object.beget(proto,template); //new object with properties form
> template and prototype proto
> I still don't like the idea of extending beget with copying behavior.
> 
> 
> 
> 
> 
> 
> --
> Cheers,
> --MarkM 
> _______________________________________________
> Es4-discuss mailing list
> Es4-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es4-discuss



More information about the Es4-discuss mailing list