Why does JavaScript treat the scope of an array differently than it does the scope of other variables? Typically, if one passes a variable in a global scope into a function as a parameter, it is then local and changing it within the function does not change the value of the global variable. For example:
var globalInt = 1;
function test1(x){
x = x + 1
}
test1(globalInt);
console.log(globalInt); //globalInt is still 1
However, it appears the same does not apply when passing an array of values.
var globalArray = ["TEST"];
function test(x){
x[0] = x[0].toLowerCase()
}
test(globalArray);
//globalArray is now ["test"] instead of ["TEST"]
console.log(globalArray[0]);
This happens for me when I test in Chrome, but I have not tested it in other browsers so far. Why does this happen and does it happen in other browsers?
This is simply because an array (which is an Object) are passed by reference while primitives are not. Note that technically it is passed by value but in this case that value is a reference, thanks Esteban
A object is automatically passed by reference, without the need to specifically state it
If you pass an object (i.e. a non-primitive value, such as Array or a user-defined object) as a parameter and the function changes the object's properties, that change is visible outside the function, as shown in the following example:
MDN Link
Yes... JavaScript objects and arrays (which are objects) are passed by reference. But you should remember to read the method signature explicitly because some array methods don't alter the original array but return a new one. Read the MDN documentation carefully about the method in question. Array.prototype.map() would actually leave the original array intact and return a brand new array which you'd need to set to assign to a variable.
I'm new to JavaScript (though experienced in C++), and today, I wrote something like this:
function foo(bar) {
bar = "something else";
}
var x = "blah";
foo(x);
alert(x); // Alerts with "blah", but I was expecting it to alert with "something else"
This confused me a lot, as I've been watching some JavaScript videos by Douglas Crockford, and remember him saying something like "JavaScript is always pass by reference".
The way I can explain this situation is that JavaScript passes references to objects, but those references are copied. This would mean in the foo function, I am assigning a new reference to bar, which then goes out of scope, leaving to reference that x has left untouched. Essentially we start with:
x ---->"blah"
Then when foo is called, bar references the same data:
x ---->"blah"
bar -----^
So when "something else" is assigned to bar, this happens:
x ---->"blah"
bar ---->"something else"
Is that an accurate model of what is actually happening in JavaScript, or am I missing something else?
As an extra question, is there any way to say, change the data referenced by this variable? Is this a situation that comes up often, or can it be easily avoided?
Edit:
Douglas Crockford in the video I watched says "objects are always passed by reference they're not passed by value", which is correct, but arguments to functions are passed by value, it's just the reference is passed by value.
Your interpretation is spot on.
First, you have a variable called x which is a reference to a string object. Let's say that memory is 0x100. x points to 0x100, which contains the bytes blah:
var x = "blah"; // x is 0x100 which references a string in memory
Next, you pass 0x100 into the function foo:
function foo(bar) {
bar = "something else";
}
As everything in JavaScript is passed by value, even references, JavaScript makes a copy of this reference in memory, which is now called bar within that function:
foo(x); // Copies the value of x (a reference) to bar
At this point, we have two separate variables. x and bar. Both happen to have the same value, 0x100. Thus, if you were to change a property of the object either of those is referencing, it would affect both x and bar.
However, what you're doing is assigning bar to point to something else:
bar = "something else"; // Now references some other string we just created
Now, bar gets re-assigned to reference a new string we've just allocated memory for. bar no longer has a value of 0x100, it now has a value of some other address (say 0x500). x of course still has a value of 0x100 since bar was merely a copy of x, and not a reference to x.
For this reason, when you:
alert(x);
You'll still get the original value, as that is what x is pointing to.
Second question:
is there any way to say, change the data referenced by this variable?
Is this a situation that comes up often, or can it be easily avoided?
Yes, just wrap it in another object. For example:
var x = {Value: "blah"};
foo(x);
Now, we have a reference to an object with a property called Value, which contains a reference to a string in memory somewhere.
In foo, we can do:
bar.Value = "something else";
Which will affect the Value property of x, since both bar and x referenced the same object, and you never changed the value of either of them.
In other words, you cannot re-assign the reference you're passing into a function, since you're simply re-assigning a copy. You can, however, change a property of an object being referenced, since other copies of that reference all point to the data you're changing.
Your interpretation is correct.
You can change the values of keys in an object, which lets you do something similar to pass-by-reference:
function foo(bar) {
bar.msg = "something else";
}
var x = { msg: "blah" };
foo(x);
alert(x.msg);
Douglas Crockford in the video I watched says "objects are always
passed by reference they're not passed by value", which is correct,
but arguments to functions are passed by value, it's just the
reference is passed by value.
It's not correct. What that describes is precisely called pass-by-value. JavaScript, like Java, only has pass-by-value. There is no pass-by-reference.
You understanding is correct. Every value in JavaScript is either a primitive, or a reference (pointer to an object). An object itself can never be a value directly. When you pass or assign a reference (pointer to an object), the new copy of the pointer sees the same object as the original pointer. But they are still two different pointer variables.
I know you've answered your own question with your edit...
Douglas Crockford in the video I watched says "objects are always passed by reference they're not passed by value", which is correct, but arguments to functions are passed by value, it's just the reference is passed by value.
but because that edit made me suddenly grok how this worked... which I will admit I was struggling with here is a code sample and pen that I think really demonstrates it.
x = {};
y = x; //point y reference to same object x is pointed to
console.log(x === y) //true both pointed at same object
function funky(o) //pass by value a reference to object
{
o = null; //change reference to point to null away from object
}
funky(x);
console.log(x)//not null still an object
var myObj = {
value: "Hello"
};
function change(localObj) {//pass reference to object
localObj.value = "Bye";//change property through the reference
localObj = null;//point the reference to null away from object
}
console.log(x === y) //still same reference;
change(myObj);
console.log(myObj.value) // Prompts "Bye"
console.log(myObj) //not null - its an object;
x = myObj; //point x to different object
console.log(x === y) //false pointed at different object;
console.log(x);
console.log(y);
https://codepen.io/waynetheisinger/pres/YewMeN
"JavaScript is always pass by reference" is, well, a [white] lie and a confusion of terms. While there is some "gray area", I go by these definitions of evaluation strategies.
Here are my arguments and reasoning. If you hold a different view, make sure that you can at least support it.
Call By Reference
Call By Reference means (to many people) that assigning to a parameter affects bindings in the caller.
In call-by-reference evaluation (also referred to as pass-by-reference), a function receives an implicit reference to a variable used as argument, rather than a copy of its value. This typically means that the function can modify (i.e. assign to) the variable used as argument—something that will be seen by its caller.
This is not the case in JavaScript, as the original post has noted in the observed behavior. Re-assigning a parameter (which can be thought of as a local variable with a dynamically supplied value) has no affect on any supplied arguments.
Sometimes, "Call By Reference" is [confusingly] used to mean "Call By Sharing" or "Call By Value [of the Reference]" as discussed next; true Call By Reference is found in languages like C++ and VB, but not JavaScript.
Call By [Object] Sharing
JavaScript's calling conventions can be discussed entirely in terms of Call By [Object] Sharing semantics.
All JavaScript objects are values; and all primitive values (which are a subset of all values) are immutable.
The semantics of call by sharing differ from call by reference in that assignments to function arguments within the function aren't visible to the caller, so e.g. if a variable was passed, it is not possible to simulate an assignment on that variable in the caller's scope. However since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call by value semantics.
An example of these Shared mutations is provided in ultrayoshi's answer and can be explained simply: when an expression (such as a variable access) evaluates to an object, and said object is passed to a function, no copy/clone is made.
Call By Value [of the Reference]
While the terminology "Call By Value [of the Reference]" is often used to describe the behavior, it should be noted that JavaScript does not have "references" (or "non-reference" values) in the sense of Java/C# so this terminology is subtly misleading - at least it's not saying Call By Reference, with it's various connotations, and many people understand a low-explanation.
In call-by-value, the argument expression is evaluated, and the resulting value is bound to the corresponding variable in the function .. If the function or procedure is able to assign values to its parameters, only its local copy is assigned — that is, [any variable] passed into a function call is unchanged in the caller's scope when the function returns.
Because only a "reference" to an object is passed (and not a copy/clone of said object), the semantics are merely that of Call By Sharing. However, I avoid this terminology in JavaScript because then it brings in unnecessary implementation details and also introduces a divide in how implementations pass objects vs primitive values.
The description "call-by-value where the value is a reference" is common (but should not be understood as being call-by-reference); another term is call-by-sharing.
Thus, when I'm talking about calling conventions in JavaScript,
I prefer to use Call By Sharing to discuss the behavior and I avoid Call By [Value/Reference] as they have too many different "meanings" and drag in unnecessary implementation details.
Primitive values like numbers, strings, etc aren't passed by reference, only objects. For example:
var myObj = {
value: "Hello"
};
function change(localObj) {
localObj.value = "Bye";
}
change(myObj);
console.log(myObj.value) // Prompts "Bye"
I have function that returns an object:
function makeObject() {
return {
property: "value"
};
}
I make can new object from it like this:
var newObject = makeObject();
I have some questions about this:
Does newObject reference the original object that was returned by the function, or is it a completely fresh, new object with it's own properties?
If it's a completely new object, is it then, in a sense, a deep copy of the object returned by the function?
What happened to the original object in the function? If it's not possible to reference it, is it being kept alive in the JavaScript runtime?
Yes (a new object is created each time you run the function, but a reference to that new object is returned by the function). You only ever store references to objects in JS variables.
It isn't.
The reference to it inside the function goes away. The reference to it that you returned is still available since you assigned it to a variable. Since there is still an accessible reference to it, it continues to exist.
The MDN documentation on garbage collection is useful related reading.
Here is an equivalent function:
function makeObj() {
var o = new Object();
o.property = 'value';
return o;
}
The object literal syntax is, effectively, a shorthand for the above.
So yes, it's a completely new object, and no, it's not a deep copy, becuase there's nothing to copy. It's manufacturing a new object every time you call the function.
When a variable refers to an object the value is a reference to the object (Referred from: Javascript by reference vs. by value )
function fun1(obj) {
obj.first = 1; //it affects the object ->obj
}
var myObj1 = {first: 0};
fun1(myObj1); //sending the object to the function
console.log(myObj1.first); // 1
But I would like to change the variable from an object, for example
function fun2(obj) {
obj = 1; }
var myObj2 = {first: 0};
fun2(myObj2.first);
console.log(myObj2.first);
Is there any way to achieve this?
Is there any way to achieve this?
Not directly. All you can do is pass an object and have the function modify a property on it, as in your first example. JavaScript does not have pass-by-reference, just pass-by-value. (The value may be an object reference, of course, but it's still a value.) There's no way in JavaScript to directly modify the variable/property you're passing into the function, because what the function receives is a copy of the value of that variable/property, not a reference to that variable/property.
Just to be clear about something: In your first code block, you said you were "sending the object to the function." That's incorrect. You send a reference to the object to the function.
This is the key thing to understand: Variables, properties, and function arguments (collectively, "variables") contain values, and those values are copied when you use assignment or when you pass them into functions. The value that refers to an object is called an object reference, because the value isn't the object, it's a reference to (pointer to) the object elsewhere in memory. The reference is copied when you pass it into a function, the object is not.
Don't confuse the "reference" in "object reference" with the "reference" in "pass-by-reference," they're completely different things. (In pass-by-reference, the reference is to the variable, not an object. JavaScript doesn't have pass-by-reference.)
From what I know, javascript, that is also based on ECMAscript the same as actionscript, does not really pass objects by reference. At least that's what I've read lately. For instance:
function doStuff(myObj){
myObj.name = 'groovy chicken';
myObj = null;
}
var newObj = new Object();
doStuff(newObj);
This is an example I found in a book 'Professional Javascript for web developers'. Although you are passing an object to the function, and adding the name property actually adds the property to your initial object, when you set to null, the object is destroyed in the local scope not in the global scope.
To me, this is still a bit confusing, since the myObj you have, is still pointing the same place as newObj and you can actully add or alter properties. The only difference is that you can not destroy it from the global scope.
So I'm wondering if the same also applies to actionscript, since from what I've read, actionscript 3 does actually pass objects by reference and I've not read anything stating the opposite.
Very few modern programming languages pass by reference (at least by default). In the twisted terminology of "pass by..", you're passing a reference by value. Here's how to think about it:
myObj and newObj are just variables, names for things.
The value of those variables are references to the object
When you call doStuff(), you're binding the name myObj to a new reference to your object (i.e. the reference itself was passed by value)
The reference points to a chunk of memory with some stuff in it, which is what lets you change the name inside of doStuff()
You can see that change by inspecting either variable because both variables contain references to the same object
myObj = null reassigns the variable to nothing, and in the process, it "destroys" the reference, but it doesn't destroy the object.
When the garbage collector notices there are no more references to an object, it will destroy that object
I'll try to help you understand the working of JavaScript's object:
when you say,
var newobj = new Object();
Here, newobj is only a name to the memory location allocated when you created an instance of Object.
When you pass newobj, it takes along the reference to the memory location. Now, myObj in the function is another name to the same memory location.
Adding a method 'name' adds it to the memory location and hence is available to both newobj and myobj.
when you set myobj to null, it removes that named reference and newobj still remains alive with the name property set.
But, I dont have an idea on how this works in actionscript.