From: Stone Zhong on
Hi there,

I am reading the book "The Concise Guide to Dojo" and I saw some code
like below on page 11:

decafbad.school.PersonClassic.prototype = {...

I personally did a test like below

==== this code does not work ===
function Person(name) {
this.name = name;
Person.prototype = {
sayHi: function() { alert('hi ' + this.name); }
};
}
var a = new Person("JavaScript");
a.sayHi(); // I got error a.sayHi is not a function

however, if I change the code to below style , it worked,
function Person(name) {
this.name = name;
Person.prototype.sayHi = function() { alert('hi ' + this.name);
}
var a = new Person("JavaScript");
a.sayHi();

My conclusion is, a function's prototype already has some hidden
properties which might be important, replace function's prototype is
not good idea, only add property to function's prototype.


From: Thomas 'PointedEars' Lahn on
Stone Zhong wrote:

> I am reading the book "The Concise Guide to Dojo"

From what I have seen here, Dojo is junk as the people maintaining it do not
know what they are doing. Unlearn everything you have read there, and ask
for a refund.

> and I saw some code like below on page 11:
>
> decafbad.school.PersonClassic.prototype = {...
>
> I personally did a test like below
>
> ==== this code does not work ===
> function Person(name) {
> this.name = name;
> Person.prototype = {
> sayHi: function() { alert('hi ' + this.name); }
> };
> }
> var a = new Person("JavaScript");
> a.sayHi(); // I got error a.sayHi is not a function

Read the ECMAScript Language Specification, Edition 3 or 5, sections 11.2.2
and 13.2.2:

The internal `[[Prototype]]' property of the newly constructed object
(instance), which is used for prototype chain lookup, is set to the current
value of the `prototype' property of the constructor *before* control enters
the execution context of the constructor (before its `[[Call]]' method is
called).

In the constructor, you are overwriting its `prototype' property, which
previously referred to the same object as the `[[Prototype]]' property of
the instance. But you are not overwriting the `[[Prototype]]' property of
the instance. So the prototype chain lookup for methods of the newly
referred value must fail.

It is also the explanation why you can augment the object referred to by a
constructor's `prototype' property *after* objects have been created with
it, and those objects can use the new properties inherited through the
prototype chain.

> however, if I change the code to below style , it worked,
> function Person(name) {
> this.name = name;
> Person.prototype.sayHi = function() { alert('hi ' + this.name);

There's a syntax error, the function expression is incomplete.

> }
> var a = new Person("JavaScript");
> a.sayHi();
>
> My conclusion is, a function's prototype already has some hidden
> properties which might be important,

It has, most notably `constructor'.

> replace function's prototype is not good idea, only add property to
> function's prototype.

That is a fallacy. There are things to consider, though, see below.

It makes no sense *here* to define that method within the constructor,
creating a new function object with identical signature and body on each
constructor call, to begin with. `this' has nothing to do with scope.
So use

function Person(name)
{
this.name = name;
}

Person.prototype.sayHi = function () {
window.alert('hi ' + this.name);
};

var a = new Person("JavaScript");
a.sayHi();

or the equivalent

function Person(name)
{
this.name = name;
}

var a = new Person("JavaScript");

Person.prototype.sayHi = function () {
window.alert('hi ' + this.name);
};

a.sayHi();

or

function Person(name)
{
this.name = name;
}

Person.prototype = {
constructor: Person,

sayHi: function () {
window.alert('hi ' + this.name);
}
};

var a = new Person("JavaScript");

a.sayHi();

if you want to have a "public" method.

(However, with the last approach you have either an *enumerable*
`constructor' property. Or if you do not define it you have one that does
not refer to the instance's constructor; but there is no explicit harm in
having that, the language itself does not use the property.)

Which is why

function Person(name)
{
this.name = name;
}

var a = new Person("JavaScript");

Person.prototype = {
sayHi: function() {
window.alert('hi ' + this.name);
}
};

a.sayHi();

must fail (`Person.prototype' now refers to an object that is not in the
prototype chain of the instance.)


PointedEars
--
Anyone who slaps a 'this page is best viewed with Browser X' label on
a Web page appears to be yearning for the bad old days, before the Web,
when you had very little chance of reading a document written on another
computer, another word processor, or another network. -- Tim Berners-Lee