From: wmc on
I'm currently reading a JS book (Zakas, Prof. JavaScript for Web
Developers, 2nd. Ed.) and wondered about a statement Zakas made in the
OOP chapter. Discussing the constructor pattern he says:

"The constructor property was originally intended for use in identifying
the object type. However, the instanceof operator is considered to be a
safer way of determining type."

Not sure I understand why this would be the case. If I use a constructor
function...

e.g. var audi = new Car("Audi", "Quattro");

.... can't I *depend* on audi.constructor being a reference to Car?

thx,

--williamc
From: Dmitry A. Soshnikov on
On Jan 11, 6:01 pm, wmc <...> wrote:

>
>      e.g. var audi = new Car("Audi", "Quattro");
>
> ... can't I *depend* on audi.constructor being a reference to Car?
>

Sure you can. Until `constructor' property of the `Car.prototype' is
still exists and references to `Car' function. But it can be easily
deleted or overwritten.

function Shuttle() {}

Car.prototype.constructor = Shuttle;

alert(audi.constructor === Car); // false
alert(audi.constructor === Shuttle); // true
alert(audi.constructor === audi.constructor.prototype.constructor); //
true

Moreover, you can define own `constructor' property in `audi' object
(by default it's taken (inherited) from the prototype as you saw):

audi.constructor = 10;

So in ECMAScript the main purpose of the constructor function - is
creation of an object; after that it can be easily deleted (including
it's `protptype' and `prototype.constructor' properties) and object
will stay to live with it's implicit reference to prototype.

function A() {}
A.prototype.x = 10;

var a = new A();
alert(a.x); // 10

// set explicit link to
// constructor function to null
A = null;

// but we still able to create
// objects of that constructor via
// other object if `constructor' has
// not been changed (via "implicit" reference)
var b = new a.constructor();
alert(b.x); // 10

// delete both implicit references
delete a.constructor.prototype.constructor;
delete b.constructor.prototype.constructor;

// we can't construct any more objects from
// function A, but still there're two
// such objects in memory which have access
// to their prototype object
alert(a.x); // 10
alert(b.x); // 10

That's about why `constructor' property can be not so useful in such
checks - ideologically it easily can be just removed at all.

But about `instanceof' operator - it also can be not so useful,
because it analyzes prototype chain and check if prototype of an
object is the same as one of the objects in that prototype chain (for
that check in your case `Car.prototype' will be used).

So the following check:

if (audi instanceof Car) {
...
}

doesn't mean that "audi was constructed by the Car constructor". All
it does - checks if audi.__proto__ (non-standard property, available
e.g. in FF, Chrome, other) is equal to some of an object in prototype
chain references by `prototype' property of and constructor:

function A() {}
A.prototype.x = 10;

var a = new A();
alert(a.x); // 10

alert(a instanceof A); // true

// if to assign null to
// A.prototype...
A.prototype = null;

// ...then "a" object will
// still have access to the
// prototype - through the a.[[Prototype]]
// which is a.__proto__
alert(a.x); // 10

// but instanceof operator
// can't work anymore as
// starts its analysis
// from the `prototype' property
// of the constructor function
alert(a instanceof A); // error, A.prototype – is not an object

From the other hand, it's possible to make such case when `instanceof'
operator will pass check with completely different constructor (all
what is needed is to set prototype of an object (__protot__) and
`prototype' property of an constructor object to the same object):

function B() {}
var b = new B();

alert(b instanceof B); // true

function C() {}

var __proto = {
constructor: C
};

C.prototype = __proto;
b.__proto__ = __proto;

alert(b instanceof C); // true
alert(b instanceof B); // false

That's why `instanceof' of taking into account that ECMAScript uses
"duck typing" can not be so useful.

Regarding to Zakas description:

> "The constructor property was originally intended for use in identifying
> the object type. However, the instanceof operator is considered to be a
> safer way of determining type."
>

It's not correct regarding to ECMAScript to talk about the "type" with
such checks. In language with "duck typing" it's not so. Nether
constructor function, nor prototype object in ECMAScript's ideology
are "types". That's possibly to talk about Java - that's class of an
object - is it's type, but not in ECMAScript (though, pair
"constructor function + prototype object" can abstractly called as a
"class" - in quotes).

ECMAScript has types and also [[Class]]ification of objects, but
that's not about that checks.

/ds
From: wmc on
Dmitry A. Soshnikov wrote:
> On Jan 11, 6:01 pm, wmc <...> wrote:
>
>> e.g. var audi = new Car("Audi", "Quattro");
>>
>> ... can't I *depend* on audi.constructor being a reference to Car?
>>
>
> Sure you can. Until `constructor' property of the `Car.prototype' is
> still exists and references to `Car' function. But it can be easily
> deleted or overwritten.
>
> function Shuttle() {}
>
> Car.prototype.constructor = Shuttle;
>
> alert(audi.constructor === Car); // false
> alert(audi.constructor === Shuttle); // true
> alert(audi.constructor === audi.constructor.prototype.constructor); //
> true
>
> Moreover, you can define own `constructor' property in `audi' object
> (by default it's taken (inherited) from the prototype as you saw):
>
> audi.constructor = 10;
>
> So in ECMAScript the main purpose of the constructor function - is
> creation of an object; after that it can be easily deleted (including
> it's `protptype' and `prototype.constructor' properties) and object
> will stay to live with it's implicit reference to prototype.
>
> function A() {}
> A.prototype.x = 10;
>
> var a = new A();
> alert(a.x); // 10
>
> // set explicit link to
> // constructor function to null
> A = null;
>
> // but we still able to create
> // objects of that constructor via
> // other object if `constructor' has
> // not been changed (via "implicit" reference)
> var b = new a.constructor();
> alert(b.x); // 10
>
> // delete both implicit references
> delete a.constructor.prototype.constructor;
> delete b.constructor.prototype.constructor;
>
> // we can't construct any more objects from
> // function A, but still there're two
> // such objects in memory which have access
> // to their prototype object
> alert(a.x); // 10
> alert(b.x); // 10
>
> That's about why `constructor' property can be not so useful in such
> checks - ideologically it easily can be just removed at all.
>
> But about `instanceof' operator - it also can be not so useful,
> because it analyzes prototype chain and check if prototype of an
> object is the same as one of the objects in that prototype chain (for
> that check in your case `Car.prototype' will be used).
>
> So the following check:
>
> if (audi instanceof Car) {
> ...
> }
>
> doesn't mean that "audi was constructed by the Car constructor". All
> it does - checks if audi.__proto__ (non-standard property, available
> e.g. in FF, Chrome, other) is equal to some of an object in prototype
> chain references by `prototype' property of and constructor:
>
> function A() {}
> A.prototype.x = 10;
>
> var a = new A();
> alert(a.x); // 10
>
> alert(a instanceof A); // true
>
> // if to assign null to
> // A.prototype...
> A.prototype = null;
>
> // ...then "a" object will
> // still have access to the
> // prototype - through the a.[[Prototype]]
> // which is a.__proto__
> alert(a.x); // 10
>
> // but instanceof operator
> // can't work anymore as
> // starts its analysis
> // from the `prototype' property
> // of the constructor function
> alert(a instanceof A); // error, A.prototype � is not an object
>
> From the other hand, it's possible to make such case when `instanceof'
> operator will pass check with completely different constructor (all
> what is needed is to set prototype of an object (__protot__) and
> `prototype' property of an constructor object to the same object):
>
> function B() {}
> var b = new B();
>
> alert(b instanceof B); // true
>
> function C() {}
>
> var __proto = {
> constructor: C
> };
>
> C.prototype = __proto;
> b.__proto__ = __proto;
>
> alert(b instanceof C); // true
> alert(b instanceof B); // false
>
> That's why `instanceof' of taking into account that ECMAScript uses
> "duck typing" can not be so useful.
>
> Regarding to Zakas description:
>
>> "The constructor property was originally intended for use in identifying
>> the object type. However, the instanceof operator is considered to be a
>> safer way of determining type."
>>
>
> It's not correct regarding to ECMAScript to talk about the "type" with
> such checks. In language with "duck typing" it's not so. Nether
> constructor function, nor prototype object in ECMAScript's ideology
> are "types". That's possibly to talk about Java - that's class of an
> object - is it's type, but not in ECMAScript (though, pair
> "constructor function + prototype object" can abstractly called as a
> "class" - in quotes).
>
> ECMAScript has types and also [[Class]]ification of objects, but
> that's not about that checks.
>
> /ds


Thanks for that incredibly detailed response. I'll work through it at my
snail's pace...

--williamc
From: Garrett Smith on
Dmitry A. Soshnikov wrote:
> On Jan 11, 6:01 pm, wmc <...> wrote:
>
>> e.g. var audi = new Car("Audi", "Quattro");
>>
>> ... can't I *depend* on audi.constructor being a reference to Car?
>>
>
> Sure you can. Until `constructor' property of the `Car.prototype' is
> still exists and references to `Car' function. But it can be easily
> deleted or overwritten.
>

The constructor property exists in the prototype of the new'd object.

It is easy to replace it by accident, as:-

function Vehicle(){}
function Car(){}

Car.prototype = new Vehicle;

(new Car).constructor; // Vehicle.

To address such situation, create a user-defined function for prototype
inheritance, such as `extend(superclass, subclass)`.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Garrett Smith on
Dmitry A. Soshnikov wrote:
> On Jan 11, 11:29 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
>> Dmitry A. Soshnikov wrote:
>>> On Jan 11, 6:01 pm, wmc <...> wrote:
>>>> e.g. var audi = new Car("Audi", "Quattro");
>>>> ... can't I *depend* on audi.constructor being a reference to Car?
>>> Sure you can. Until `constructor' property of the `Car.prototype' is
>>> still exists and references to `Car' function. But it can be easily
>>> deleted or overwritten.
>> The constructor property exists in the prototype of the new'd object.
>>
>> It is easy to replace it by accident, as:-
>>
>> function Vehicle(){}
>> function Car(){}
>>
>> Car.prototype = new Vehicle;
>>
>> (new Car).constructor; // Vehicle.
>>
>> To address such situation, create a user-defined function for prototype
>> inheritance, such as `extend(superclass, subclass)`.
>> --
>> Garrett
>> comp.lang.javascript FAQ:http://jibbering.com/faq/
>
> Yeah, thanks, I know this.
>

(You quoted my signature).

The OP may not have been aware of what I posted.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/