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

J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
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.

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

No closure. Though I would be amazed if it would have any significant
impact on memory use.

Joost.
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
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.

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

No closure. [...]

I think there is one. `Dummy' was declared in the definition
context of `extend' that `extend' reproduces when it is called;
that is how a closure is defined.


PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
Joost said:
Thomas 'PointedEars' Lahn said:
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.

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

No closure. [...]

I think there is one. `Dummy' was declared in the definition
context of `extend' that `extend' reproduces when it is called;
that is how a closure is defined.

If you're defining closures like that, every function that calls another
function, or accesses any other global property would be a closure:

function a() { alert() }
function b() { a(); }

My informal definition is that a closure is a function that keeps
references to objects that are defined in an outer lexical scope. Dummy
here is just a property of the global object, not a lexical variable.

Joost.
 
T

Thomas 'PointedEars' Lahn

Joost said:
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.

That would define how you define "clone". Suffice it to say that two
objects implicitly share their property values this way when derived from
the same prototype object is definitely counter-intuitive. It is the direct
result of the wrong application of prototype-based inheritance in ECMAScript
implementations.
I didn't deny that. Stick to the subject.

You must be kidding.


EOD

PointedEars
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
Joost said:
function Dummy(){} ^^^^^
function extend(proto) {
Dummy.prototype=proto; ^^^^^
return new Dummy();
}

No closure. [...]
I think there is one. `Dummy' was declared in the definition
context of `extend' that `extend' reproduces when it is called;
that is how a closure is defined.

If you're defining closures like that,

It is not my definition.
every function that calls another function,

Not every function. It depends on where the other function was defined.
or accesses any other global property would be a closure:
[...]

That is correct. Probably that is why Flanagan made his oversimplifying
false statement.
My informal definition is that a closure is a function that keeps
references to objects that are defined in an outer lexical scope. Dummy
here is just a property of the global object, not a lexical variable.

Note that functions are first-class objects in ECMAScript implementations.


PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
That would define how you define "clone". Suffice it to say that two
objects implicitly share their property values this way when derived from
the same prototype object is definitely counter-intuitive. It is the direct
result of the wrong application of prototype-based inheritance in ECMAScript
implementations.

AFAIK the current implementations behaviour is exactly according to the
spec. Section 4.3.5 of Ecma 262.

You may not like the spec, but the way properties are resolved in
JavaScript is not unique. There are other prototype-based systems that
work exactly the same (except they usually don't use constructors like
that, they just let you set & read the prototype directly).

It's an extremely simple system and it keeps memory use down and
run-time modification extremely simple, but it generally makes propery
lookup slower.
You must be kidding.

Read it again.

Joost.
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
Joost said:
Thomas 'PointedEars' Lahn said:
Joost Diepenmaat wrote:
function Dummy(){}
^^^^^
function extend(proto) {
Dummy.prototype=proto;
^^^^^
return new Dummy();
}

No closure. [...]
I think there is one. `Dummy' was declared in the definition
context of `extend' that `extend' reproduces when it is called;
that is how a closure is defined.

If you're defining closures like that,

It is not my definition.

Then you won't mind me demonstrating that it's wrong:

function a() { alert("First") }

function b() { a() };

function a() { alert("Second") }

b();
Not every function. It depends on where the other function was defined.

See code above. We're accessing a global property, not a lexical
variable. The fact that the variable is a function doesn't matter.
or accesses any other global property would be a closure:
[...]

That is correct. Probably that is why Flanagan made his oversimplifying
false statement.

Which statement?

Joost.
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
That would define how you define "clone". Suffice it to say that two
objects implicitly share their property values this way when derived from
the same prototype object is definitely counter-intuitive. It is the direct
result of the wrong application of prototype-based inheritance in ECMAScript
implementations.

AFAIK the current implementations behaviour is exactly according to the
spec. Section 4.3.5 of Ecma 262.

You may not like the spec, [...]

JFTR: Quite the contrary. The above was _not_ to say that the
implementation was wrong, but the application of the implementation
*by you*.
Read it again.

BTDT. Your reply to my explanation is still ridiculous.


PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
JFTR: Quite the contrary. The above was _not_ to say that the
implementation was wrong, but the application of the implementation
*by you*.

Sharing a prototype's properties is not wrong by itself. It's what
prototypes in javascript are there for. The only time it's wrong is when
you actually don't want to share the properties, just copies. And
javascript does not provide any /built in/ mechanism to do that, so I
really don't see what you're complaining about.

Joost.
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
Joost said:
Joost Diepenmaat wrote:
function Dummy(){}
^^^^^
function extend(proto) {
Dummy.prototype=proto;
^^^^^
return new Dummy();
}

No closure. [...]
I think there is one. `Dummy' was declared in the definition
context of `extend' that `extend' reproduces when it is called;
that is how a closure is defined.
If you're defining closures like that,
It is not my definition.

Then you won't mind me demonstrating that it's wrong:

The definition certainly is not wrong; maybe my interpretation of it in this
context is.
function a() { alert("First") }

function b() { a() };

function a() { alert("Second") }

b();

The second declaration for `a' overwrites the reference with one to another
Function object before b() is executed. ISTM you have just proved that
there is a closure :)
See code above. We're accessing a global property, not a lexical
variable. The fact that the variable is a function doesn't matter.

That seems contradictory.
or accesses any other global property would be a closure:
[...]
That is correct. Probably that is why Flanagan made his oversimplifying
false statement.

Which statement?

That one cited in
<[email protected]>

Different thread, same source of confusion. Sigh. [psf 10.1]


PointedEars
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
JFTR: Quite the contrary. The above was _not_ to say that the
implementation was wrong, but the application of the implementation *by
you*.

Sharing a prototype's properties is not wrong by itself. [...] The only
time it's wrong is when you actually don't want to share the properties,
just copies. And javascript does not provide any /built in/ mechanism to
do that, so I really don't see what you're complaining about.

Please review my example more thoroughly.

I was not talking about properties, but about non-default property *values*.
Sharing *them* is certainly not what prototypes are designed for. Usually,
you would not want to automatically have something appended to list #2 if
you appended it to list #1, and vice-versa, just because both targets are
lists (here: arrays). It might merely be an interesting hack to take
advantage of the unconventional application of prototype-based inheritance,
to say the least.


PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
The second declaration for `a' overwrites the reference with one to another
Function object before b() is executed. ISTM you have just proved that
there is a closure :)

I expected that reply and have prepared the following, demonstrating
that the lookup of a() in b() is done via dynamic, not lexical scoping.

function a() { alert("first") }

function b() { a() }

c = { a: function() { alert("second") } };
a();

with (c) {
a();
}
That seems contradictory.

Javascript variables that aren't declared (with var) in a function scope
or as a function argument are dynamic, defaulting to the global object's
property via whatever with() scopes are in place.

The same goes for functions: named functions defined in the global scope
are set as dynamic variables. Named functions defined within a with(X)
in the global scope are put in X. Named functions defined within a
function scope are lexical. I'm not sure what with() within a function
does.

Compare the above with:

function a() {
alert("first");
}

function b() { a() }

function c() {
function a() {
alert("second");
};
b();
}

a();
c();

or accesses any other global property would be a closure:
[...]
That is correct. Probably that is why Flanagan made his oversimplifying
false statement.

Which statement?

That one cited in
<[email protected]>

Different thread, same source of confusion. Sigh. [psf 10.1]

I don't see the connection.

Joost.
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
I was not talking about properties, but about non-default property *values*.
Sharing *them* is certainly not what prototypes are designed for. Usually,
you would not want to automatically have something appended to list #2 if
you appended it to list #1, and vice-versa, just because both targets are
lists (here: arrays). It might merely be an interesting hack to take
advantage of the unconventional application of prototype-based inheritance,
to say the least.

I noticed that, and I can see where that usage may be confusing. But
all prototype *values* are shared by design.

Properties are just references to objects. Modifying the object does not
change the shared status. Direct assigment to a "prototyped" property
creates a new reference in the "subclassed" object that points to a new
value object, overriding but not changing the prototyped property.

Can we at least agree that when you know what you're doing this sort of
thing can be useful, and not automatically wrong?

Joost.
 
J

Joost Diepenmaat

Joost Diepenmaat said:
I expected that reply and have prepared the following, demonstrating
that the lookup of a() in b() is done via dynamic, not lexical scoping.

function a() { alert("first") }

function b() { a() }

c = { a: function() { alert("second") } };
a();

with (c) {
a();
}

Never mind that. It's wrong and my analysis was wrong.

Joost.
 
T

Thomas 'PointedEars' Lahn

Joost said:
I noticed that, and I can see where that usage may be confusing. But all
prototype *values* are shared by design.

Quite the contrary. That is exactly what I wanted to point out: properties
are shared by design, but not property values. Meaning that if you modify
the property value of an object that is *not* a prototype object, it is
*not* by design that all other objects that have the same prototype object
in their prototype chain have their property value changed accordingly.
Properties are just references to objects.

They can store references to objects, they don't have to. In my example
(that is probably only Lasse's slightly adapted) they do (`items' stores a
reference to a shared Array object), which is the cause of the
counter-intuitive result.
Modifying the object does not change the shared status. Direct assigment
to a "prototyped" property creates a new reference in the "subclassed"
object that points to a new value object, overriding but not changing the
prototyped property.

Can we at least agree that when you know what you're doing this sort of
thing can be useful, and not automatically wrong?

We can. I don't deny that there can be useful applications of it, but I
doubt that they are commonplace.


PointedEars
 
R

RobG

That only becomes an issue if it causes paging to disc or some
secondary storage. I have no idea how much memory is consumed by an
empty function, I'll guess that it's very small in comparison to the
kind of non-trivial script that might use it.

The only issue I can think of with closures is related to IE memory
leaks, I don't think that's an issue here. There might be other
concerns with inappropriate use, but the usage here is quite specific
and should not cause any problems.
function Dummy(){}
function extend(proto) {
Dummy.prototype=proto;
return new Dummy();

}

No closure. Though I would be amazed if it would have any significant
impact on memory use.

There are always pros and cons... the above makes Dummy a global
variable that can be re-assigned by any function that wants to. In
Richard's original (and Crockford's), the use of a closure keeps it
private. If there is a need to dynamically modify or replace it
(which seems contrary to the whole point of the extend method, but
let's consider it) then a privileged function can be provided to do
that.

The amount of memory consumed in either case is trivial, I think the
performance gain (again, it's very small in one-of cases) outweighs
the memory consumed.
 
T

Thomas 'PointedEars' Lahn

RobG said:
The amount of memory consumed in either case is trivial, I think the
performance gain (again, it's very small in one-of cases) outweighs
the memory consumed.

I don't know what you mean by "one-of cases", but my benchmarks show that
the performance gain is negligible, too. With 10'000 iterations, it's a gain of

30 ms in Firefox 2.0.0.11,
125 ms in IE 7, and
16 ms in Opera 9.24.

All running on Windows XP SP 2 on a Pentium M 740, 1.73 GHz, 1 GB RAM, 1.2
GB Swap (at the time of testing).

Benchmark source code:

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

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

if (typeof console == "undefined")
{
console = {log: function(s) { window.alert(s); }};
}

function Super() {}
function Sub() {}

var start = new Date();
for (var i = 10000; i--;)
Sub.prototype = extend(Super.prototype);
console.log(new Date() - start);

start = new Date();
for (i = 10000; i--;)
Sub.prototype = extend2(Super.prototype);
console.log(new Date() - start);


PointedEars
 
V

VK

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?

http://blogs.msdn.com/ericlippert/archive/2003/11/06/53352.aspx has it
all explained in details.
 
K

kj

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

Well, clearly I'm one of those who was pretty slow at figuring this
out... (Though, irrespective of matters of accuracy, I've never
been not fond of Flanagan's ponderous tome.)

But if not Flanagan's book, then what?

Is there a better alternative for someone looking for an authoritative
JavaScript reference book? I suppose I could use the ECMA specs...
But is there something closer to JavaScript (whatever that is)?

I should say that I dislike most computer language "bibles" that
one can buy. It is clear that most of them aim for *bulk* rather
than substance. (It wouldn't surprise me if some of them used
thicker paper than normal, to create an imposing "authoritative"
presence in bookstores' shelves!)

So, to be more specific, my gold-standard for language reference
books is Harbison and Steele's "C: a reference manual". It's as
authoritative as any formal C specification, but significantly more
readable, without any superfluous handholding fluff... (The also
excellent Python Reference Manual by van Rossum is a very close
second.)

Is there something like that for JavaScript?

kynn
 
R

RobG

I don't know what you mean by "one-of cases"

Single cases where extend() is called once or only a few times.

, but my benchmarks show that
the performance gain is negligible, too.  With 10'000 iterations, it's again of

 30 ms in Firefox 2.0.0.11,
[...]

Yes, it's more a feel-good measure than a must-have. But if extend()
is to be used as a library function, why not optimise it? Anyhow,
it's up to individuals to chose how it's implemented, I just thought
it worth while posting an alternative.
 

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,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top