Object-arrays - duplicate object-references

A

Are Nybakk

Hi, I've stumbled into a problem I just can't figure out. I found out
that variables in JS don't have local scope inside brackets in say, a
loop, but things still doesn't add up. Also, the phenomena seemed very
much alike to a closure-related one, but I'm not returning any
functions as far as I can see (I'm fresh when it comes to closures
tho). Let me illustrate the very basic task at hand, which is filling
an array with new objects. All seven positions in the array returned
point to the same object!

---code---

var o = new Array();

for(var j=0; j<7; j++) {

//Create object
var obj = new SomeType();

//Manipulate object
obj.doSomething();


o[j] = obj;

}

//Array not what is expected here

someOtherObj.setArray(o);

---/code---


I also tried the code below to no avail. I don't see how it's any
different.


---code---

var o = new Array();

for(var j=0; j<7; j++) {

//Create object
o[j] = new SomeType();

//Manipulate object
o[j].doSomething();

}

//Array not what is expected here

someOtherObj.setArray(o);

---/code---

Does anyone have any enlightening explanations for why this occurs,
and what a solution might be?

Thanks
 
T

Thomas 'PointedEars' Lahn

Are said:
[...] Let me illustrate the very basic task at hand, which is filling
an array with new objects. All seven positions in the array returned
point to the same object!

No, they don't.
---code---

function SomeType(bar)
{
this.foo = bar;
}

SomeType.prototype = {
constructor: SomeType,
doSomething: function() {}
};
var o = new Array();

for(var j=0; j<7; j++) {

//Create object
var obj = new SomeType();

For proof, replace with this line with

var obj = new SomeType(j);
//Manipulate object
obj.doSomething();


o[j] = obj;

}

//Array not what is expected here

You have not said what you expect. Anyhow:

// 0,1
window.alert([o[0].foo, o[1].foo]);
someOtherObj.setArray(o);

The error may lie in here.
Does anyone have any enlightening explanations for why this occurs,
and what a solution might be?

Maybe if you posted the code of SomeType() or someOtherObj.setArray().

http://www.jibbering.com/faq/faq_notes/clj_posts.html#ps1DontWork


PointedEars
 
A

Are Nybakk

Are said:
[...] Let me illustrate the very basic task at hand, which is filling
an array with new objects. All seven positions in the array returned
point to the same object!

No, they don't.

If so, they are all identical objects, which is not the case. The
objects are created correctly, I have confirmed it.

*snip*
You have not said what you expect. Anyhow:

An array of 7 different objects?
// 0,1
window.alert([o[0].foo, o[1].foo]);
someOtherObj.setArray(o);

The error may lie in here.

This was just to illustrate what it's beeing used for later. The array
is wrong before this call.
Maybe if you posted the code of SomeType() or someOtherObj.setArray().

Simplified:

function SomeType() {

//private variables
var m_id = 0;

SomeType.prototype.setId = function(id) {
m_id = id;
}

SomeType.prototype.getId = function() {
return m_id;
}

}

Is it correct to set the methods inside the class like this btw? I
tested it and creating objects worked. Is it possible that all objects
of this type somehow operate on the same "private" variables?

*snip*
 
A

Are Nybakk

*snip*
Simplified:

function SomeType() {

//private variables
var m_id = 0;

SomeType.prototype.setId = function(id) {
m_id = id;
}

SomeType.prototype.getId = function() {
return m_id;
}

}

Is it correct to set the methods inside the class like this btw? I
tested it and creating objects worked. Is it possible that all objects
of this type somehow operate on the same "private" variables?

I think I was into something here. It seems the code below works as it
was meant to be :)

function SomeType() {

//private variables
var m_id = 0;

}

SomeType.prototype.setId = function(id) {
this.m_id = id;
}

SomeType.prototype.getId = function() {
return this.m_id;
}
 
T

Thomas 'PointedEars' Lahn

Are said:
Are said:
[...] Let me illustrate the very basic task at hand, which is filling
an array with new objects. All seven positions in the array returned
point to the same object!
No, they don't.

If so, they are all identical objects,

Pardon? You have said that they point to (refer to) the same object, my
test case shows that they do not. If what I said (and what my test case
proves) is true, there are different objects, of course.
which is not the case.

Of course not.
The objects are created correctly, I have confirmed it.

Doesn't matter.
*snip*


An array of 7 different objects?

Which is what happens. Have you even bothered to run my test case?
// 0,1
window.alert([o[0].foo, o[1].foo]);
someOtherObj.setArray(o);
The error may lie in here.

This was just to illustrate what it's beeing used for later. The array
is wrong before this call.

Then the error may lie only in the constructor, obj.doSomething(), or the
way you instantiate your variables.
Simplified:

function SomeType() {

//private variables
var m_id = 0;

SomeType.prototype.setId = function(id) {
m_id = id;
}

SomeType.prototype.getId = function() {
return m_id;
}
}

Is it correct to set the methods inside the class like this btw?

Firstly, there are no classes, these are languages that provide
prototype-based inheritance:

http://javascript.crockford.com/javascript.html
http://javascript.crockford.com/inheritance.html

It is correct, however less efficient than one-time redefinition/
augmentation, to try augmenting/redefining the prototype object in the
constructor.
I tested it and creating objects worked. Is it possible that all objects
of this type somehow operate on the same "private" variables?

Nevertheless, with such an initialization you do create a closure, with
`m_id' being a variable bound to the local execution context of the
constructor, and so the methods do operate on the same local variable
instantiated on the last constructor call (since that is when you define
the prototype methods last).

Here is a way to create private members that works as supposed:

function SomeType()
{
// private member
var m_id = 0;

this.setId = function(id) {
m_id = id;
};

this.getId = function() {
return m_id;
};
}

As you can see, in current client-side ECMAScript implementations you can
only buy information hiding with decreased memory efficiency.

http://www.crockford.com/javascript/private.html


HTH

PointedEars
 
T

Thomas 'PointedEars' Lahn

Are said:
*snip*

I think I was into something here. It seems the code below works as it
was meant to be :)

Only that you have no information hiding anymore, and that the local
variable really has become superfluous as it is _not_ used:
function SomeType() {

//private variables
var m_id = 0;

Unused local variable.
}

SomeType.prototype.setId = function(id) {
this.m_id = id;

Creates a new property of the calling object named `m_id', value of `id', or
overwrites the value of the existing property with that name.
}

SomeType.prototype.getId = function() {
return this.m_id;

Returns the value of the property named `m_id' of the calling object, or
`undefined' if the property has not been defined or set to `undefined' before.

And so

var o = new SomeType();
o.m_id = 'x';
window.alert(o.m_id);

is possible again. Not quite what you wanted, is it?


PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
Returns the value of the property named `m_id' of the calling object, or
`undefined' if the property has not been defined or set to `undefined' before.


And so

var o = new SomeType();
o.m_id = 'x';
window.alert(o.m_id);

is possible again. Not quite what you wanted, is it?

For a better proof that nothing is private anymore then, use

var o = new SomeType();
o.m_id = 'x';
window.alert(o.getId());

or

var o = new SomeType();
o.setId('x');
window.alert(o.m_id);


PointedEars
 
A

Are Nybakk

*snip*
Simplified:

function SomeType() {

//private variables
var m_id = 0;

SomeType.prototype.setId = function(id) {
m_id = id;
}

SomeType.prototype.getId = function() {
return m_id;
}

}

Is it correct to set the methods inside the class like this btw? I
tested it and creating objects worked. Is it possible that all objects
of this type somehow operate on the same "private" variables?

I think I was into something here. It seems the code below works as it
was meant to be :)

function SomeType() {

//private variables
var m_id = 0;

}

SomeType.prototype.setId = function(id) {
this.m_id = id;
}

SomeType.prototype.getId = function() {
return this.m_id;
}
 
A

Are Nybakk

Yes, I bumped into this as I had set properties on some of those
variables in the constructor. The methods did then not know of it,
giving 'undefined' results.
For a better proof that nothing is private anymore then, use

var o = new SomeType();
o.m_id = 'x';
window.alert(o.getId());

or

var o = new SomeType();
o.setId('x');
window.alert(o.m_id);

I think I'm beginning to hate JS :p Thanks for clearing this up.

I wonder which is generally the better of two evils.. inefficient data-
hiding or efficient public data... any thoughts? Some of my classes
contain only "static" methods, so there's no problem there, but I have
some others which contains data, like in this example, and just 1-2
methods. I wouldn't say the data-hiding is _necessary_, but in some
cases value-checking might be nice to have. The code certainly would
be more robust and reusable that way. I guess I'm pretty much
answering my own question.
 
T

Thomas 'PointedEars' Lahn

Are said:
I think I'm beginning to hate JS :p Thanks for clearing this up.

I wonder which is generally the better of two evils.. inefficient data-
hiding or efficient public data... any thoughts? Some of my classes
contain only "static" methods, so there's no problem there, but I have
some others which contains data, like in this example, and just 1-2
methods. I wouldn't say the data-hiding is _necessary_, but in some
cases value-checking might be nice to have. The code certainly would
be more robust and reusable that way. I guess I'm pretty much
answering my own question.

Yes, why not use the best of both worlds? It appears to reasonable to use
private members and protected accessor methods only when information hiding
or value checking is required, and public properties otherwise.

However, to ease your pain a little bit ;-) there are ECMAScript
implementations that support getters and setters. For example,
JavaScript 1.5:

function SomeType()
{
var id = 0;

this.__defineGetter__(
"id",
function() {
return id;
}
);

this.__defineSetter__(
"id",
function(v) {
if (!isNaN(v)) id = v;
}
);
}

var o = new SomeType();

o.id = "a";

// 0
window.alert(o.id);


Please trim your quotes to the necessary minimum.


PointedEars
 
L

Lasse Reichstein Nielsen

Are Nybakk said:
I think I was into something here. It seems the code below works as it
was meant to be :)
Almost.

function SomeType() {

//private variables
var m_id = 0;

This declares a local variable that is not accessible by any other
code. You can remove the declaration and not change anything.

You might vant to do:
this.m_id = 0;
instead, which does initialize the object property that the following
methods access:
SomeType.prototype.setId = function(id) {
this.m_id = id;
}

/L
 
A

Are Nybakk

*snip*
However, to ease your pain a little bit ;-) there are ECMAScript
implementations that support getters and setters. For example,
JavaScript 1.5:

*snip*

Ah, now that's very nice! Too bad it seems IE doesn't support this.
Personally I don't see any point at all in using IE, but the users do,
sadly. Thanks again for the input, it was really useful 8)

(Sigh, I need to go back to a real usenet-client. Damn Google...)
 

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,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top