Puzzling question about JS prototypes

J

javadesigner

Hi:

Consider this:
-----------------------------
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
var f = new foo(); //Y
foo.prototype = bar.prototype; //X
alert (f.y);
------------------------------

This results in alerting undefined

Now consider this:
------------------------------------
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
foo.prototype = bar.prototype; //X
var f = new foo(); //Y
alert (f.y);
----------------------------------

This alerts 'hello'

The only difference between the two examples is that line marked X and
Y have been switched. But prototypes are dynamic, so why does the
first example NOT alert 'hello' ???

Best regards,
--j
 
J

John G Harris

Hi:

Consider this:

Here foo.prototype holds a newly created default prototype chain.
var f = new foo(); //Y

Now f's prototype chain is that default prototype chain assigned from
foo.prototype.
foo.prototype = bar.prototype; //X

Now the value in foo.prototype has been replaced, but that doesn't alter
earlier assignments.
alert (f.y);
------------------------------

This results in alerting undefined

Now consider this:
------------------------------------
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
foo.prototype = bar.prototype; //X

Now the value in foo.prototype has been replaced.
var f = new foo(); //Y

So here f has the prototype chain that was copied from bar.prototype.
alert (f.y);
----------------------------------

This alerts 'hello'

The only difference between the two examples is that line marked X and
Y have been switched. But prototypes are dynamic, so why does the
first example NOT alert 'hello' ???

They may be dynamic, whatever that means, but they don't reach backwards
in time. Each object holds a direct reference to the prototype chain it
was given at construction. It doesn't access its prototype chain via the
creating function.

John
 
T

Thomas Allen

Hi:

Consider this:
-----------------------------
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
var f = new foo();              //Y
foo.prototype = bar.prototype;  //X
alert (f.y);
------------------------------

This results in alerting undefined

Now consider this:
------------------------------------
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
foo.prototype = bar.prototype;   //X
var f = new foo();               //Y
alert (f.y);
----------------------------------

This alerts 'hello'

The only difference between the two examples is that line marked X and
Y have been switched. But prototypes are dynamic, so why does the
first example NOT alert 'hello' ???

What I find interesting is that the first also example works if you
specify the property explicitly:

function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
var f = new foo();
foo.prototype.y = bar.prototype.y;
alert (f.y);

Thomas
 
J

javadesigner

John:

They may be dynamic, whatever that means, but they don't reach backwards
in time. Each object holds a direct reference to the prototype chain it
was given at construction. It doesn't access its prototype chain via the
creating function.

You formulated this extremely well. By dynamic, I meant (and thought)
that each
object, dynamically, accessed it's prototype chain via the creating
function at runtime,
everytime.

As you point out, interestingly, the prototype chain for an object is
"baked-in" at that
object's creation time..

Best regards,
--j
 
R

RobG

What I find interesting is that the first also example works if you
specify the property explicitly:

function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
var f = new foo();
foo.prototype.y = bar.prototype.y;

That adds the y property to foo.prototype, it doesn't replace
foo.prototype as occurred in the OP.

f inherits from foo.prototype because its internal [[prototype]]
property references it. Once that relationship is established, it
can't be changed however new properties can be added to the prototype
and f will "inherit" them.
 
G

Gregor Kofler

Am Mon, 06 Apr 2009 12:51:48 -0700 schrieb Thomas Allen:
What I find interesting is that the first also example works if you
specify the property explicitly:

Why? Augmenting prototypes is common practice.
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
var f = new foo();
foo.prototype.y = bar.prototype.y;
alert (f.y);

foo.prototype.y gets (re-)assigned. Whether this assignment stems from
another prototype doesn't matter.

Gregor
 
T

Thomas Allen

On Apr 6, 3:22 pm, (e-mail address removed) wrote:
What I find interesting is that the first also example works if you
specify the property explicitly:
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
var f = new foo();
foo.prototype.y = bar.prototype.y;

That adds the y property to foo.prototype, it doesn't replace
foo.prototype as occurred in the OP.

f inherits from foo.prototype because its internal [[prototype]]
property references it. Once that relationship is established, it
can't be changed however new properties can be added to the prototype
and f will "inherit" them.

Got it, thanks for the clarification.

Thomas
 
J

Jorge

(...)
As you point out, interestingly, the prototype chain for an object is
"baked-in" at that
object's creation time..

Right. But note that 'instanceof' checks -instead- at runtime against
the *current* prototype of the constructor.

f= new foo();
f instanceof foo; //-> true

foo.prototype= {};
f instanceof foo; //-> false
 
J

javadesigner

Right. But note that 'instanceof' checks -instead- at runtime against
the *current* prototype of the constructor.

f= new foo();
f instanceof foo; //-> true

foo.prototype= {};
f instanceof foo; //-> false

This is quite confusing.

I thought that it had something to do with the constructor property,
so I tried saying (as per your example):

foo.prototype = {}
foo.prototype.constructor = foo; //added this line

f instanceof foo; //-> false

Can you explain why this is happening a bit further ?
 
J

Jorge

This is quite confusing.

I thought that it had something to do with the constructor property,
so I tried saying (as per your example):

foo.prototype = {}
foo.prototype.constructor = foo;   //added this line

f instanceof foo; //-> false

Can you explain why this is happening a bit further ?

Yes, read this recent thread:

http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/410fb4c180bc16a0

To cut a long story short, instanceof returns : (*current*
constructor's prototype) is in (object's prototype *chain*).
 
L

Lasse Reichstein Nielsen

Hi:

Consider this:
-----------------------------
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
var f = new foo(); //Y
foo.prototype = bar.prototype; //X
alert (f.y);
------------------------------

This results in alerting undefined

Now consider this:
------------------------------------
function bar() { } ;
bar.prototype.y = 'hello';
function foo() { };
foo.prototype = bar.prototype; //X
var f = new foo(); //Y
alert (f.y);
----------------------------------

This alerts 'hello'

The only difference between the two examples is that line marked X and
Y have been switched. But prototypes are dynamic,

No, prototypes are not dynamic. Or rather: The prototype chain of an
object is not dynamic. The properties on those objects are.
so why does the first example NOT alert 'hello' ???

Because the prototype of f is the original value of foo.prototype,
because that was the value when f was created.

Constructor functions are simple factories. They create an object, and
afterwards, they have no relation to the object at all.

/L
 
T

Thomas 'PointedEars' Lahn

This is quite confusing.

I thought that it had something to do with the constructor property,
so I tried saying (as per your example):

foo.prototype = {}
foo.prototype.constructor = foo; //added this line

f instanceof foo; //-> false

Can you explain why this is happening a bit further ?

The second assignment is irrelevant. Per the first assignment, the object
being referred to by `foo.prototype' is a different one than before, and
that object is not in the prototype chain of the object `f' refers to.

1. function foo() {} foo ---> [Function object]
^ '-- prototype --> [Object object 1]
constructor | ^
| |
2. f = new foo(); f -----> [foo object] |
'--- [[Prototype]] ---'

3. foo.prototype = {}; foo ---> [Function object]
'-- prototype --> [Object object *2*]

4. foo.prototype.constructor = foo;

foo ---> [Function object] <---------------------.
^ '-- prototype --> [Object object 2] |
constructor | '-- constructor --'
|
5. f instanceof foo; f -----> [foo object]
'-- [[Prototype]] --> [Object object *1*]

Test case for Firebug[1] (Fb) or Jesse Ruderman's JavaScript Shell[2] (JSSh)
in Firefox/Iceweasel (comments are the string representations):

/* `function F() { 42; }' (in JSSh without output) */
function F() { 42; }

/* `Object' (in Fb only; because the prototype chain is: o --> F.prototype
--> Object.prototype) */
var o = new F();

/* `true' */
o.__proto__ === F.prototype;

/* `Object' (Fb) or `[object Object]' (JSSh) (because `{}' is equivalent to
`new Object()') */
F.prototype = {};

/* `false'; see above */
o.__proto__ === F.prototype;

/* `F()' (Fb) or `function F() {\n}' (JSSh) see above */
o.constructor


PointedEars
___________
[1] <http://getfirebug.com/>
[2] <http://www.squarefree.com/shell/>
 
J

John G Harris

On Mon, 6 Apr 2009 at 16:40:22, in comp.lang.javascript, Jorge wrote:

To cut a long story short, instanceof returns : (*current*
constructor's prototype) is in (object's prototype *chain*).

That's rather misleading. instanceof knows nothing about constructors,
current or otherwise.

Suppose you do

x instanceof f

If f is not a function then it's an error. If f is a function then
instanceof is true if any object in x's prototype chain is the same
object as f.prototype, otherwise it is false (including if x is not an
object).

instanceof doesn't care if f has been used as a constructor in your
application. It just cares if f is an object that can do the test, which
it can if it is any function.

John
 
J

Jorge

On Mon, 6 Apr 2009 at 16:40:22, in comp.lang.javascript, Jorge wrote:



That's rather misleading. instanceof knows nothing about constructors,
current or otherwise.
(...)

(object) instanceof (constructor);
 
J

John G Harris

(object) instanceof (constructor);

No, it's
(object) instanceof (function)

You can declare a function that does nothing, assign a useful prototype
chain to its prototype property, then use the function in your
instanceof tests. Whether this is going to be a popular thing to do is a
different discussion.

John
 
J

Jorge

(...)
You can declare a function that does nothing, assign a useful prototype
chain to its prototype property, then use the function in your
instanceof tests. Whether this is going to be a popular thing to do is a
different discussion.

Yes it's a very popular pattern:

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

but obviously not for the reason you state. See:
http://javascript.crockford.com/prototypal.html
^^^^^^^^^^^

HTH :)
 
J

Jorge

That's a pattern for people who can't remember to type 'new' when
creating a new object, not for use with instanceof.

The perfect pattern to build an inheritance chain: d inherits from c
that inherits from b that inherits from a:

d= object(c= object(b= object(a= {})));

Try to write that in a single line using 'new'...
 
J

John G Harris

John said:
That's a pattern for people who can't remember to type 'new' when
creating a new object, not for use with instanceof.

Or for people who might deliberately wish to *not* invoke `new` as
`new` happens to call its operand's [[Construct]] with all of the
expected consequences. This pattern is a dissected [[Construct]]
intended to set up [[Prototype]] without calling constructor (as
constructor invocation is often too obtrusive for such simple task as
changing [[Prototype]])

Er, ... you can't *change* [[Prototype]].

John
 

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,175
Latest member
Vinay Kumar_ Nevatia
Top