homepage Welcome to WebmasterWorld Guest from 54.166.228.100
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Pubcon Platinum Sponsor 2014
Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
Forum Library, Charter, Moderator: open

JavaScript and AJAX Forum

    
Failing to pass by reference
gasell




msg:3601087
 10:31 pm on Mar 14, 2008 (gmt 0)

I read somewhere that if you pass an object to a function then it is passed by reference. Since it sounded just what I needed I tried it out to find that it didn't work. I either did something wrong or am trying to achieve impossible. Since I'm a beginner I don't which case it is.

In head I have a script that defines:

function myobject() 
{
var name;
}

I also make an object of that type in head outside any function and define the function (let's call it foo) that's supposed to pass it on to another function (let's call it bar). Foo doesn't get object as parameter but it calls bar with my object. Foo itself is called in body section of the page. Bar is defined in external .js file that is imported in head. In Firefox I don't get an error if I try to modify name in bar, but when I try to use name in foo after a call to bar then it isn't there.

Also let's say I've called foo once and name is initialized by bar(if it is possible), then what if I call foo again afterwards? Can I still access what's stored in name?

I'm not entirely sure now that it was clear enough. Feel free to ask more information.

 

gasell




msg:3601095
 10:47 pm on Mar 14, 2008 (gmt 0)

My mistake. I had an asynchronous request in progress at the same time, when testing.

MarkFilipak




msg:3601238
 3:51 am on Mar 15, 2008 (gmt 0)

Pass By Reference

Actually, gasell, javascript is kinda weird. It passes by value, not reference, but when you manipulate the property of an object that is passed in, it acts like it's passing by reference. To confirm this, try
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"/>
<html>
<meta http-equiv = 'Content-Type' content = 'text/html; charset = ISO-8859-1'>
<meta http-equiv = 'Content-Language' content = 'en'>
<meta http-equiv = 'Content-Script-Type' content = 'text/javascript'>
<meta http-equiv = 'Content-Style-Type' content = 'text/css'>
<meta http-equiv = 'Expires' content = 'Thu, 01 Jan 1970 00:00:00 GMT'>
<meta http-equiv = 'Pragma' content = 'no-cache'>
<meta http-equiv = 'Cache-Control' content = 'no-cache'>
<script><!--
var object1 = {prop: 'hello'};
function changeProperty(object, propertyName, newValue) {
object[propertyName] = newValue;
}
function changeObject(object, propertyName, newValue) {
object = {};
object[propertyName] = newValue;
}
/*line 1*/ alert(object1.prop);
/*line 2*/ changeProperty(object1, 'prop', 'goodbye');
/*line 3*/ alert(object1.prop);
/*line 4*/ changeObject(object1, 'prop', 'hello again');
/*line 5*/ alert(object1.prop);
//--></script>
</head>
</html>

Line 1 displays the value of object1.prop (='hello').
Line 2 passes object1.
Line 3 shows that the value of object1.prop has changed (='goodbye') so it seems that the object was passed by reference, otherwise the value of the global wouldn't have changed.
Line 4 passes object1 once again, this time to changeObject.
Line 5 shows that the value of object1.prop has not changed (still ='goodbye') so it seems that changeObject's first line did not reinitialize object1, thus, the 1st arg to changeObject could not possibly have been a reference.

fside




msg:3601333
 7:51 am on Mar 15, 2008 (gmt 0)

> is kinda weird <

It's not necessarily an exception to the pass-by-value method. That is how it's done, supposedly. Javascript passes object references, by value. That's the official language. So, it's always object reference, by value. Copies, values, are being used by the called function. For primitive objects, apparently, this value is as one would expect, a copy. But not for non-primitive objects, it's a vector/pointer. And not complete trees. The value of object primitive 4, is 4. So the function is passed the value, 4. The value of an object which contains a variable with a value of 4, is apparently - object. Apparently a new copy of the object is made for the function. But it's only a placeholder for the copied object. What's in the object is not copied.

There's no 'deep copy'. What's in the object is defined, still, only in the original object. Since the inside objects aren't copied, as with other programming languages objects in the object can be modified, effectively by reference. So one COULD create a script passing by reference if they passed an enclosing object, and then referred to dependent (obviously) objects within. If the object is, "obj", you can't change "obj". But you can alter the values of existing member objects. You can add to them. You can delete them. Etc. It's almost like a 'root node', and the inability to lose that. But you can change everything 'inside'.

So with that said, why wouldn't it also be true if x=4 is a 'primitive' object, wouldn't x:4 be changeable as part of its object? acting as if by reference:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<style type="text/css">

</style>
</head>
<body>

<script>

x = 4;

function incrX(x){ x++ }
incrX(x);

alert(x); /* 4 */

/*___________*/

obj = { }; /* or just { x:4 } */
obj.x = 4;

function incrOx(obj){ obj.x++ }
incrOx(obj);

alert( obj.x ); /* 5 */

/*___________*/

incrX(obj.x);

alert( obj.x ); /* 5 */

/*___________*/

obj.ar = [ 1, 2, 3 ];

var modOar = function(obj){ obj.ar[1]++ }(obj);

alert( obj.ar ); /* 1,3,3 */

/*___________*/

var pushOar = function(obj){ obj.ar[5]=6 }(obj);

alert( obj.ar[5] ); /* 6 */

/*___________*/

var deleteOar = function(obj){ obj.ar=null }(obj);

alert( obj.ar ); /* null */

</script>

</body>
</html>

It would then seem the way to avoid inadvertent 'by reference' changes, which is effectively what they are, to create an effective by-value one would have to run through the entire object and copy the whole thing in recursive fashion, every name/value. Create a complete, full-tree copy of the function. And work on that.

You could add this as a last example:

/*___________*/

obj.ar = [ 1, 2, 3 ];

function copyObj(obj) {
for (i in obj) {
if (typeof obj[i] === 'object') {
this[i] = new copyObj(obj[i]);
} else {
this[i] = obj[i];
}
}
}

var mod1Oar = function(obj){
obj = new copyObj(obj)
obj.ar[1]=10;

alert( obj.ar[1] ); /* 10 */
alert( obj.ar[2] ); /* 3 */
}(obj);

alert( obj.ar[1] ); /* 2 */

fside




msg:3601408
 12:19 pm on Mar 15, 2008 (gmt 0)

Can't edit, at this point.

Let me correct a typo.

It read: "create an effective by-value one would have to run through the entire object and copy the whole thing in recursive fashion, every name/value. Create a complete, full-tree copy of the function."

S/B pass by-value, one would have to run through the entire object and copy the whole thing in recursive fashion, every object in the object, every name/value. One would create a complete, full-tree copy of the object."

MarkFilipak




msg:3601721
 12:22 am on Mar 16, 2008 (gmt 0)

> Javascript passes object references, by value

1, By reference means that the base memory address of an object's data structure is passed via the call stack.
2, By object means that a copy of an object's data structure is made and the copy is passed via the call stack.

Per ECMA, 1 is never the case. That said (written), the reason why changeProperty() works, as it clearly does, is not explained.

Edit:

fside, I think your explanation is half-right, but for the wrong reasons. Bear with me, friend, because to my experience, this has never been adequately explained and I'm interested in your thoughts.

...oops. Notification went out so I'd better continue this thought in another message

[continued...]

[edited by: MarkFilipak at 12:31 am (utc) on Mar. 16, 2008]

MarkFilipak




msg:3601753
 1:15 am on Mar 16, 2008 (gmt 0)

[...continued]

fside, you write of primative objects vs. non-primative objects. Javascript (nor Java for that matter) doesn't make any such distinction. An object is an object whether its constructor is Object or HTMLDivElement. That's the part of your explanation that is half-wrong.

Suppose that an object consists of a data structure that contains
1, the object's datatype,
2, its value, and
3, a list of pointers to its properties (or a pointer to the list of pointers).

When an object is passed, that structure is copied and the copy is passed. Thus it can be said that the object is "passed by value". Actually, the object is not passed (by value or otherwise). A value (structure) identical to the object's value (structure) is created and it is that structure that is passed.

The called function (changeProperty or changeObject) receives that value (structure). If the code in the function overwrites a property (as changeProperty does), it gets to that property via the list of pointers. Since that list is identical to the original object's list (that is, the original object and the passed-in object both point to the same properties), the property of the original object is overwritten. However, if the code overwrites the passed-in object (as changeObject does), the passed-in object is overwritten and a new list of properties is created for it. The two objects no longer point to the same property list. Thus, changing or overwritting a property of the new object does not affect the original object or its properties.

So, if the explanation above is correct (as I believe it is), javascript does not pass by value, it passes by copy of value.

What do you think, fside?

fside




msg:3602003
 10:44 am on Mar 16, 2008 (gmt 0)

> never been adequately explained <

I admit that I found ECMA262-3 misleading in one thing in particular. I quoted. I shouldn't have. But to be fair, they do leave a lot to the implementers.

The official language is that the object references are passed, by value. There are 'native' and 'built in' objects. And a primitive is different than an object/function.

ECMA262-3: An object is a member of the type Object. It is an unordered collection of properties each of which
contains a primitive value, object, or function.

The reason for this behavior with objects in other languages is because a vector/pointer is passed which refers to the object/structure. I suggested an object copy function, which has been around forever. Then you would be working on a copy of the object.

If the tree were copied, as xslt's copy-of and others, then the values could be altered in the function scope and not affect the global, in this case. But when you try to change the function itself, as your changeobject tries to reinitialize, or if you'd set it to null, or whatever, then you appear to suddenly be working with a different object inside the function. The global becomes 'disconnected', as you say. The value of the reference, if you will, has been altered. Essentially, you've placed a "var" in front of it. You've created a separate object, is all. It used to point to the object being passed in. Now it points to a new and different object.

MarkFilipak




msg:3602410
 12:04 am on Mar 17, 2008 (gmt 0)

fside:

What you write seems logical, but you're not taking into account what is happening in memory. Objects and variables and values don't just exist in the ether. They are memory locations. Regarding your explicit comments...

> ...each of which contains a primitive value...
First, primitive values are not directly accessible. Second, you wrote of primitive objects vs. non-primitive objects. I don't believe there is any such distinction.

In my post, I carefully described a mechanical process that involves how memory is used, and that explains what happens at the code level. Unless this description is shown to be wrong, I believe that it is correct and that it explains more than vague concepts like "primitive objects" vs. "non-primitive objects". So my opinion is that javascript passes "by copy of value" and I'm sticking to it.

fside




msg:3602633
 7:06 am on Mar 17, 2008 (gmt 0)

> primitive values are not directly accessible <

Just in the sense that as Crockford says - "everything else is objects"

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<style type="text/css">

</style>
</head>
<body>

<script>

x = 4;

alert(typeof x); /* number */

s = "hello";

alert(typeof s); /* string */

s.s1 = "again";

alert(s.s1); /* undefined */

s = { };

alert(typeof s); /* object */

s.s1 = "again";

alert(s.s1); /* "again" */

</script>

</body>
</html>

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved