prototype object and arrays - I'm confused

P

Piotr K

I came across a strange problem or I just don't understand how
prototype object works.. but first things first - take a look at this
code

var A = function() {}

A.prototype.r = [10];

var a1 = new A, a2 = new A;

a2.r[0] = 20;

alert(a1.r[0]); // = 20 WTF ?!

Can someone explain me why JS doesn't create array copy for every new
instance but simply points to the same array? Of course I can create
that array in constructor class like this

var A = function() { this.r = [10]; }

This works fine however if I do it in that way, hasOwnProperty will
return TRUE for 'r' while doing it with prototype will return FALSE.
 
T

Thomas 'PointedEars' Lahn

Piotr said:
I came across a strange problem or I just don't understand how
prototype object works.. but first things first - take a look at this
code

var A = function() {}

A.prototype.r = [10];

var a1 = new A, a2 = new A;

a2.r[0] = 20;

alert(a1.r[0]); // = 20 WTF ?!

Can someone explain me why JS doesn't create array copy for every new
instance but simply points to the same array?

Searching the prototype chain for your assignment will result in the
property named `r' of the prototype object because you have not added a
property named `r' to the object referred to by `a2' before. As a result,
looking up the property named `r' of the object referred to by `a1' results
in a reference to the same Array object, with the same property value that
you have just set before.

The prototype chain looks as follows:

a1 ------> A.prototype ---> Object.prototype
^
a2 --------'
Of course I can create that array in constructor class

There are no classes. A constructor is a [[Construct]]able object.
like this

var A = function() { this.r = [10]; }

This works fine

(But you should have delimited the outer assignment with `;', too.)

Because then each individual object (as in constructor code, `this' refers
to the object about to be constructed) has a (non-inherited) property named
`r', and searching the prototype chain will result in a reference to the
corresponding Array object that the property stores.
however if I do it in that way, hasOwnProperty will
return TRUE for 'r' while doing it with prototype will return FALSE.

Works as designed.


PointedEars
 
P

Piotr K

Piotr said:
I came across a strange problem or I just don't understand how
prototype object works.. but first things first - take a look at this
code
var A = function() {}
A.prototype.r = [10];
var a1 = new A, a2 = new A;
a2.r[0] = 20;
alert(a1.r[0]);   // = 20 WTF ?!
Can someone explain me why JS doesn't create array copy for every new
instance but simply points to the same array?

Searching the prototype chain for your assignment will result in the
property named `r' of the prototype object because you have not added a
property named `r' to the object referred to by `a2' before.  As a result,
looking up the property named `r' of the object referred to by `a1' results
in a reference to the same Array object, with the same property value that
you have just set before.

The prototype chain looks as follows:

  a1 ------> A.prototype ---> Object.prototype
             ^
  a2 --------'

Thanks for detailed explanation, now it's clear to me however the
question is how to resolve this? Is there any way to create copy of
that array for each instance without adding it "manually" in
constructor so hasOwnProperty will return FALSE? So far the only
solution I see is creating smth like this:

function hasOwnProperty(obj, key) {
return (typeof obj.constructor.prototype[key] != 'undefined');
}

function copy(obj) {
if(obj.constructor == Array) return obj.slice(0)
[...]
}

var A = function() {
for(var key in this.constructor.prototype) {
if(this.constructor.prototype.hasOwnProperty(key)) {
this[key] = copy(this.constructor.prototype[key]);
}
}
}

A.prototype.r = [10];

Any other ideas?
 
L

Lasse Reichstein Nielsen

Piotr K said:
Thanks for detailed explanation, now it's clear to me however the
question is how to resolve this? Is there any way to create copy of
that array for each instance without adding it "manually" in
constructor so hasOwnProperty will return FALSE?

Realistically, no (i.e., not without building your own framework inside
the language). And why would you?
You want each instance to have its own array, but you want
hasOwnProperty to say that it doesn't.
So far the only
solution I see is creating smth like this:

function hasOwnProperty(obj, key) {
return (typeof obj.constructor.prototype[key] != 'undefined');
}

function copy(obj) {
if(obj.constructor == Array) return obj.slice(0)
[...]
}

var A = function() {
for(var key in this.constructor.prototype) {
if(this.constructor.prototype.hasOwnProperty(key)) {
this[key] = copy(this.constructor.prototype[key]);
}
}
}

A.prototype.r = [10];

I.e., manually copying object properties from the prototype at
creation time. That won't change how Object.prototype.hasOwnProperty
reports it, but if you use your own hasOwnProperty, you can omit
the copied properties.

Still, why? What is the problem you are trying to solve?
It feels very much like you are trying to solve a problem in one
particular way instead of considering why it is a problem to begin
with.

/L
 
R

RobG

Piotr said:
I came across a strange problem or I just don't understand how
prototype object works.. but first things first - take a look at this
code
var A = function() {}
A.prototype.r = [10];
var a1 = new A, a2 = new A;
a2.r[0] = 20;
alert(a1.r[0]);   // = 20 WTF ?!
Can someone explain me why JS doesn't create array copy for every new
instance but simply points to the same array?
Searching the prototype chain for your assignment will result in the
property named `r' of the prototype object because you have not added a
property named `r' to the object referred to by `a2' before.  As a result,
looking up the property named `r' of the object referred to by `a1' results
in a reference to the same Array object, with the same property value that
you have just set before.
The prototype chain looks as follows:
  a1 ------> A.prototype ---> Object.prototype
             ^
  a2 --------'

Thanks for detailed explanation, now it's clear to me however the
question is how to resolve this?

As Lasse said, without a clear explanation of what "this" is, it's
difficult to suggest a fix.
Is there any way to create copy of
that array for each instance without adding it "manually" in
constructor so hasOwnProperty will return FALSE? So far the only
solution I see is creating smth like this:
[...]
Any other ideas?

You can insert another object in the prototype chain using a maker
function and give that object the r property, so you have:

a1 --> dummy.prototype --> A.prototype ...

During construction, add an r property to dummy.prototype so that each
instance of A has an r property but hasOwnProperty('r') will return
false.

While that is possible, it seems like a solution looking for a
problem.
 
T

Thomas 'PointedEars' Lahn

Piotr said:
Thanks for detailed explanation, now it's clear to me

You are welcome.
however the question is how to resolve this? Is there any way to create
copy of that array for each instance without adding it "manually" in
constructor so hasOwnProperty will return FALSE?

Mu.


PointedEars
 
P

Piotr K

I.e., manually copying object properties from the prototype at
creation time. That won't change how Object.prototype.hasOwnProperty
reports it, but if you use your own hasOwnProperty, you can omit
the copied properties.

Still, why? What is the problem you are trying to solve?
It feels very much like you are trying to solve a problem in one
particular way instead of considering why it is a problem to begin
with.

What I want to do is iterate thru object properties and methods using
"in" operator while ignoring all "built-in" members and to achieve
this I need hasOwnProperty to return FALSE for these members - so this
code:

var A = function() {};

A.prototype.r = [10, 20];

var obj = new A;

obj.x = 5;
obj.y = 10;

for(var key in obj) {
if(obj.hasOwnProperty(key)) {
document.write(key);
}
}

Will return "x" "y".
 
T

Thomas 'PointedEars' Lahn

Piotr said:
What I want to do is iterate thru object properties and methods using
^^^^
You should employ proper language forms here.
"in" operator while ignoring all "built-in" members and to achieve
this I need hasOwnProperty to return FALSE

Probably you mean `false' (without quotes); ECMAScript implementations are
case-sensitive.
for these members - so this code:

var A = function() {};

A.prototype.r = [10, 20];

var obj = new A;

obj.x = 5;
obj.y = 10;

for(var key in obj) {

That is _not_ using the `in' operator, but a for-in loop. One must
distinguish carefully between `in' used in an expression (as an operator),
and in a for-in statement.

if(obj.hasOwnProperty(key)) {
document.write(key);
}
}

Will return "x" "y".

It is likely to _print_ "xy" (without quotes) to the document view. Your
statement implies that you wish it to print "rxy" and the like there; you
should simply remove the filtering `if' statement along with the
hasOwnProperty() call then.


PointedEars
 
P

Piotr K

Piotr said:
What I want to do is iterate thru object properties and methods using

                               ^^^^
You should employ proper language forms here.
"in" operator while ignoring all "built-in" members and to achieve
this I need hasOwnProperty to return FALSE

Probably you mean `false' (without quotes); ECMAScript implementations are
case-sensitive.
for these members - so this code:
var A = function() {};
A.prototype.r = [10, 20];
var obj = new A;
obj.x = 5;
obj.y = 10;
for(var key in obj) {

That is _not_ using the `in' operator, but a for-in loop.  One must
distinguish carefully between `in' used in an expression (as an operator),
and in a for-in statement.

   if(obj.hasOwnProperty(key)) {
           document.write(key);
   }
}
Will return "x" "y".

It is likely to _print_ "xy" (without quotes) to the document view.  Your
statement implies that you wish it to print "rxy" and the like there; you
should simply remove the filtering `if' statement along with the
hasOwnProperty() call then.

I wish to print "xy" but also have copy of "r" for each instance which
can't be achieved using "prototype" so I need to assign it in
constructor but then it will print "rxy" (cause hasOwnProperty will
return TRUE for "r"). In other words - I want "r" as a "built-in"
member.
 
J

John G Harris

I came across a strange problem or I just don't understand how
prototype object works.. but first things first - take a look at this
code

var A = function() {}

A.prototype.r = [10];

var a1 = new A, a2 = new A;

a2.r[0] = 20;

alert(a1.r[0]); // = 20 WTF ?!

Can someone explain me why JS doesn't create array copy for every new
instance but simply points to the same array?

Because javascript is not a conventional prototype-based language. Nor
is it a conventional class definition-based language. In fact,
javascript is pretty much on its own.

Of course I can create
that array in constructor class like this

var A = function() { this.r = [10]; }

This works fine however if I do it in that way, hasOwnProperty will
return TRUE for 'r' while doing it with prototype will return FALSE.

It's badly named.
hasOwnProperty
is really
isIndependentProperty
where what you would like is
isPropertyAddedAfterConstruction

You can emulate this quite easily. Just give the objects a special
property to hold all the properties added later, as in

var obj = new A;

obj.added.x = 5;
obj.added.y = 10;

for(var key in obj.added)
{
if(obj.added.hasOwnProperty(key))
...
}

John
 
T

Thomas 'PointedEars' Lahn

Piotr said:
I wish to print "xy" but also have copy of "r" for each instance which
can't be achieved using "prototype" so I need to assign it in
constructor but then it will print "rxy" (cause hasOwnProperty will
return TRUE for "r"). In other words - I want "r" as a "built-in"
member.

There are no members, there are properties. There are no classes, there is
a prototype chain. And there is no spoon.

Your question reads to me like "Can I make a cat sound like a dog?" And the
answer that you apparently want to hear is "Yes, you can, if you augment the
cat's central nervous system with a synthesizer that recognizes the signal
for the meow and puts out a bark instead."¹

Please trim your quotes to the necessary minimum required to retain context.

<http://jibbering.com/faq/#posting>


PointedEars
___________
¹ Kids, *please* don't try this at home!
 
J

John G Harris

John said:
Of course I can create
that array in constructor class like this

var A = function() { this.r = [10]; }

This works fine however if I do it in that way, hasOwnProperty will
return TRUE for 'r' while doing it with prototype will return FALSE.
It's badly named.
hasOwnProperty
is really
isIndependentProperty

In which sense is it independent? I think "own" describes property
relation to an object quite well.

I was thinking its value can be assigned independently of all other
objects, which is true. Unfortunately, if the value is an object the
object might also be the value of some other object property. Neither
'own' nor 'independent' are completely suitable for javascript :-(

John
 
G

Garrett Smith

John said:
I came across a strange problem or I just don't understand how
prototype object works.. but first things first - take a look at this
code

var A = function() {}

A.prototype.r = [10];

var a1 = new A, a2 = new A;

a2.r[0] = 20;

alert(a1.r[0]); // = 20 WTF ?!

Can someone explain me why JS doesn't create array copy for every new
instance but simply points to the same array?

Because javascript is not a conventional prototype-based language. Nor
is it a conventional class definition-based language. In fact,
javascript is pretty much on its own.

Of course I can create
that array in constructor class like this

var A = function() { this.r = [10]; }

This works fine however if I do it in that way, hasOwnProperty will
return TRUE for 'r' while doing it with prototype will return FALSE.

It's badly named.
hasOwnProperty
is really
isIndependentProperty
where what you would like is
isPropertyAddedAfterConstruction


Independent would seem to mean "owned or controlled by nothing else".

That definition what other objects in the objects prototype chain may
not have.

The problem with that is that it is different from "hasOwnProperty".
Method hasOwnProperty means that the object has a property with that
name. It doesn't say that a property exists in the prototype chain, but
it does not preclude that possibliity.

A constructor's prototype is useful for shared behavior as well as
default property values. An example default instance properties in the
prototype:

function Animation(duration) {
if (typeof duration == "number")
this.duration = duration * 1000; // default 1 sec.
this.timeLimit = this.duration; // for SeekTo()
}

Animation.prototype = {
duration : 1000
// shared behavior, etc.
};


var a = new Animation;
a.duration; // 1000
a.hasOwnProperty("duration"); // false.
a.duration = 2000;
a.hasOwnProperty("duration"); // true.
delete a.duration; // true;
a.hasOwnProperty("duration"); //false
a.duration; // 1000

When [[Get]] is called on that Animation "instance", the - duration -
property is found in the prototype chain.

When [[Put]] is called on that object, the property is added to the
objecdt itself.
You can emulate this quite easily. Just give the objects a special
property to hold all the properties added later, as in

Yes, a separate, plain old object for those that can be enumerated would
be a simple approach.

[snip example]

Garrett
 
H

Hamish Campbell

Your question reads to me like "Can I make a cat sound like a dog?"  And the
answer that you apparently want to hear is "Yes, you can, if you augment the
cat's central nervous system with a synthesizer that recognizes the signal
for the meow and puts out a bark instead."¹

[OT] Apologies in advance for the offence caused:

Q: How do you make a dog meow?

A: Freeze it and cut it in half with a chainsaw.

Q: How do you make a cat woof?

A: Dunk it in petrol and light it on fire.
 

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

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top