How instanceof works?

D

Dolaameng

Hi, guys, I am a newbie to javascript. I'd like to find out how the
'instanceof' operator works in javascript? What kind of tests are
going on behind the scene? For example, in following code, I
constructed a 'Base' class, and a 'Derived' class to extend it. Then I
instantiate an instance of 'Derived' to test if it is 'instanceof' the
Base class:

<script type="text/javascript">
//<![CDATA[
function extend(SubClass, SupClass){
var F=function(){};
F.prototype=SupClass.prototype;
SubClass.prototype=new F();
SubClass.prototype.constructor=SubClass;
//...
}
var Base=function(){};
//Base.prototype={};
var Derived=function(){
//Base.apply(this,null);
};
extend(Derived,Base);
var d=new Derived();

alert(d instanceof Base); //true
//]]>
</script>

The instanceof test above evaluates to true, with no surprise. I
guess this is because the interpreter found that
'Derived.prototype.prototype.constructor' is now 'Base'. So I add a
new line of code

Base.prototype={}

between the definition of Base and Derived class. This time I know
that 'Base.prototype.constructor' is not 'Base' anymore, it has been
overwritten to 'Object' instead. But superisely 'd instanceof Base'
still evaluates to true. Why does this magic happen?
 
D

Dolaameng

Dolaameng said:
Hi, guys, I am a newbie to javascript. I'd like to find out how
the 'instanceof' operator works in javascript?

The standard for javascript is ECMA 262, currently 3rd edition, which
defines the behaviour required of ECMAScript implementations (which is
what current versions of javascript claim to be). That document will ay
exactly what - instanceof - can be expected to do.
What kind of tests are
going on behind the scene?

The instance of operator performs a runtime comparison between the
identity of the current value of a function's - prototype - property
and, in tern, each of the objects on an object's internal prototype
chain. If any of the objects on the prototype chain are the object that
the function's - prototype - property refers to then the result is true.
This isn't a hugely useful relationship to test so - instanceof - is not
that frequently used.
For example, in following code, I
constructed a 'Base' class, and a 'Derived' class to extend it.
//]]>
</script>

The instanceof test above evaluates to true, with no surprise.  I
guess this is because the interpreter found that
'Derived.prototype.prototype.constructor' is now  'Base'.  So I
add a new line of code

The - constructor - property of object's is not involved in the
specified behaviour.
Base.prototype={}
between the definition of Base and Derived class. This time I
know that 'Base.prototype.constructor' is not 'Base' anymore,
it has been overwritten to 'Object' instead. But superisely
'd instanceof Base' still evaluates to true.

No it doesn't.
Why does this magic happen?

My guess is that you typoed - prototype - and ended up assigning the
object to the wrong property of - Base - (leaving its original -
prototype - property referring to its original value.

Richard.

Thanks Richard for you useful explanation. However, when I insert the
line 'Base.prototype={};' (with no typo) BEFORE invoking 'extend
(Derived,Base);', the statement 'alert(d instanceof Base );' indeed
evaluates to true (in firefox 3.5.3).

But if I invoke 'Base.prototype={};' AFTER 'extend(Derived,Base);',
the instanceof operation now evaluates to false as you said.

So I realized this could be due to the implementation of the 'extend'
function in my code, where I made a copy of SupClass.prototype through
a temp function F. If I invoke 'Base.prototype={};' BEFORE calling
extend, that actually means I just add the an empty object into
SubClass's Chain, and now Base.prototype is also that same empty
object. As a result 'd instanceof Base' is true.
If I change the invocation order, that will cause a mismatch between
Base.prototype and the one added in SubClass's prototype chain, so the
instanceof operation evaluates to false.

Is what I said here correct? thanks again!
 
R

RobG

The standard for javascript is ECMA 262, currently 3rd edition, which
defines the behaviour required of ECMAScript implementations (which is
what current versions of javascript claim to be). That document will ay
exactly what - instanceof - can be expected to do.

Yes, but the specification is sufficiently obfuscated as to make the
exercise of learning in isolation extremely difficult.

The following is an example of working it out from first principles.
Firstly, use the index and go to section 11.8.6 (wrapped for posting):

| 11.8.6 The instanceof operator
|
| The production RelationalExpression:
| RelationalExpression instanceof ShiftExpression
| is evaluated as follows:
|
| 1. Evaluate RelationalExpression.
| 2. Call GetValue(Result(1)).
| 3. Evaluate ShiftExpression.
| 4. Call GetValue(Result(3)).
| 5. If Result(4) is not an object, throw a TypeError exception.
| 6. If Result(4) does not have a [[HasInstance]] method, throw
| a TypeError exception.
| 7. Call the [[HasInstance]] method of Result(4) with parameter
| Result(2).
| 8. Return Result(7).

It seems reasonably straight forward, until [[HasInstance]] in step 6.
Section 8.6.2 says it:

| "Returns a boolean value indicating whether Value
| delegates behaviour to this object. Of the native
| ECMAScript objects, only Function objects implement
| [[HasInstance]]."

In this section, [[HasInstance]] is listed as a *property* in a
section that talks about properties and methods. So get annoyed that
the specification talks about properties that can be called, but
aren't defined as methods.

It's also a round about way of saying that the ShiftExpression must be
a function, else a TypeError exception will occur at step 6 (as only
Functions have [[HasInstance]]).

So if the original expression was:

objB instanceof ObjA

it is now internalised as:

ObjA.[[HasInstance]](objB)

The next question is what does "delegates behaviour to" mean? The word
"delegate" only appears once in the document (in the above phrase), so
what next? Perhaps "delegates behaviour to" means "affects the
behaviour of", and from that can be deduced that ObjA.prototype should
be on the internal prototype chain of objB. A little bit of testing
shows that to be how it works in practice, the following seems to
confirm that logic (though is probably not sufficient to prove it
beyond doubt):

function ObjA() {}
function ObjC() {}
var objB = new ObjA();

alert( objB instanceof ObjA); // true

var temp = ObjA.prototype;
ObjA.prototype = ObjC.prototype;
ObjC.prototype = temp;

alert( objB instanceof ObjA); // false
alert( objB instanceof ObjC); // true

It would have made life much easier had the ECMAScript authors stated
the relationship with prototypes in the explanation of
[[HasInstance]], or if the explanation of Prototype in section 4.3.5
included the phrase "delegates behaviour" so at least it can be found
by searching.

The instance of operator performs a runtime comparison between the
identity of the current value of a function's - prototype - property
and, in tern, each of the objects on an object's internal prototype
chain. If any of the objects on the prototype chain are the object that
the function's - prototype - property refers to then the result is true.
This isn't a hugely useful relationship to test so - instanceof - is not
that frequently used.

If only you would use your talent for such clear and succinct
explanations (sans typos, of course) to write a book covering all the
parts of ECMAScript, I'm sure it would be very well received. Why not
“ECMAScript: All the Parts”? Heaven forbid, you might make money from
it. :)

The only bit I would add is to caution that if a constructor's
prototype is replaced, then instanceof will use the new prototype for
the comparison. Hence instanceof may return false for objects that
were created from a constructor and true for objects that weren't.
Given the nature of prototype inheritance as implemented in
ECMAScript, it's really up to the code author to keep track of
inheritance if knowing something is an instance of, or was constructed
by, something else matters.
 
R

RobG

The standard for javascript is ECMA 262, currently 3rd edition, which
defines the behaviour required of ECMAScript implementations (which is
what current versions of javascript claim to be). That document will ay
exactly what - instanceof - can be expected to do.
The instance of operator performs a runtime comparison between the
identity of the current value of a function's - prototype - property
and, in tern, each of the objects on an object's internal prototype
chain. If any of the objects on the prototype chain are the object that
the function's - prototype - property refers to then the result is true.
This isn't a hugely useful relationship to test so - instanceof - is not
that frequently used.
<snip>> alert(d instanceof Base); //true
//]]>
</script>
The instanceof test above evaluates to true, with no surprise. I
guess this is because the interpreter found that
'Derived.prototype.prototype.constructor' is now 'Base'. So I
add a new line of code
The - constructor - property of object's is not involved in the
specified behaviour.
No it doesn't.
My guess is that you typoed - prototype - and ended up assigning the
object to the wrong property of - Base - (leaving its original -
prototype - property referring to its original value.

Thanks Richard for you useful explanation. However, when I insert the
line 'Base.prototype={};' (with no typo) BEFORE invoking 'extend
(Derived,Base);', the statement 'alert(d instanceof Base );' indeed
evaluates to true (in firefox 3.5.3).

But if I invoke 'Base.prototype={};' AFTER 'extend(Derived,Base);',
the instanceof operation now evaluates to false as you said.

So I realized this could be due to the implementation of the 'extend'
function in my code,

Not the implementation, but the order of assignment and execution of
surrounding code (see below).
where I made a copy of SupClass.prototype through
a temp function F.

You don't make a copy, you create another reference to it. It is
impossible to make a copy of an object in ECMAScript such that given
objects ObjectA and ObjectB then:

ObjectA === ObjectB

evaluates to true if and only if ObjectA and ObjectB refer to the same
object (where object includes functions). You can copy the properties
and values of one object to another (which is what some extend
functions do).

If I invoke 'Base.prototype={};' BEFORE calling
extend, that actually means I just add the an empty object into

Not add, you assign a reference to that empty object to
Base.prototype, replacing the previous reference.
SubClass's Chain, and now Base.prototype is also that same empty
object. As a result 'd instanceof Base' is true.
If I change the invocation order, that will cause a mismatch between
Base.prototype and the one added in SubClass's prototype chain, so the
instanceof operation evaluates to false.

Is what I said here correct? thanks again!

Yes. The object referenced by SubClass[[prototype]] is still the
object referenced by Base.prototype SubClass was constructed. The
instanceof operator uses the current value of Base.prototype, so if
that now refers to some other object, the result will be false unless
the new object is referenced somewhere else on SubClass' [[prototype]]
chain.
 
D

Dolaameng

<snip>

The thing that I would question is not that money could be made but
whether that money would be a suitable return for the time and effort
involved. Particularly in comparison with javascript programming for a
living, baring in mind that I am currently employed as a specialist and
very well paid for that.

Any javascript book would be, at best, targeted at a niche market, and
so have relatively restricted sales potential. So, financially, it looks
like my best interests lie in carrying on doing what I am doing now.
Things may change, but it does not look very likely that they will in
the foreseeable future.

Richard.

Thanks guys, I do learn here. Would you recommend to me some good
books about how javascript works inside? For example, I like very
much the style of <inside c++ object model> and <effective c++>. They
show you how C++ works from inside out. So i am wondering if there are
any similiar books in javascript? As you know, deciphering the ECMA
standard is really tough for a beginner, and boring.... Sometime I am
just not confident when using some features of javascript in my code.
For example, I am usually not quite sure if 'instanceof' or
'constructor test' would work for me in the code, or does the 'this'
variable refer to the right object here? That is really frustrating.
 
V

VK

Dolaameng said:
So I add a
new line of code

Base.prototype={}

between the definition of Base and Derived class. This time I know
that 'Base.prototype.constructor' is not 'Base' anymore, it has been
overwritten to 'Object' instead. But superisely 'd instanceof Base'
still evaluates to true. Why does this magic happen?

I guess you didn't program Java from were instanceof "syntax sugar"
has been taken ;) Just like in Java, each object instance is
instanceof of its own class and instanceof of generic Object. That has
a structural sense though might not be obvious.

function MyObject() {
this.foo = 'bar';
}

var obj = new MyObject;

window.alert(obj instanceof MyObject); // true

window.alert(obj instanceof Object); // true

I highly recommend Eric Lippert blog article "The JScript Type System,
Part Two: Prototypes and constructors" at
http://blogs.msdn.com/ericlippert/archive/2003/11/06/53352.aspx
That is the only source I know where some matters are described
decently.
 
V

VK

between the definition of Base and Derived class. This time I
No it doesn't.

Of course if does (see my answer). Do not read ECMA 262 3rd.ed. too
often, it makes a damage, I told you so many times.

:)
 

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,770
Messages
2,569,584
Members
45,079
Latest member
ElidaWarin

Latest Threads

Top