Inheriting Data Properties

B

Benjy Borda

I assume this question must have been answered in the past, but I have
been searching the archives the last couple of days and cannot find a
solid answer to my problem.

I have a couple of properties that need to be created with every new
object created. To simplify, assume the only property I need to do
this with is called 'dom', which stores a dom object. In this context,
every object will need to create its own dom to avoid sharing of the
same dom object. A solution I have is like so:

var clone = (function(){
function F(){}
return (function(o){
F.prototype = o;
return new F();
});
})();

var proto_root = { /* bunch of methods */};

function Root() {
this.dom = document.createElement('div');
}
Root.prototype = proto_root;

var proto_widgetA = clone(proto_root);
var proto_widgetA.someNewProp = function() { //does something}

function WidgetA() {
Root.call(this); // to set the dom property
// set some specific "widgetA" properties
}
WidgetA.prototype = proto_widgetA;

Then create new widgetA like: var w = new WidgetA();

There will eventually be lots of widgetXYZ constructors and more
objects that inherit from those

This will WORK, but I can't help but feel like it is not the correct
way to accomplish such a thing in a prototype based language.
Inheriting properties like this makes me feel like I am coupling these
constructors too much together and gives me a feel of creating classes
in a class-based language.

An alternative I could come up with that "feels" more prototypical:
function addDom(o) {
o.dom = document.createElement('div');
return o;
}

var root = { /* bunch of methods */};

var proto_widgetA = clone(root);
var proto_widgetA.someNewProp = function() { //does something}

function widgetA() {
var w = addDom(clone(proto_widgetA)); // note the addDom call
here
// add widgetA stuff
return w;
}

and create widgetA's like: var w = widgetA();

The problem I see with this is that there may eventually end up with
things like:
addDom(addSomething(addSomethingElse(clone(obj)));
Which seems ugly to me

What are your thoughts on my two proposed methods? How would you solve
the same problem?
 
S

slebetman

I assume this question must have been answered in the past, but I have
been searching the archives the last couple of days and cannot find a
solid answer to my problem.

I have a couple of properties that need to be created with every new
object created. To simplify, assume the only property I need to do
this with is called 'dom', which stores a dom object. In this context,
every object will need to create its own dom to avoid sharing of the
same dom object. A solution I have is like so:

    var clone = (function(){
      function F(){}
      return (function(o){
          F.prototype = o;
          return new F();
      });
    })();

    var proto_root = { /* bunch of methods */};

    function Root() {
      this.dom = document.createElement('div');
    }
    Root.prototype = proto_root;

   var proto_widgetA = clone(proto_root);
   var proto_widgetA.someNewProp = function() { //does something}

    function WidgetA() {
      Root.call(this);   // to set the dom property
      // set some specific "widgetA" properties
    }
    WidgetA.prototype = proto_widgetA;

Then create new widgetA like: var w = new WidgetA();

There will eventually be lots of widgetXYZ constructors and more
objects that inherit from those

Eh? Why overcomplicate what you're trying to do? Why not do it the
native way:

// Root constructor:
function Root () {
this.dom = document.createElement('div');

this.method1 = function () {//...}
this.method2 = function () {//...}
}

// WidgetA constructor:
function WidgetA () {
// bunch of methods and attributes
}
// Inherit from Root:
WidgetA.prototype = new Root();
 
B

Benjy Borda

Eh? Why overcomplicate what you're trying to do? Why not do it the
native way:

  // Root constructor:
  function Root () {
    this.dom = document.createElement('div');

    this.method1 = function () {//...}
    this.method2 = function () {//...}
  }

  // WidgetA constructor:
  function WidgetA () {
    // bunch of methods and attributes
  }
  // Inherit from Root:
  WidgetA.prototype = new Root();

Because then all WidgetA objects will share the same div from the
prototype. Each object needs its own.
 
T

Thomas 'PointedEars' Lahn

Benjy said:
I assume this question must have been answered in the past, but I have
been searching the archives the last couple of days and cannot find a
solid answer to my problem.

One reason for that is that there is the rather junky Prototype.js library
which has frequently been referred to just as "Prototype"; however,
"prototype chain" should prove to be enlightening. I, for one, remember to
have submitted a number of postings on the subject here that use this term.
I have a couple of properties that need to be created with every new
object created. To simplify, assume the only property I need to do
this with is called 'dom', which stores a dom object. In this context,
every object will need to create its own dom to avoid sharing of the
same dom object. A solution I have is like so:

var clone = (function(){
function F(){}
return (function(o){ ^
F.prototype = o;
return new F();
});
^
`function() { ... }' is a proper expression (see below). You need the
additional parentheses only if the /FunctionExpression/ is part of a
/CallExpression/.

If you do this, `F' is a bound variable in the returned function (as
understood in closures), meaning that all objects you create with clone()
are "F objects" and thus share the same prototype chain. You really don't
want that. Using closures to increase efficiency is usually commendable but
counterproductive here.
var proto_root = { /* bunch of methods */};

You don't need or want this variable.
function Root() {

Shouldn't that be a more talking identifier, like ` DivWrapper'?
this.dom = document.createElement('div');
}
Root.prototype = proto_root;

You can (and should) assign the object reference directly.

Root.prototype = {
// ...
};

However, see below for the drawbacks of this approach.
var proto_widgetA = clone(proto_root);
var proto_widgetA.someNewProp = function() { //does something}
^[1] ^^^^^^^^^^^^^^^^^[2]
There are two syntax errors.

[1] A variable name must be an /Identifier/, and an /Identifier/ MUST NOT
contain dots (or other non-word characters except for escape sequences).

[2] The single-line comment disables the `}' so this does not match
/FunctionExpression/.

Did you mean

proto_widgetA.someNewProp = function() { /* does something */ };

?
function WidgetA() {
Root.call(this); // to set the dom property
// set some specific "widgetA" properties
}
WidgetA.prototype = proto_widgetA;

Note that if you do this you overwrite the default prototype object which
includes the `constructor' property. There are two possibilities to work
around that: redefine the `constructor' property in your prototype object
(here referred to by proto_widgetA, but the variable is unnecessary), or
only add/overwrite properties in a loop.
Then create new widgetA like: var w = new WidgetA();

There will eventually be lots of widgetXYZ constructors and more
objects that inherit from those

All the more reason to set up different prototype chains.
This will WORK, but I can't help but feel like it is not the correct
way to accomplish such a thing in a prototype based language.

Your bad feeling ist justified. You are on the right track (IMHO), but have
a few steps to go.
[...]
The problem I see with this is that there may eventually end up with
things like:
addDom(addSomething(addSomethingElse(clone(obj)));
Which seems ugly to me

It is.
What are your thoughts on my two proposed methods? How would you solve
the same problem?

With the exception of the syntax errors in your code, I'm using more or less
the first variant (prototype properties are added to the prototype object of
the constructor instead, where they belong; the prototype object of the
constructor's prototype only serves for building the proper prototype chain).

It has frequently been recommended here, and I have not encountered any
problems with it so far; in fact, it has helped me greatly to set up an
exception hierarchy despite that Error usually cannot be reused. I'm using
less variables, though. Search for "inheritFrom" here for the basic
implementation.


PointedEars
 
S

slebetman

Because then all WidgetA objects will share the same div from the
prototype. Each object needs its own.

Oh, forgot about that. I personally prefer to use the factory pattern
rather than constructors to create objects. It has a neater syntax and
does exactly what you want. The down side is that instanceof doesn't
work:

function makeRoot () {
this = {}
this.dom = document.createElement('div');
}

function makeWidgetA () {
this = makeRoot();
}

var a = makeWidgetA();
 
B

Benjy Borda

My apologies for the syntax errors but thanks for your help Thomas
Lahn.

If you do this, `F' is a bound variable in the returned function (as
understood in closures), meaning that all objects you create with clone()
are "F objects" and thus share the same prototype chain.  You really don't
want that.  Using closures to increase efficiency is usually commendable but
counterproductive here.

This got me thinking because that is what I thought was going to
happen when I read this code. However, this is not the results I am
seeing:
var clone = (function(){
function F(){}
return function(o){
F.prototype = o;
return new F();
};
})();

// Some random objects to be cloned
var proto1 = {prop1: 'prop1'};
var proto2 = {prop2: 'prop2'};

function x() {}
x.prototype = clone(proto1);

function y() {}
y.prototype = clone(proto2);

var x1 = new x();
var y1 = new y();

Now I get the following values:
x1.prop1 => 'prop1'
x1.prop2 => undefined
y1.prop1 => undefined
y1.prop2 => 'prop2'

My expectations were that the initial call to clone would setup the
prototype hierarchy as:
new F() (an empty object) => proto1 => ...
and then the second call to clone would replace proto1 in the above
chain with proto2. And since F objects share the same prototype, all
new x and y objects should only inherit properties from proto2. I
would have expected to see x1.prop1 => undefined and x1.prop2 =>
'prop2'.

Clearly, something is going on here that does not make sense to me
(perhaps related to __proto__ property on new F objects?)
 
T

Thomas 'PointedEars' Lahn

kangax said:
Where did you get that from?

CallExpression:
MemberExpression Arguments

MemberExpression:
FunctionExpression

FunctionExpression:
function Identifier opt ( FormalParameterListopt ){ FunctionBody }

Arguments:
()

`function(){}()` (i.e. /FunctionExpression/ as part of /CallExpression/)
looks perfectly valid to me. I don't see why one would need additional
parenthesis here, except for clarity/convention.

Parantheses are not needed when the CallExpression is produced only through
AssignmentExpression, but they are needed when CallExpression is produced
through ExpressionStatement.

function/* ... */(/* ... */){/* ... */}(/* ... */);

won't compile, because of:

| Statement :
| [...]
| ExpressionStatement

| ExpressionStatement :
| [lookahead ∉ {{, function}] Expression ;

I have since made it my code convention to parenthesize called
FunctionExpressions always. Sorry for the oversimplification.
If you do this, `F' is a bound variable in the returned function (as
understood in closures), meaning that all objects you create with clone()
are "F objects" and thus share the same prototype chain. You really don't
want that. Using closures to increase efficiency is usually commendable but
counterproductive here.

I'm failing to see how prototype chain is shared here. If `F.prototype`
is being assigned a new object on `clone` invocation, and returned
object is then initialized with [[Prototype]] referencing this new `o`
object, what does it matter that the same function object was used as
constructor?

I had planned a figure for my refutation, but in making it I saw all too
quickly that I had been wrong, and that it doesn't really matter -- as you
indicated -- that the constructor is the same. (Which is supported by
Benjy's observations.)

Because the prototype chain of an object is not defined indirectly through
the instance-constructor-prototype relationship but directly through the
internal [[Prototype]] property which is set on creation of the object.

Maybe I will modify my inheritance method accordingly.

For the figure, I have used the property names from the OP's
<to indicate object indentity.

I have tried to stay as less confusing as possible. Arrows with "solid"
lines indicate normal object references, while arrows with "dotted" lines
indicate the prototype chain (which boils down to object references as well
but cannot be modified in a standards-compliant way; see below).

I hope it makes any sense (fixed-width font required, of course):

,--[Function object "F"]--.
| | .--> 1. [Object object "o_1"] <--.
| prototype -----------------' :
| ... | '--> 2. [Object object "o_2"] <- - -.
`-------------------------' : :
^ ^ : :
| | ,--[Object object "proto1"]--. : :
| | | | : :
| '--- constructor | : :
| | [[Prototype]] - - - - - - - - - - - - - - - - - - --' :
| | ... | :
| `----------------------------' :
| ^ ^ :
| | '- - - - - - - - - --. :
| | : :
| '-------------------. : :
| | : :
| ,--[Object object "proto2"]--. | : :
| | | | : :
'------- constructor | | : :
| [[Prototype]] - - - - - - - - - - - - - - - - - - - --'
| ... | | :
`----------------------------' | :
^ ^ | :
| '- - - - - - - - - - - - - - - - - - - --.
| | : :
'----------------------------------. :
| : | :
| : | :
,--[Function object "x"]-----. | : | :
| | | : | :
| prototype --------------------' : | :
| ... | : | :
`----------------------------' : | :
^ : | :
.----------------' : | :
| : | :
1. | ,--[Object object "x1"]------. : | :
| | | : | :
'--- constructor | : | :
| [[Prototype]] - - - - - - - - - - -' | :
| ... | | :
`----------------------------' | :
| :
,--[Function object "y"]-----. | :
| | | :
| prototype ------------------------------------' :
| ... | :
`----------------------------' :
^ :
.----------------' :
| :
2. | ,--[Object object "x2"]------. :
| | | :
'--- constructor | :
| [[Prototype]] - - - - - - - - - - - - - - - - - - - - --'
| ... |
`----------------------------'

Benjy: The proprietary `__proto__' property of JavaScriptâ„¢ objects allows
direct access to the internal [[Prototype]] property. Objects in other
ECMAScript implementations don't have it.¹


PointedEars
___________
¹ Confirmed for JScript (in IE/MSHTML), Opera ECMAScript,
and KJS (in KHTML and WebKit).
 
T

Thomas 'PointedEars' Lahn

Benjy said:
My apologies for the syntax errors but thanks for your help Thomas
Lahn.

You are welcome. And call me Thomas or PointedEars (in references you may
use "PE", appears to have been widely adopted).
Thomas said:
If you do this, `F' is a bound variable in the returned function (as
understood in closures), meaning that all objects you create with clone()
are "F objects" and thus share the same prototype chain. You really don't
want that. Using closures to increase efficiency is usually commendable but
counterproductive here.

This got me thinking because that is what I thought was going to
happen when I read this code. However, this is not the results I am
seeing: [...]

I was wrong, see <

Regards,

PointedEars
 
J

John G Harris

Note that if you do this you overwrite the default prototype object which
includes the `constructor' property. There are two possibilities to work
around that: redefine the `constructor' property in your prototype object
(here referred to by proto_widgetA, but the variable is unnecessary), or
only add/overwrite properties in a loop.
<snip>

Or notice that the 'constructor' property isn't used and don't bother
creating it.

Elsewhere, if objects are created by beget, aka create, aka clone, there
isn't a sensible constructor function to point to.

John
 
T

Thomas 'PointedEars' Lahn

kangax said:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Only through /AssignmentExpression/? What about these cases? I don't see
/AssignmentExpression/'s here:


(function(){
...
return function(){}();
^^^^^^^^^^^^^^
...
})();

typeof function(){}();
^^^^^^^^^^^^^^

Those are ExpressionStatements.
through ExpressionStatement.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
[...] the prototype chain of an object is not defined indirectly through
the instance-constructor-prototype relationship but directly through the
internal [[Prototype]] property which is set on creation of the object. [...]
Maybe I will modify my inheritance method accordingly.

I am surprised to hear you're not reusing "dummy" function in
"clone"/"inherit"/"beget", as explained and recommended by Cornford as
far back as few years ago (don't have link to his post at the moment).

Probably I overlooked it then, too.
Yep. Makes perfect sense after careful observation.

Thanks, but you wouldn't have needed to quote it in full (although it
demonstrates that it can even be quoted :))
[...]
Benjy: The proprietary `__proto__' property of JavaScriptâ„¢ objects allows
direct access to the internal [[Prototype]] property. Objects in other
ECMAScript implementations don't have it.¹

WebKit-based environments have had `__proto__` for a while now.

Unfortunately, Safari doesn't run "at home" (where I wrote that article).
Something in it is incompatible with WINE or vice-versa. Hence the footnote.
Blackberry's proprietary implementation had it too, las time I checked
(not sure if they are using webkit).

However, your statement is not supported by the documentation¹.

If there was another ECMAScript implementation to consider, that would be
rather important for me to know at this point. As I have not access to a
BlackBerry, and the documentation¹ doesn't appear to help here², could you
please provide the value of navigator.userAgent or other information which
might provide some insight as to that?

Also, FF3.5 has (soon-to-be-standard)
^^^^^^^^^^^^^^^^^^^^^
We'll see. So far it is only a *working draft*.
ES5's `Object.getPrototypeOf`, probably as a replacement for proprietary
`__proto__`.

Good to know, thanks. One wonders, though, when ES 5 would draw
considerable attention by other vendors so that this would become
a really useful fact.


PointedEars
 
T

Thomas 'PointedEars' Lahn

kangax said:
Thomas said:
kangax said:
Thomas 'PointedEars' Lahn wrote:
kangax wrote:
[...]
Benjy: The proprietary `__proto__' property of JavaScriptâ„¢ objects allows
direct access to the internal [[Prototype]] property. Objects in other
ECMAScript implementations don't have it.¹
WebKit-based environments have had `__proto__` for a while now.
Unfortunately, Safari doesn't run "at home" (where I wrote that article).
Something in it is incompatible with WINE or vice-versa. Hence the footnote.

JFYI: Finally, I got Safari 4 working on WINE with `winetricks' as described
on <http://alicious.com/2009/safari-4-on-linux-with-wine-update/>

(AFAICS, one of iphlpapi.dll, core fonts, and Flash Player plugin was missing.)

That is, the layout and script engines are working, so the Matrix's test
cases can run. Too bad that neither `javascript:' in the Location Bar (or
whatever Apple calls it) nor the Web Inspector/Error Console are usable, though.
Have you tried installing Chromium on Linux? I've heard they had
significant progress in that "field".

$ aptitude show chromium | grep ^Description:
Description: fast paced, arcade-style, scrolling space shooter

"BlackBerry9500/4.7.0.41 Profile/MIDP-2.0 Configuration/CLDC-1.1
VendorID/-1"

Hmmm, doesn't look like WebKit. Apparently there is a another /doc I have
to dig through.
And yes, `__proto__` exists there, although I haven't checked if it's
functional.

Please do and report back here.
IE8 is another browser that implemented parts of ES5.
`Object.defineProperty` and `JSON.stringify/parse` come to mind. Note
that FF3.5 and currently beta Chrome 3 also implement
`JSON.stringify/parse`.

The Matrix has you.

JFTR: I'm going to look into the ES grammar issue later.


PointedEars
 
R

RobG

Oh, forgot about that. I personally prefer to use the factory pattern
rather than constructors to create objects. It has a neater syntax and
does exactly what you want. The down side is that instanceof doesn't
work:

function makeRoot () {
this = {}

ECMA-262 Sect. 10.1.7
"...The this value associated with an execution
context is immutable."

You can't assign a value to the this keyword, the above code is never
executed.
this.dom = document.createElement('div');
}

function makeWidgetA () {
this = makeRoot();

If you could assign to the this keyword, its value would be undefined
since makeRoot has no return statement.
}

var a = makeWidgetA();

As above. If this statement was actually evaluated, a would be
undefined.
 
T

Thomas 'PointedEars' Lahn

kangax said:
Do you know of some other way to check engine being used?

At this point (without nearly complete ES Matrix, without RTSL) none that
would not be based on weak inference.
I remember something about webkit returning "//" for `new RegExp('').toString()`,
while all (?) other browsers would result in - "(?:)".

Blackberry returns former one, which is why I thought it is based on webkit.

That's what I mean.
Amazingly, __proto__ is readable, writable and even restorable (contrary
to FF, IIRC)

Thanks. And you are somewhat right, after `__proto__ = null' the property
cannot be restored; other first assignments keep it working, though.
(Firebug 1.4X.0b8 in Iceweasel 3.5 [JavaScript 1.8.1 TraceMonkey] shows
"true, true, undefined, undefined, false" for your test code.)


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,701
Latest member
XavierQ83

Latest Threads

Top