Prev: How to link CSS(s) already linked to parent frame into child iframe using javascript
Next: Error getElementbyClassName
From: wmc on 11 Jan 2010 10:01 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 11 Jan 2010 10:43 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 11 Jan 2010 11:00 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 11 Jan 2010 15:29 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 11 Jan 2010 19:42
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/ |