/    Sign up×
Community /Pin to ProfileBookmark

Array is not local scope inside function?

I’ve noticed a JavaScript behavior that does not agree with my understanding of variable scope and was hoping that someone could clarify:

[CODE]function change(arr)
{
var tmp1 = arr[0];
var tmp2 = arr[1];
arr[0] = arr[2];
arr[1] = tmp1;
arr[2] = tmp2;
}

var arr = [‘cat’, ‘dog’, ‘parrot’];

change(arr);

alert(arr.join(‘,’)); //results in “parrot, dog, cat”[/CODE]

In the above code, the function accepts an array, puts the third item at the beginning, and moves the other two to the right. If you’ll notice, however, the function does [I]not[/I] return the newly sorted array. It simply operates on the array it was given, which in my understanding should be an entirely independent array with scope that is [I]local[/I] to the function and ceasing to exist when the function stops executing.

So how come the resulting alert is “parrot, dog, cat?” Even though the function operated only on the array it was given, it affected the original array.

Note that in this example the original array is [I]not[/I] changed:

[CODE]function change(arr)
{
arr = [‘monkey’, ‘mouse’, ‘ferret’];
}

var arr = [‘cat’, ‘dog’, ‘parrot’];

change(arr);

alert(arr.join(‘,’)); //This time, alert is “cat, dog, parrot.”[/CODE]

to post a comment
JavaScript

9 Comments(s)

Copy linkTweet thisAlerts:
@jamesbcox1980Oct 30.2009 — I wonder if it has something to do with ambiguous names? I'll check it out.
Copy linkTweet thisAlerts:
@jamesbcox1980Oct 30.2009 — Yes, this is an ambiguous name conflict. If you remove the argument from the function and just use change() the function will work properly. When you "var arr" you are creating a global variable, but when you change the variable "arr" inside the function "change", you are only changing it in the local scope.

If you were to "return arr.join(',')" and do "alert(change(arr))" instead, you will see the proper behavior. Alternatively, you could put "var" in front of "arr" within he "change" function to return it to global scope.

You might want to spend some time looking at global and local variable scopes. Also, you might want to look at how you're constructing functions, in this respect.
Copy linkTweet thisAlerts:
@jamesbcox1980Oct 30.2009 — [CODE]<script type="text/javascript">
function change()
{
arr = ['monkey', 'mouse', 'ferret'];
}

var arr = ['cat', 'dog', 'parrot'];

change(arr);

alert(arr.join(',')); //This time, alert is "cat, dog, parrot."
</script>[/CODE]
Copy linkTweet thisAlerts:
@tarsusauthorOct 30.2009 — I don't think I've explained myself well enough. I'm not asking how to make the function affect the global variable.

It's not that I [I]do[/I] want the global variable to be changed. It's that it [I]is[/I] being changed, when it seems like it shouldn't.

When you "var arr" you are creating a global variable, but when you change the variable "arr" inside the function "change", you are only changing it in the local scope.[/QUOTE]

That's what I intend to do. But that doesn't seem to be what's happening. The global variable is being changed.

If you were to "return arr.join(',')" and do "alert(change(arr))" instead, you will see the proper behavior.[/QUOTE]

This is precisely what I would expect I'd have to do. But, again, the function as it is is having the same result as if I had used a return value exactly as you say.

As for your fixed version of the second function: I know how to change a global variable within a function if I please. The one I included was simply to demonstrate that the global variable is [I]not[/I] changed, even though the function is similar to the other.

Somehow I'm feeling like I've been even more confusing that the first time. Here's my question restated: I [I]want[/I] the function to alter the local variable, leaving the global variable unchanged. But that's not what's happening. Why?
Copy linkTweet thisAlerts:
@jamesbcox1980Oct 30.2009 — It's one in the same problem. In the first example you're not setting a new version of "arr" so you're effectively not creating a local variable.
Copy linkTweet thisAlerts:
@tarsusauthorOct 30.2009 — Uh . . . arguments passed to a function [I]are[/I] local in scope. If I declared a new variable "arr" with the "var" keyword, I would not be using the argument that was passed; I would be overwriting it!

Observe:

[CODE]function changeNumber(x)
{
x = (x + 1 - 5) * 12;
}
var x = 6;
changeNumber(x);
alert(x); //result is 6[/CODE]


I can change the value of x inside the function all I want; the global x is always going to be 6. No "var" keyword in the function is involved to make it local scope.

With that said, I did a little checking elsewhere. [I]Objects[/I] passed to a function are passed by reference, not by value. That, I knew. I suppose arrays must be treated like objects in this context. (As, indeed, they actually are objects in JavaScript.) Not sure why I'd never run into unexpected results with this before, but I'll definitely keep it in mind for the future.
Copy linkTweet thisAlerts:
@jamesbcox1980Oct 30.2009 — If you know so much about the scope of variables, then why'd you even ask? There's no need to be so abrasive about it.

When you pass a function to a variable, you're not creating a local variable, you're creating an argument. When you create ambiguous variable names and arguments, the variable is called first in the hierarchy.

When you set x = (x + 1 - 5) * 12, you're creating a local variable that overrides the argument. So, you won't affect x. Also, when you pass variables to a function, it's not actually being passed. The value of x is set to the value of the argument, which in this case is named "x". It's not an issue of referral, it's an ambiguous name.

If you used this instead, you would get a different result:[CODE]function change(y)
{
x = (y + 1 - 5) * 12;
}
var x = 6;
change(x);
alert(x);[/CODE]


You're just not getting that you're constructing the function wrong. Ambiguous names are, by definition, an error in constructing functions. It may or may not be doing what you want it to do, but it's not built correctly. The above code shows the correct behavior.
Copy linkTweet thisAlerts:
@tarsusauthorOct 30.2009 — I'm sorry if I came across as abrasive; it was not intentional.

I've already found my answer in my investigating, but in case it is of help to anyone following the thread, I'll try to clarify where we're miscommunicating.

Here's an example that should, hopefully, illustrate why ambiguous names are not the problem (I say "problem," but I was never trying to imply that JavaScript was doing it wrong, just that I didn't understand why it worked the way it did):

[CODE]function change(arr)
{
arr[0] = 'new';
}
var myArray = ['old1', 'old2'];
change(myArray);
alert(myArray.join(',')); //results in "new, old2"[/CODE]


As you can see, I am now no longer using the same name for my argument as I do for the global variable. You can also see that nowhere in the function is "myArray" being operated on. Yet the global variable "myArray" is still changed.

So it turns out that this is because, unlike simple data types like numbers and strings, arrays pass a reference to the original variable rather than the value itself.
Copy linkTweet thisAlerts:
@rnd_meOct 30.2009 — if you want to act on a new copy of the array instead, you can clone it with .concat() to break the "byRef" behavior of objects:

[CODE]function change(arr){
arr=[COLOR="Red"]arr.concat();[/COLOR]
var tmp1 = arr[0];
var tmp2 = arr[1];
arr[0] = arr[2];
arr[1] = tmp1;
arr[2] = tmp2;
[COLOR="Red"]return arr;[/COLOR]
}

[/CODE]
×

Success!

Help @tarsus spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.18,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @AriseFacilitySolutions09,
tipped: article
amount: 1000 SATS,

tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,
)...