"x.constructor == Foo" vs "x instanceof Foo"

K

kj

My book (Flanagan's JavaScript: The Definitive Guide, 5th ed.)
implies on page 111 that the following two constructs are equivalent:

( x.constructor == Foo )

and

( x instanceof Foo )

The author states that the instanceof operator computes its result
by examining the value of its first argument's the constructor
property.

However, I've recently ran into a situation that contradicts this.

I've been trying to understand jQuery better, with the aid of
Firefox's Firebug debugger. At one breakpoint, there's one variable
(I'll call it x) for which

x instanceof jQuery

is true, but

x.constructor == jQuery

is false.

In fact, x.constructor is Object, but (Object instanceof jQuery)
is false.

Could anyone explain to me what's going on?

TIA!

Kynn
 
L

liamgegan

My book (Flanagan's JavaScript: The Definitive Guide, 5th ed.)
implies on page 111 that the following two constructs are equivalent:

( x.constructor == Foo )

and

( x instanceof Foo )

The author states that the instanceof operator computes its result
by examining the value of its first argument's the constructor
property.

However, I've recently ran into a situation that contradicts this.

I've been trying to understand jQuery better, with the aid of
Firefox's Firebug debugger. At one breakpoint, there's one variable
(I'll call it x) for which

x instanceof jQuery

is true, but

x.constructor == jQuery

is false.

In fact, x.constructor is Object, but (Object instanceof jQuery)
is false.

Could anyone explain to me what's going on?

TIA!

Kynn

I know that there are difference in the way that instanceof is
determined vs. x.constructor. In this instance it sounds like it's an
issue with the way that JQuery handles it's extends functionality. Not
having used JQuery a great deal, could you shed some light on the way
that JQuery extends?
 
K

kj

In said:
I know that there are difference in the way that instanceof is
determined vs. x.constructor. In this instance it sounds like it's an
issue with the way that JQuery handles it's extends functionality. Not
having used JQuery a great deal, could you shed some light on the way
that JQuery extends?

That went over my head! :) But I'll do my best...

The jQuery object does have an extend method, if that's what you're
asking. It can be invoked in a few ways, but probably the most
general one is something like

jQuery.extend( bool, target, obj1, obj2, obj3 ... );

If bool is false, extend copies values from obj1, obj2, obj3, etc.
into the corresponding slots in target. If bool is true, instead
of copying it extends the slots when the the contents of both the
target and source slots are themselves are objects. (That's a very
broad-strokes description!)

But I find your question also puzzling, because it suggests that
"extends" is a function that, when available, gets called automatically
by the interpreter in certain situations, just like, e.g., valueOf
or toString. If this is the case then I'm even more mystified than
before, because I've never heard of such a thing. (FWIW, Flanagan
doesn't even *mention* extend.)

Kynn

P.S. I really need to get myself an authoritative reference on
JavaScript... I thought that Flanagan's book was it, but just
today I've run into a few topics (such as the const keyword) that
Flanagan doesn't even *mention*. I'm wondering if "extend" will
be another such blind spot...
 
J

Joost Diepenmaat

kj said:
My book (Flanagan's JavaScript: The Definitive Guide, 5th ed.)
implies on page 111 that the following two constructs are equivalent:

( x.constructor == Foo )

and

( x instanceof Foo )

They're not. For one thing, obj.constructor does the wrong thing when
the constructor has a prototype assigned to it, since the constructor is
actually determined by the prototype.

function Super() {}
function Sub() {}
Sub.prototype = new Super(); // note: this is wrong, but since it
// but everybody does it and it works.
// more or less.
// unless you actually want to read the
// the constructor later

var sub = new Sub(); // like here, sub.constructor == Super!

alert(sub.constructor == Sub); // false
alert(sub.constructor == Super); // true
alert(sub instanceof Sub); // true
alert(sub instanceof Super); // true

also, instanceof checks the full prototype chain, while obj.constructor
can only be a single value, so it's useless for inherited objects.
The author states that the instanceof operator computes its result
by examining the value of its first argument's the constructor
property.

However, I've recently ran into a situation that contradicts this.

As shown above, you're right. One of the problems is that you can't
access an object's prototype directly, you apparently have to use
obj.constructor.prototype, *but* obj.constructor is read from the
objects's prototype, which is why replacing a constructor's prototype
outright leads to issues. My current strategy in those cases where I
need access to the constructor directly is to merge properties into the
existing prototype instead.

Joost.
 
K

kj

They're not. For one thing, obj.constructor does the wrong thing when
the constructor has a prototype assigned to it, since the constructor is
actually determined by the prototype.
function Super() {}
function Sub() {}
Sub.prototype = new Super(); // note: this is wrong, but since it
// but everybody does it and it works.
// more or less.
// unless you actually want to read the
// the constructor later
var sub = new Sub(); // like here, sub.constructor == Super!
alert(sub.constructor == Sub); // false
alert(sub.constructor == Super); // true
alert(sub instanceof Sub); // true
alert(sub instanceof Super); // true
also, instanceof checks the full prototype chain, while obj.constructor
can only be a single value, so it's useless for inherited objects.
As shown above, you're right. One of the problems is that you can't
access an object's prototype directly, you apparently have to use
obj.constructor.prototype, *but* obj.constructor is read from the
objects's prototype, which is why replacing a constructor's prototype
outright leads to issues. My current strategy in those cases where I
need access to the constructor directly is to merge properties into the
existing prototype instead.


Thank you very much! Your post (and liamgegan's) finally clarified
the matter for me. Indeed, in the jQuery source, I see that
jQuery.prototype gets assigned an anonymous object...

kynn
 
L

liamgegan

That went over my head! :) But I'll do my best...

The jQuery object does have an extend method, if that's what you're
asking. It can be invoked in a few ways, but probably the most
general one is something like

jQuery.extend( bool, target, obj1, obj2, obj3 ... );

If bool is false, extend copies values from obj1, obj2, obj3, etc.
into the corresponding slots in target. If bool is true, instead
of copying it extends the slots when the the contents of both the
target and source slots are themselves are objects. (That's a very
broad-strokes description!)

But I find your question also puzzling, because it suggests that
"extends" is a function that, when available, gets called automatically
by the interpreter in certain situations, just like, e.g., valueOf
or toString. If this is the case then I'm even more mystified than
before, because I've never heard of such a thing. (FWIW, Flanagan
doesn't even *mention* extend.)

Kynn

P.S. I really need to get myself an authoritative reference on
JavaScript... I thought that Flanagan's book was it, but just
today I've run into a few topics (such as the const keyword) that
Flanagan doesn't even *mention*. I'm wondering if "extend" will
be another such blind spot...

Sorry, I didn't mean to confuse :D

Extends functionality is unavailable in Javascript, but is a
fundamental feature of other OOP languages (including AS 2+ [also
ECMA]). In Javascript as in AS1, Extends functionality needed to be
simulated in one of 3 ways, each with advantages of their own (but
also with many and varied problems):
a) copy all methods from subclass into superclass and provided an
implemented constructor. I always hated this way as it's more
implementation than an extension.
b) sub.__proto__ = super.prototype; This seems to be the most correct
type to me, but can easily break down expected behaviour in the sub/
super relationship if you don't understand it properley;
c) sub.prototype = new Super(); Probably the most used method, but the
class instanciation always seemed superfluous to me.
 
T

Thomas 'PointedEars' Lahn

Joost said:
They're not.

True. I wonder how long it will take until everybody recognizes that
Flanagan actually has no clue what he is writing about.
For one thing, obj.constructor does the wrong thing when the constructor
has a prototype assigned to it, since the constructor is actually determined
by the prototype.

The constructor is the Function object that was used to create the object.
It has a `prototype' property implicitly. It is not that this property is
assigned a value that makes the `constructor' property of the created object
useless, but when this value is not an object that provides a user-defined
`constructor' property to refer to the constructor.
function Super() {}
function Sub() {}
Sub.prototype = new Super(); // note: this is wrong, but since it
// but everybody does it and it works.

Not everybody does it, as it does not work, because it is wrong. This
statement does not add Super.prototype to the prototype chain of Sub
objects; it adds a newly created Super object there:

new Sub() --> Sub.prototype --> new Super() --> Super.prototype --> ...
--> Object.prototype

So there is no real prototype-based inheritance anymore as any property
value that is defined for Super objects only in their constructor is
inherited from that object through the prototype chain, even though
Super.prototype does not need to have that property or provides a different
default value for it.

One way to do it properly is this oft-recommended approach:

function extend(P)
{
function Dummy() {}
Dummy.prototype = P;
return new Dummy();
}

Sub.prototype = extend(Super.prototype);

The resulting prototype chain is then

new Sub() --> Sub.prototype === new Dummy() --> Dummy.prototype ===
Super.prototype --> ... --> Object.prototype

as it should be. (A prototype object is inserted into the prototype chain.)
// more or less.

It fails whenever prototype properties are involved, for example. Search
the newsgroup for details.


PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
True. I wonder how long it will take until everybody recognizes that
Flanagan actually has no clue what he is writing about.

For some reason /nobody/ I've read gets OO javascript right except
Crockford. And I just looked up that page in Flanagan, and he *does*
just outright say instanceof checks the constructor property. He should
know better.
The constructor is the Function object that was used to create the object.
It has a `prototype' property implicitly. It is not that this property is
assigned a value that makes the `constructor' property of the created object
useless, but when this value is not an object that provides a user-defined
`constructor' property to refer to the constructor.

Yes, you're right about that. I could have stated that more clearly.
Not everybody does it, as it does not work, because it is wrong.This
statement does not add Super.prototype to the prototype chain of Sub
objects;

Of course it does. Just confusingly. See your diagram directly below.
it adds a newly created Super object there:

new Sub() --> Sub.prototype --> new Super() --> Super.prototype --> ...
--> Object.prototype

For example:

function Super() {}
Super.prototype.thingy=42;

function Sub() {}
Sub.prototype = new Super();

alert((new Sub()).thingy); // 42.
So there is no real prototype-based inheritance anymore as any property
value that is defined for Super objects only in their constructor is
inherited from that object through the prototype chain, even though
Super.prototype does not need to have that property or provides a different
default value for it.

So? Super() does not add any properties, and even if it did, that won't
make it wrong. It's just that constructors confuse matters.
One way to do it properly is this oft-recommended approach:

function extend(P)
{
function Dummy() {}
Dummy.prototype = P;
return new Dummy();
}

Sub.prototype = extend(Super.prototype);

The resulting prototype chain is then

new Sub() --> Sub.prototype === new Dummy() --> Dummy.prototype ===
Super.prototype --> ... --> Object.prototype

What? Just. No. That's just even *more* confusing. Why not do this if
you want real prototyping:

var SubProto = {};
var SuperProto = extend(SubProto);
var super = extend(sub);

and just forget about "new constructor()" altogether and use extend() to
create *all* objects. Constructors are an ugly, ugly hack in JavaScript
anyway.
 
J

Joost Diepenmaat

Joost Diepenmaat said:
What? Just. No. That's just even *more* confusing. Why not do this if
you want real prototyping:

var SubProto = {};
var SuperProto = extend(SubProto);
var super = extend(sub);

I meant:

var SubProto = {};
var SuperProto = extend(SubProto);
var super = extend(SuperProto);

Sorry about the confusion.

Joost.
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
True. I wonder how long it will take until everybody recognizes that
Flanagan actually has no clue what he is writing about.

For some reason /nobody/ I've read gets OO javascript right except
Crockford. [...]

Including you? ;-)
Of course it does. Just confusingly. See your diagram directly below.

OK, it does add Super.prototype, but it does not add it in the proper way.
For example:

function Super() {}
Super.prototype.thingy=42;

function Sub() {}
Sub.prototype = new Super();

alert((new Sub()).thingy); // 42.

You miss the point. For example:

function Super() {}
Super.prototype.items = [];

function Sub() {}
Sub.prototype = new Super();

var sub1 = new Sub();
var sub2 = new Sub();
sub1.items.push(42);

// yields [42], instead of [] as it should
sub2.items

Lasse Reichstein Nielsen already pointed that out when this issue first (or
at least most intensively) came up here. You really should increase the
range of your research.
So? Super() does not add any properties, and even if it did, that won't
make it wrong.

Yes, it would. The object inherited from would not be Super.prototype, but
a Super object (no pun intended):

function Super()
{
this.foo = "bar";
}

function Sub() {}
Sub.prototype = new Super();

var sub1 = new Sub();
Super.prototype.foo = 42;

// yields "bar", instead of 42 as it should
sub1.foo
It's just that constructors confuse matters.

I don't agree.
What? Just. No. That's just even *more* confusing.

No, it is has been proven a correct approach, if not *the* correct one.
Again, you should search the newsgroup.

[imported correction from said:
Why not do this if you want real prototyping:

var SubProto = {};
var SuperProto = extend(SubProto);
var super = extend(SuperProto);

Nonsense. User-defined objects should inherit from prototype (Object)
objects, not from constructor (Function) objects.

It is possible to pass the constructor instead of the prototype object, but
extend() can be renamed clone() and the necessary hard-coding of the
prototype property in it would prevent this code reuse. Besides, passing
the prototype object explicitly shows the caller what is going to happen;
I consider that a Good Thing.
and just forget about "new constructor()" altogether and use extend() to
create *all* objects. Constructors are an ugly, ugly hack in JavaScript
anyway.

I don't think so.


PointedEars
 
D

Dr J R Stockton

Sun said:
P.S. I really need to get myself an authoritative reference on
JavaScript...

So get ISO/IEC 16262, free as a PDF.
I thought that Flanagan's book was it, but just
today I've run into a few topics (such as the const keyword) that
Flanagan doesn't even *mention*. I'm wondering if "extend" will
be another such blind spot...

Remember that a script engine author needs to know everything in the
current and the imminent standards, and should also know what other
script engines actually do. For that, ordinary books cannot be expected
to suffice.

But a page author needs to know only those standards with which current
and recent script engines are compliant, and what the common browsers
actually do; if he knows anything else, he must keep the two sets of
knowledge quite separate in his mind.
 
T

Thomas 'PointedEars' Lahn

Thomas said:
[imported correction from said:
Why not do this if you want real prototyping:

var SubProto = {};
var SuperProto = extend(SubProto);
var super = extend(SuperProto);

`super' is a reserved word.
Nonsense. User-defined objects should inherit from prototype (Object)
objects, not from constructor (Function) objects.
[...]

Please ignore that, I was overlooking that you are using Object objects already.
and just forget about "new constructor()" altogether and use extend() to
create *all* objects. [...]

While the identifiers are confusing and even misleading, it certainly is an
interesting idea: One Object object would inherit from the other, indeed.
However, it looks as if there was a bug in it and I just don't see it yet.


PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
You miss the point. For example:

function Super() {}
Super.prototype.items = [];

function Sub() {}
Sub.prototype = new Super();

var sub1 = new Sub();
var sub2 = new Sub();
sub1.items.push(42);

// yields [42], instead of [] as it should
sub2.items

That's expected. Prototypes aren't templates, they're objects in their
own right, and sharing a prototype, which is exactly what constructors
do to their generated objects, means you're sharing the prototype's
properties until you override them by setting them in the super object.
But you know that.
I don't agree.

I belief they do: constructors are just way of setting prototypes and
properties but they look way too much like classes / class-based
constructors.

Joost.
 
J

Joost Diepenmaat

Joost Diepenmaat said:
Thomas 'PointedEars' Lahn said:
You miss the point. For example:

function Super() {}
Super.prototype.items = [];

function Sub() {}
Sub.prototype = new Super();

var sub1 = new Sub();
var sub2 = new Sub();
sub1.items.push(42);

// yields [42], instead of [] as it should
sub2.items

That's expected. Prototypes aren't templates, they're objects in their
own right, and sharing a prototype, which is exactly what constructors
do to their generated objects, means you're sharing the prototype's
properties until you override them by setting them in the super
object. ^^^^^

I meant: sub object

Joost.
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
You miss the point. For example:

function Super() {}
Super.prototype.items = [];

function Sub() {}
Sub.prototype = new Super();

var sub1 = new Sub();
var sub2 = new Sub();
sub1.items.push(42);

// yields [42], instead of [] as it should
sub2.items

That's expected.

No, it is _not_ expected at all that two objects derived from the same
prototype share their property *values*. The very point about objects
is that they have identity, that they *differ* from each other.
Prototypes aren't templates, they're objects in their own right,

I'm afraid you are in error here. Prototypes are objects in their
own right, but the term "prototype", translatable at least into all
Indo-European languages, including Nederlands if I may say so, has
the meaning of "template". In engineering, a working prototype is
the first thing you need to make a series of machines with similar
functionality and properties. Note that since the words are not
being used in the OOP sense here, the connection is most obvious.

See also http://en.wikipedia.org/wiki/Prototype pp.


PointedEars
 
R

RobG

On Jan 28, 10:39 am, Thomas 'PointedEars' Lahn <[email protected]>
wrote:
[...]
One way to do it properly is this oft-recommended approach:

  function extend(P)
  {
    function Dummy() {}
    Dummy.prototype = P;
    return new Dummy();
  }

Richard Cornford suggested that can be written more efficiently by
reusing the Dummy constructor:

var extend = (function(){
function Dummy(){}
return (function(P){
Dummy.prototype = P;
return new Dummy();
});
})();

<URL:
http://groups.google.com.au/group/c...hl=en&lnk=gst&q=clone+object#21965e62bfb3aa9f
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
Joost said:
Thomas 'PointedEars' Lahn said:
You miss the point. For example:

function Super() {}
Super.prototype.items = [];

function Sub() {}
Sub.prototype = new Super();

var sub1 = new Sub();
var sub2 = new Sub();
sub1.items.push(42);

// yields [42], instead of [] as it should
sub2.items

That's expected.

No, it is _not_ expected at all that two objects derived from the same
prototype share their property *values*. The very point about objects
is that they have identity, that they *differ* from each other.

Javascript does not clone from a prototype, it just links the new object
to its prototype and does property lookup via the prototype chain. If
you want cloning of certain properties (and you usually don't want to
clone ALL properties) you have to make it happen yourself.

Provided you know that, nothing about the above code should be
confusing. Well except that it becomes very unclear why you'd need
constructors at all.
I'm afraid you are in error here. Prototypes are objects in their
own right, but the term "prototype", translatable at least into all
Indo-European languages, including Nederlands if I may say so, has
the meaning of "template". In engineering, a working prototype is
the first thing you need to make a series of machines with similar
functionality and properties. Note that since the words are not
being used in the OOP sense here, the connection is most obvious.

I thought this was a JavaScript group. The meaning of the word in
JavaScript is what matters to me.

Joost.
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
Joost said:
You miss the point. For example:

function Super() {}
Super.prototype.items = [];

function Sub() {}
Sub.prototype = new Super();

var sub1 = new Sub();
var sub2 = new Sub();
sub1.items.push(42);

// yields [42], instead of [] as it should
sub2.items
That's expected.
No, it is _not_ expected at all that two objects derived from the same
prototype share their property *values*. The very point about objects
is that they have identity, that they *differ* from each other.

Javascript does not clone from a prototype, it just links the new object
to its prototype and does property lookup via the prototype chain. If
you want cloning of certain properties (and you usually don't want to
clone ALL properties) you have to make it happen yourself.

You are not making sense. Don't you see that your *wrong* assignment can
make objects share not only their properties, but also their property
values, i.e. clones them?
Provided you know that, nothing about the above code should be
confusing. Well except that it becomes very unclear why you'd need
constructors at all.
Disagreed.


I thought this was a JavaScript group. The meaning of the word in
JavaScript is what matters to me.

The meaning of the word in software engineering, including programming in
ECMAScript implementations, is clearly derived from the meaning of the word
in general engineering. It is simply unreasonable to deny that.


PointedEars
 
T

Thomas 'PointedEars' Lahn

RobG said:
Richard Cornford suggested that can be written more efficiently by
reusing the Dummy constructor:

var extend = (function(){
function Dummy(){}
return (function(P){
Dummy.prototype = P;
return new Dummy();
});
})();

<URL:
http://groups.google.com.au/group/c...hl=en&lnk=gst&q=clone+object#21965e62bfb3aa9f

Thanks, I was looking for that. However, you should consider that the
increased runtime efficiency gained by declaring the Dummy() constructor
only once is mitigated by the reduced memory efficiency caused by the
continued allocation of memory due to the closure. And since there are
more issues with closures than without them, I would avoid them here.


PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
You are not making sense. Don't you see that your *wrong* assignment can
make objects share not only their properties, but also their property
values, i.e. clones them?

Linking to a prototype does not clone anything. That's the reason the
properties are shared. If they were cloned they wouldn't be shared.
*shrug*


The meaning of the word in software engineering, including programming in
ECMAScript implementations, is clearly derived from the meaning of the word
in general engineering. It is simply unreasonable to deny that.

I didn't deny that. Stick to the subject.

Joost.
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top