Go Back   CodingForums.com > :: Client side development > JavaScript programming

Before you post, read our: Rules & Posting Guidelines

Reply
 
Thread Tools Rate Thread
Enjoy an ad free experience by logging in. Not a member yet? Register.
Old 01-03-2011, 06:36 PM   PM User | #1
johnmerlino
Regular Coder

 
Join Date: Oct 2009
Posts: 189
Thanks: 38
Thanked 3 Times in 3 Posts
johnmerlino is an unknown quantity at this point
Passing object by reference question

My question is commented in the script:

Code:
function Love(){
	var req = {
		ring : 'gold',
		money : 'a lot',
		commitment : 'long-term'
	}
	
	this.loveReqs = function(){
		return req;
	}
}

var you = new Love();
var details = you.loveReqs();
details.ring = "silver";
console.log(details.ring);


var me = new Love();
var details = me.loveReqs();
console.log(details.ring); // why does this return gold and not silver if req is passed by reference and we already changed its value above and so it's pointing to the same memory position?
johnmerlino is offline   Reply With Quote
Old 01-03-2011, 07:42 PM   PM User | #2
DaveyErwin
Regular Coder

 
Join Date: Aug 2010
Posts: 809
Thanks: 12
Thanked 168 Times in 166 Posts
DaveyErwin is on a distinguished road
Quote:
Originally Posted by johnmerlino View Post
My question is commented in the script:

Code:
function Love(){
	var req = {
		ring : 'gold',
		money : 'a lot',
		commitment : 'long-term'
	}
	
	this.loveReqs = function(){
		return req;
	}
}

var you = new Love();
var details = you.loveReqs();
details.ring = "silver";
console.log(details.ring);


var me = new Love();
var details = me.loveReqs();
console.log(details.ring); // why does this return gold and not silver if req is passed by reference and we already changed its value above and so it's pointing to the same memory position?
The value of req is not change in this code.The value returned by
me.loveReqs() stored in details has been altered.
DaveyErwin is offline   Reply With Quote
Old 01-03-2011, 09:22 PM   PM User | #3
Logic Ali
Regular Coder

 
Logic Ali's Avatar
 
Join Date: Sep 2010
Location: London
Posts: 959
Thanks: 0
Thanked 198 Times in 193 Posts
Logic Ali will become famous soon enoughLogic Ali will become famous soon enough
Quote:
Originally Posted by johnmerlino View Post
var you = new Love();
var details = you.loveReqs();
details.ring = "silver";
console.log(details.ring);


var me = new Love();
var details = me.loveReqs();
console.log(details.ring); // why does this return gold and not silver if req is passed by reference and we already changed its value above and so it's pointing to the same memory position?
[/CODE]
you and me are different instances, so why would a change to a property of one be reflected in the other?
Logic Ali is offline   Reply With Quote
Old 01-03-2011, 09:23 PM   PM User | #4
johnmerlino
Regular Coder

 
Join Date: Oct 2009
Posts: 189
Thanks: 38
Thanked 3 Times in 3 Posts
johnmerlino is an unknown quantity at this point
But req is a private variable and therefore not part of the returned object when constructor is called:

Code:
 
function Love(){
        // var this = Object.create(Love.prototype);

	var req = {
		ring : 'gold',
		money : 'a lot',
		commitment : 'long-term'
	}
	
	this.loveReqs = function(){
		return req;
	}

     //return this;
}
So req is an own member of Love and never part of the you instance. req is only accessible because of the closure created. However, it's still not part of the instance. But we can access it through the "privileged" method.

Nevertheless, we call the privileged method and assign its returned object (req) to variable a:

Code:
var you = new Love();
var a = you.loveReqs();
a.ring = "silver";
console.log(a.ring);
So when we return the object and assign it to variable a, a now points to the original object, which is a private property not accessible to the instance, no? If it points to original object, then this does too:

Code:
var me = new Love();
var b = me.loveReqs();
console.log(b.ring);
Hence, since b is pointing to what a is pointing to, the value should be the same. Isn't that what passing by reference is all about?

Thanks for response.

Last edited by johnmerlino; 01-03-2011 at 09:31 PM..
johnmerlino is offline   Reply With Quote
Old 01-04-2011, 05:24 PM   PM User | #5
DaveyErwin
Regular Coder

 
Join Date: Aug 2010
Posts: 809
Thanks: 12
Thanked 168 Times in 166 Posts
DaveyErwin is on a distinguished road
Code:
<html>
<head>
  <title> pointers? </title>
</head>
<body>
  <div id="container">&nbsp;</div>
<script type="text/javascript">
 function Love(){
	req = {
		ring : 'gold',
		money : 'a lot',
		commitment : 'long-term'
	}	
	this.loveReqs = function(){
		return req;
	}
}
var details;
var you = new Love();
details = you.loveReqs();
document.write('here ring = ' + details.ring + ' as expected <br>');
req.ring = 'x';
document.write('here we have changed ring to ' + details.ring + ' by changing the req object <br>');
document.write('But as you can see from the alerted code a new instance of Love will set req.ring to gold <br>');
alert(Love)
var me = new Love();
details = me.loveReqs();
document.write('here ring again equals ' + details.ring ); 
</script>
</body>
</html>
DaveyErwin is offline   Reply With Quote
Old 01-04-2011, 09:42 PM   PM User | #6
Old Pedant
Supreme Master coder!

 
Old Pedant's Avatar
 
Join Date: Feb 2009
Posts: 23,198
Thanks: 59
Thanked 3,996 Times in 3,965 Posts
Old Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to all
Quote:
req is only accessible because of the closure created. However, it's still not part of the instance.
Actually, it is part of the instance. It's not *accessible* directly through an instance of Love, but nevertheless the fact that you used a closure means that indeed each instance of Love will have its own copy.

If you think about it, there's no other way that closures can work. The whole point of a closure is to create a value that is private to each instance of a function. If that didn't happen, closures would be worthless. The fact that in this case the function is being used as a constructor doesn't change how the closure should and does work.
__________________
An optimist sees the glass as half full.
A pessimist sees the glass as half empty.
A realist drinks it no matter how much there is.
Old Pedant is online now   Reply With Quote
Old 01-05-2011, 10:16 PM   PM User | #7
johnmerlino
Regular Coder

 
Join Date: Oct 2009
Posts: 189
Thanks: 38
Thanked 3 Times in 3 Posts
johnmerlino is an unknown quantity at this point
But aren't prototype properties not recreated when new instance is called with constructor?

Take a look:
Code:
function Love(){
	var z = {a : 'a'};
 	this.getZ = function(){
		return z;
	}
}

var inst = new Love();
var ref = inst.getZ();
ref.a = 'abc'; 
console.log(inst.getZ()); //output:  Object { a="abc"} - Again this proves that object is passed by reference because when we called getZ() the first time, we assigned the returned object to another object, and when changing the values on the other object, it changed the values on the inst object.

var inst2 = new Love();
console.log(inst2.getZ()); //output:  Object { a="a"} - This proves when we instantiate and call constructor, it recreates its own members and so inst2 is now dealing with a totally different object.

//However, we are told that prototype does not recreate the members and so the prototype properties are shared across all instances:
Love.prototype = {
	getB : function(){
		return {key : 'value'};
 	} 
}

var instance = new Love();
var instance_variable = instance.getB();
instance_variable.key = "property's value";
var instance2 = new Love();
var instance_variable2 = instance2.getB();
console.log(instance_variable2.key); // output is "value" not "property's value"!
Why does it refer to the original property again if we changed it in the instance_variable instance and if all instances share same prototype, meaning that prototype properties are NOT recreated whenever constructor is called, then that property should have been permanently changed. But obviously it's not.

Thanks for response.
johnmerlino is offline   Reply With Quote
Old 01-05-2011, 11:27 PM   PM User | #8
DaveyErwin
Regular Coder

 
Join Date: Aug 2010
Posts: 809
Thanks: 12
Thanked 168 Times in 166 Posts
DaveyErwin is on a distinguished road
Code:
<html>
<head>
  <title> which object ? </title>
</head>
<body>
  <div id="container">&nbsp;</div>
<script type="text/javascript">
 function Love(){
	var z = {a : 'a'};
 	this.getZ = function(){
		return z;
	}
}

var inst = new Love();
var ref = inst.getZ();
ref.a = 'abc'; 
document.write(inst.getZ()); //output:  Object { a="abc"} - Again this proves that object is passed by reference because when we called getZ() the first time, we assigned the returned object to another object, and when changing the values on the other object, it changed the values on the inst object.

var inst2 = new Love();
document.write(inst2.getZ()); //output:  Object { a="a"} - This proves when we instantiate and call constructor, it recreates its own members and so inst2 is now dealing with a totally different object.

//However, we are told that prototype does not recreate the members and so the prototype properties are shared across all instances:
Love.prototype = {
	getB : function(){
		return {key : 'value'};
 	} 
}

var instance = new Love();
var instance_variable = instance.getB();
instance_variable.key = "property's value";
alert(Love.prototype.getB)
Love.prototype = {
	getB : function(){
		return {key : "property's value"};
 	} 
}
var instance2 = new Love();
var instance_variable2 = instance2.getB();
document.write(instance_variable2.key); // output is "property's value"!

</script>
</body>
</html>
johnmerlino said ...
"Why does it refer to the original property again if we changed it in the instance_variable instance and if all instances share same prototype, meaning that prototype properties are NOT recreated whenever constructor is called, then that property should have been permanently changed. But obviously it's not. "

Because the value of Love.prototype.getB is not changed
DaveyErwin is offline   Reply With Quote
Users who have thanked DaveyErwin for this post:
johnmerlino (01-05-2011)
Old 01-05-2011, 11:58 PM   PM User | #9
johnmerlino
Regular Coder

 
Join Date: Oct 2009
Posts: 189
Thanks: 38
Thanked 3 Times in 3 Posts
johnmerlino is an unknown quantity at this point
Quote:
Originally Posted by DaveyErwin View Post
Code:
<html>
<head>
  <title> which object ? </title>
</head>
<body>
  <div id="container">&nbsp;</div>
<script type="text/javascript">
 function Love(){
	var z = {a : 'a'};
 	this.getZ = function(){
		return z;
	}
}

var inst = new Love();
var ref = inst.getZ();
ref.a = 'abc'; 
document.write(inst.getZ()); //output:  Object { a="abc"} - Again this proves that object is passed by reference because when we called getZ() the first time, we assigned the returned object to another object, and when changing the values on the other object, it changed the values on the inst object.

var inst2 = new Love();
document.write(inst2.getZ()); //output:  Object { a="a"} - This proves when we instantiate and call constructor, it recreates its own members and so inst2 is now dealing with a totally different object.

//However, we are told that prototype does not recreate the members and so the prototype properties are shared across all instances:
Love.prototype = {
	getB : function(){
		return {key : 'value'};
 	} 
}

var instance = new Love();
var instance_variable = instance.getB();
instance_variable.key = "property's value";
alert(Love.prototype.getB)
Love.prototype = {
	getB : function(){
		return {key : "property's value"};
 	} 
}
var instance2 = new Love();
var instance_variable2 = instance2.getB();
document.write(instance_variable2.key); // output is "property's value"!

</script>
</body>
</html>
johnmerlino said ...
"Why does it refer to the original property again if we changed it in the instance_variable instance and if all instances share same prototype, meaning that prototype properties are NOT recreated whenever constructor is called, then that property should have been permanently changed. But obviously it's not. "

Because the value of Love.prototype.getB is not changed
So what is changed is this.getB, where "this" refers to the current instance. So when you do:

Code:
var instance_variable = instance.getB();
we are calling getB() part of the returned "this" object from the constructor. Hence, that getB() method was added as a property to the current object. So when we change its value:

Code:
instance_variable.key = "property's value";
it will only affect the current instance and that which we passed by reference from the current instance.

But the original method, which is the prototype of the Love constructor remains unchanged, as you show:

Code:
Love.prototype.getB
Ultimately, you are changing the property of "this" not the actual prototype property of the Love constructor.

If that's the case, then that makes sense. thanks.

Last edited by johnmerlino; 01-06-2011 at 12:04 AM..
johnmerlino is offline   Reply With Quote
Old 01-06-2011, 01:08 AM   PM User | #10
johnmerlino
Regular Coder

 
Join Date: Oct 2009
Posts: 189
Thanks: 38
Thanked 3 Times in 3 Posts
johnmerlino is an unknown quantity at this point
Actually what I wrote above is wrong. THe properties of prototype are never attached as properties to the returned "this" object from the constructor. They always remain part of the Love object. When "this" is returned by the constructor during instantiation, somehow the JavaScript engine makes the properties of Love.prototype available to the instance, but they are not properties of "this" for the following reason:

Code:
var instance_variable = instance.getB();
instance_variable.key = "property's value";
console.log(Love.prototype.getB()); // output is "value"  
console.log(instance.getB()); //output is "value"!!!!

Yet you get different behavior with this:

Code:
var instant = new Love();
var instant_obj = instant.getZ();
instant_obj.a = 'd';
console.log(instant.getZ()); // output is 'd' not 'a'
So wen we modified the returned object when the method was declared in the constructor with this, this is altered. However, when we modify the returned object, and then return instance method, it is not changed by changes in returned object. Only conclusion is that the prototype properties are never attached to the returned instance. Yet somehow the returned instance can access them.
johnmerlino is offline   Reply With Quote
Old 01-06-2011, 01:20 AM   PM User | #11
johnmerlino
Regular Coder

 
Join Date: Oct 2009
Posts: 189
Thanks: 38
Thanked 3 Times in 3 Posts
johnmerlino is an unknown quantity at this point
Ok I think this is how it works. when you create the instance, it returns an object (return this). this has all the instance methods you created with this keyword packaged with the returned this object. Now when you call one of those methods of prototype, it's not part of "this". So the interpeter must resolve it. It goes one level up scope chain to the constructor of this. Interpreter notices that the method is not declared as an own member, so it checks the prototype and indeed it finds it. So it returns the method. But that method is never part of the returned object, explaining why we cannot alter it with the instance. Yet we are able to alter the instance methods packaged with "this".
johnmerlino is offline   Reply With Quote
Old 01-06-2011, 02:58 PM   PM User | #12
johnmerlino
Regular Coder

 
Join Date: Oct 2009
Posts: 189
Thanks: 38
Thanked 3 Times in 3 Posts
johnmerlino is an unknown quantity at this point
Alright ignore my posts above. After doing some research on ECMA, I'm pretty confident this is how it all works. I explain it in the comments:

Code:
function Love(){
	//var this = Object.create(Love.prototype);	
 	this.getObj = function(){
		return {a : 'a'};
	}
	
	var z = {a : 'a'};
 	this.getZ = function(){
		return z;
	}
 	//return this;  
}

Love.prototype = {
	getKey : function(){
		return {key : 'value'};
 	}
}

var instant = new Love();
var instant_obj = instant.getObj();
console.log(instant_obj);
var instant_obj2 = instant_obj;
instant_obj.a = 'd';
console.log(instant.getObj()); //Object {a="a"} - This returns original object and its key/value pairs because the object literal in the inner function may have access to the variables of outer function after function exits, courtesy of closure, but the variables in the inner function are themselves destroyed when function exits, meaning that when we call the function again, it returns a new object every single time. Now if we store the returned object in a variable, and then reference it in another object, then that object will be passed by reference and modifying one will modify the other. Check end notes
console.log(instant_obj2.a); //'d' - objects passed by reference change

var inst = new Love();
var ref = inst.getZ();
console.log(ref);
ref.a = 'abc'; 
console.log(inst.getZ()); //Object {a="abc"} - The reason why this returns "abc" is because the variable z is a closure (outside of the immediate function), so when we call the function again, changes to it are remembered. It has nothing to do with passing an object by referenece. 

 
var instance2 = new Love();
var instance_variable = instance2.getKey();
var instance_variable2 = instance_variable;
instance_variable.key = "property's value";
console.log(instance2.getKey()); //Object {key="value"} - This returns original object and its key/value pairs because the object literal in the inner function may have access to the variables of outer function after function exits, courtesy of closure, but the variables in the inner function are themselves destroyed when function exits, meaning that when we call the function again, it returns a new object every single time. Now if we store the returned object in a variable, and then reference it in another object, then that object will be passed by reference and modifying one will modify the other. 
//So the question remains how does the instance have access to getKey() if getKey() is part of the prototype of Love. The answer: The "new" operator will invoke your constructor passing in the specified parameters. A special variable named "this" will exist within the scope of the constructor (var this). "this" points to the current object instance (given that "this" is returned at the end of the constructor expression: return this;). Using "this" you can add and modify properties on the instance being created by the constructor (e.g. this.a = 'a'; this.fun = function(){}). all JS objects have a private prototype property. I say "private" because this property is not directly visible or accessible from the object itself (e.g. you don't say instance.prototype.getB()). When the runtime performs a lookup on a property, it first looks at the instance to see if that property is defined there. If it is not defined there, the runtime looks for the property on the object's private prototype. So how does the instance have access to getB() if it was initialized in the constructor's prototype? When new operator is invoked, it not only creates the new object, but it also assigns the constructor's prototype property (the publicly accessible one) to the new instance's private prototype. By defining properties on the constructor's prototype, like Love.prototype.getB(), we are creating properties that will be in the private prototype chain of each new instance. These become, in effect, instance methods. 

console.log(instance_variable2.key); //property's value - objects passed by reference change
johnmerlino is offline   Reply With Quote
Reply

Bookmarks

Tags
object, reassignment, reference

Jump To Top of Thread


Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 12:40 AM.


Advertisement
Log in to turn off these ads.