inheritance question

P

petermichaux

Hi,

Hopefully the group doesn't mind an(other) inheritance question. Maybe
the prototype inheritance style is starting to become a low dim light
in my brain...probably not yet.

----

If I do the following...

var a = document.getElementById("my_div");

var b = new Object();
b.prototype = a;
b.new_property = function(){alert("the new property!");

Now b has the new property. Also, b has all the properties of a.

----

Is it possible to do this more efficiently with a constructor?
Something like...

function B(element){
// what goes here?
}
B.prototype.new_property = function(){alert("the new property!")};

var a = document.getElementById("my_div");
var b = new B(a);

This way I could efficiently make many b-type objects based on
different a-type objects without having to attach new_property
explicitly to each new b-type object.
 
P

petermichaux

I keep thinking I should be able to do this but it doesn't work.

function B(element){
this.prototype = element;
}
B.prototype.new_property = function(){alert("the new property!")};

var a = document.getElementById("my_div");
var b = new B(a);
 
V

VK

Hi,

Hopefully the group doesn't mind an(other) inheritance question. Maybe
the prototype inheritance style is starting to become a low dim light
in my brain...probably not yet.

----

If I do the following...

var a = document.getElementById("my_div");

var b = new Object();
b.prototype = a;
b.new_property = function(){alert("the new property!");

Now b has the new property. Also, b has all the properties of a.

Uhmm... Who told you that? a is a reference to a DOM object (presumably
DIV), b is a reference to JavaScript object. They are completely
different species. Did you try say alert(b.tagName) before posting?

Withing JavaScript program you have to deal with JavaScript objects.
But you can store references onto DOM in these objects.

<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">
function B(dom_obj) {
this.$DOM = dom_obj;
this.new_property = B.new_property;
}
B.new_property = function() {
var msg = 'new property of ' + this.$DOM.id;
window.alert(msg);
}
function init() {
var a = document.getElementById("myDiv");
var b = new B(a);
b.new_property();
}
window.onload = init;
</script>
</head>

<body>
<div id="myDiv">&nbsp;</div>
</body>
</html>

btw underscores are not allowed (though tolerated on many UA's) in
element ID, so my_div is changed to myDiv.
 
M

Michael Winter

On 28/03/2006 10:11, VK wrote:

[snip]
function B(dom_obj) {
this.$DOM = dom_obj;
this.new_property = B.new_property;
}
B.new_property = function() {
var msg = 'new property of ' + this.$DOM.id;
window.alert(msg);
}

The method, new_property, should be a property of the prototype object
for the B constructor function. It is not, in any way, useful as a
'class' method.

[snip]
btw underscores are not allowed (though tolerated on many UA's) in
element ID, so my_div is changed to myDiv.

ID and NAME tokens must begin with a letter ([A-Za-z]) and may
be followed by any number of letters, digits ([0-9]), hyphens
("-"), underscores ("_"), colons (":"), and periods (".").
^^^^^^^^^^^^^^^^^
-- 6.2 SGML basic types, HTML 4.01

Mike
 
P

petermichaux

VK said:
Uhmm... Who told you that? a is a reference to a DOM object (presumably
DIV), b is a reference to JavaScript object. They are completely
different species.

Say what?! This sounds extremely strange. I thought that a JavaScript
variable could hold either a primative or a reference to a JavaScript
object. I also thought that document.getElementById() returned a
JavaScript object ("instance" of Element "class"). I didn't think there
were other kinds of objects other than JavaScript objects. Perhaps
document.getElementById() returns a DOM object wrapped in a JavaScript
object?

Thanks,
Peter
 
C

Csaba Gabor

Say what?! This sounds extremely strange. I thought that a JavaScript
variable could hold either a primative or a reference to a JavaScript
object. I also thought that document.getElementById() returned a
JavaScript object ("instance" of Element "class"). I didn't think there
were other kinds of objects other than JavaScript objects. Perhaps
document.getElementById() returns a DOM object wrapped in a JavaScript
object?

You may find the following year old (March 16, 2005) thread and
subthreads dealing with this issue interesting:
http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/e26f83c684a5f892/

Csaba Gabor from Vienna
 
M

Michael Winter

Yes, it does.

No, it doesn't. Firstly, the prototype property is only significant for
constructor functions. When an object is created using that function and
the new operator, the object referenced by the prototype property of the
constructor is assigned to the internal [[prototype]] property of the
newly created object. It is this internal property that is used when
trying to lookup an object property. See section 8.6.2.1 [[Get]](P) in
ECMA-262. The new object will not have a prototype property.

[snip]
Say what?! This sounds extremely strange.

The next thing to note is that there are two broad types of object:
native objects, and host objects.

Native objects are specified by ECMA-262 and include Object, Function,
Array, Math, String, Number, Date, and RegExp. The objects in that list
are also known as built-in objects, as they are available from the
outset of execution. User-defined objects (created using constructor
functions) are also native objects.

Host objects are provided by the environment. All DOM objects are host
objects, as are the 'DOM 0' objects such as location. In IE, ActiveX
objects are also of this category.

Whilst native objects must act as described by ECMA-262, host objects
are at the whim of the implementation in many regards. For instance, in
Gecko browsers, DOM objects have prototype properties that can be
modified to affect relevant DOM nodes, and DOM objects can be the
prototype object of constructor functions. In IE, neither is the case,
but this is permitted.

[snip]

Hope that helps,
Mike
 
L

Lasse Reichstein Nielsen

var a = document.getElementById("my_div");

var b = new Object();
b.prototype = a;
b.new_property = function(){alert("the new property!");

Now b has the new property. Also, b has all the properties of a.

No. It has two new properties. One called "new_property" and one
called "prototype". They are both plain properties, with no relevant
difference.

Assigining to a property called "prototype" on an object does not
change that object's actual prototype.
Is it possible to do this more efficiently with a constructor?

You have to use constructors to create a prototype link in Javascript,
so if it can be done, it is done with prototypes.
Something like...

function B(element){
// what goes here?
}
B.prototype.new_property = function(){alert("the new property!")};

var a = document.getElementById("my_div");
var b = new B(a);

Try
function B() {
this.new_property = function() {alert("the new property");};
}
var a = document.getElementById("my_div");
B.prototype = a;
var b = new B();

This uses B as a constructor, creating a new object (as constructors
do) with "a" as the prototype object of the object.
This way I could efficiently make many b-type objects based on
different a-type objects without having to attach new_property
explicitly to each new b-type object.

If that's the goal, try:

function B(a) {
function Dummy(){};
Dummy.prototype = a;
var b = new Dummy();
b.new_property = function(){alert("the new property!");
return b;
}

Again, you have to use a constructor to create a new object with
an existing object as its prototype. Javascript does not make that
as easy as I would have liked. The clone function tries to
wrap this up and allow a direct way to create new objects inheriting
from existing ones.


/L
 
V

VK

Say what?! This sounds extremely strange. I thought that a JavaScript
variable could hold either a primative or a reference to a JavaScript
object. I also thought that document.getElementById() returned a
JavaScript object ("instance" of Element "class"). I didn't think there
were other kinds of objects other than JavaScript objects.

That's a very common mistake so don't be ashame. In the reality
JavaScript context has nothing in common with DOM tree - but it is able
to communicate with DOM over host object methods.

"East is East, and West is West, and never the twain shall meet" :)

Actually they shall meet - over DOM interface, but not in such
straightforward way as you originally thought. Did my code snipplet
solve your current task or you need some more help?
 
P

petermichaux

VK said:
Did my code snipplet solve your current task or you need some more help?

Yes it did help but not really the way I was trying to go with my idea.
I was hoping to get to a place where i could efficiently set up to say
things like "b.style.background = " where b has inherited from the
element. This would be instead of the second option of b *having* an
element like and saying "b.$DOM.style.background = ". All these posts
have made me realize I should be using the second of these options
since the host objects are such special cases and potentially not
compatible across browsers. Seems like extending a host object through
inheritance is a touchy subject that may not work with the other things
I'm doing. The second option is not limiting me. It just doesn't
emphasize what I was thinking. The second option feels a little more
like a C struct than an object-oriented style of code.

Another thing I've realized is the book I have "JavaScript: The
Definitive Guide 4th edition" by David Flanigan (the rhino book from
O'Reilly) which covers JavaScript 1.5 is no where near definitive when
it comes to the 24-page objects chapter. Also, the book is four years
old now and the way people are coding JavaScript has probably changed a
little over time. Any suggestions for a newer and better book on
JavaScript objects?

Thanks,
Peter
 
P

petermichaux

Hi Lasse,

Thanks for more great info. I realize this thread is much like the last
one you helped me with. The new slant on things really messed me up.

Assigining to a property called "prototype" on an object does not
change that object's actual prototype.

Good to know!

If that's the goal, try:

function B(a) {
function Dummy(){};
Dummy.prototype = a;
var b = new Dummy();
b.new_property = function(){alert("the new property!");
return b;
}


This doesn't seem so efficient since every property like "new_property"
has to be attached to every new object that inherits from a.

The clone function tries to
wrap this up and allow a direct way to create new objects inheriting
from existing ones.

By clone function you mean your B function above?


Thanks,
Peter
 
L

Lasse Reichstein Nielsen

I was hoping to get to a place where i could efficiently set up to say
things like "b.style.background = " where b has inherited from the
element. This would be instead of the second option of b *having* an
element like and saying "b.$DOM.style.background = ". All these posts
have made me realize I should be using the second of these options
since the host objects are such special cases and potentially not
compatible across browsers.

I wouldn't worry about them being host objects, unless I planned to
put them back into the DOM document structure. I *would* worry that
writing "b.className='foo'" does not change the class attribute of
the element object, and is instead set on the extending object.

A saying from the class based world seems to apply to prototype
based inheritance as well:
"Favor composition over inheritance"
I.e., it's often better to have a reference to a DOM object than to
inherit it. When you inherit, you receive all the features of the
inherited object, not just the ones you need. Also, since you can only
inherit from one object, doing it unnecessarily constrains you from
inheriting something else.
Seems like extending a host object through inheritance is a touchy
subject that may not work with the other things I'm doing.

That depends on what you are doing, and it's not just host objects.
Any object with a non-standard [[Put]] implementation will not
grant that to the inheriting object.
E.g., Inheriting from an array also fails to have the inheriting
object act as an array. Setting array properties or the "length"
property does not carry through to the array.
The second option is not limiting me. It just doesn't emphasize what
I was thinking. The second option feels a little more like a C
struct than an object-oriented style of code.

Indeed. But adding a method like
function style(){ return this.$DOM.style; }
to the wrapper would hide how the reference is kept and expose an
interface to access it.

/L
 
L

Lasse Reichstein Nielsen

This doesn't seem so efficient since every property like "new_property"
has to be attached to every new object that inherits from a.

Indeed. You inherit from the value that varies and extends by the
one that doesn't. The opposite is probably smarter.
As commented elsewhere in this thread, you might not want to extend
from the DOM object just to make its properties easily available.
The result isn't really a DOM object, so inheritance is conceptually
not really correct.

The opposite version would be:
function B(a);
this.element = a;
}
B.prototype.new_property = function(){alert("the new property!");
B.prototype.style = function style(){return this.element.style;};
/// a = something
var b = new B(a);
b.style().backgroundColor="red";

By clone function you mean your B function above?

I mean the function I used earlier:

function clone(object) {
function Dummy(){};
Dummy.prototype = object;
return new Dummy();
}

It creates new objects inheriting from existing objects without
exposing the constructor function used.
You can use the companion function to check whether one object
inherits from another:

function inheritsFrom(object, potentialAncestor) {
function Dummy(){};
Dummy.prototype = potentialAncestor;
return object instanceof Dummy;
}

Javascript tries to hide the creation of the prototype link and
to look like class based instantiation by using the constructor
functions. Much of the time it gets away with it, but at its
heart, Javascript is not class based. It just pretends to be
if you are not looking too hard.

/L
 
T

Thomas 'PointedEars' Lahn

I keep thinking I should be able to do this but it doesn't work.

I will mark the order of evaluation/execution so that you see your error.

1. Variable instantiation, declaring the constructor
function B(element){

7. Assignment in constructor context
this.prototype = element;
}

4. AssignmentExpression in global context
B.prototype.new_property = function(){alert("the new property!")};

2. Variable instantiation, VariableStatement in global context
5. AssignmentExpression in global context
var a = document.getElementById("my_div");

3. Variable instantiation, VariableStatement in global context
6. AssignmentExpression in global context, calling the constructor
and evaluating to an object reference (NewExpression)
var b = new B(a);

Use a debugger next time.


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,774
Messages
2,569,599
Members
45,165
Latest member
JavierBrak
Top