Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
296 views
in Technique[技术] by (71.8m points)

javascript - Passing an array to the function multiple times

I'm learning javascript and I'm trying to figure out why my below function doesn't work as expected. See the explanation in the 2 code examples:

// First time I call the shoplist function I pass [1] in the argument. Results are as I expect:

var shopitems = [];

function shoplist(ids) {
    alert("ids passed to shoplist function: " + ids); // 1
    alert("current ids in shopitems var: " + shopitems); // (empty)
    shopitems.push(ids);
    alert("ids in shopitems after pushing: " + shopitems); // 1
    }


// Second time I call the shoplist functions I pass [1, 2] in the argument. Results are not what I would expect:

function shoplist(ids) {
    alert("ids passed to shoplist function: " + ids); // 1, 2
    alert("current ids in shopitems var: " + shopitems); // 1, 2  <--- Why is there 1, 2 and not only 1?
    shopitems.push(ids);
    alert("ids in shopitems after pushing: " + shopitems); // 1, 2, 1, 2

EDIT: Here is the full code (warning: probably very confusing): http://dpaste.org/wXMy5/

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your problem will occur if you are modifying the SAME ids array before calling the second invocation of shoplist(). Because javascript passes arrays by reference and only a reference goes into the shopitems array, when you modify the ids array before passing it to the second invocation of shoplist(), you are also inadvertently modifying shopitems[0] too. If each of your arguments to shoplist() the first and second time you call it are completely separate arrays, you will not have this problem, but if the second invocation is just being passed a modification of the first array, you will have this problem.

The quick illustration is this:

// this will not have the problem because each call to shoplist
// is passing a completely separate array
var list = [1];
shoplist(list);
list = [1,2];      // create new array
shoplist(list);    // shoplist is [[1], [1,2]]

// this will have the problem because they are the same array
var list = [1];
shoplist(list);
list.push(2);     // modify first array
shoplist(list);   // shoplist is [[1,2], [1,2]] and both array elements are actually the same array

For more detailed explanation: .push(ids) adds a whatever the contents of ids as a new items onto the end of the shopitems array. So, each time you call shoplist, you get a new item on the end of shopitems. But, since the item you are adding is an array, it adds a reference to that array, not a copy of that array. If you subsequently change that array, the shopitems array entry will point to the changed version of the array.

You can see that in this code:

var x = [];
var list = [];
x.push(1);       // contains contains [1]
list.push(x);    // list is [[1]]
x.push(2);       // x is [1,2]
list.push(x);    // list is [[1,2], [1,2]]  (contains two references to x)

In this code example, list will contain two elements and each will point to the same live version of x which contains [1,2].

This is because by default, javascript passes references for things like arrays and objects. When you push an array element into your container array, it is not putting a static copy of that variable into the array. It's putting a pointer to the original variable. If you then change the original variable, that change is reflected in the array too.

To separate the second entry from the first, you either need to consciously make a copy of the first array and push that copy into the container array or you need to create a new array from scratch and push it into the container array.

For example, here are a couple ways to create two independent elements in the container array:

var x = [];
var list = [];
x.push(1);       // contains contains [1]
list.push(x);    // list is [[1]]
x = [];          // set x to a new array (the old version of x is still in list)
x.push(1);       // x is [1]
x.push(2);       // x is [1,2]
list.push(x);    // list is [[1], [1,2]]  (contains two separate items)

Or, make a copy of x:

var x = [];
var list = [];
x.push(1);       // contains contains [1]
list.push(x);    // list is [[1]]
x = x.slice(0);  // make a copy of x, the old version of x is still in list
x.push(1);       // x is [1]
x.push(2);       // x is [1,2]
list.push(x);    // list is [[1], [1,2]]  (contains two separate items)

The important thing to remember here is that in javascript, object assignment or array assignment does not make a copy. It just assigns a pointer to the original data structure. If you change the original data structure, that will be reflected in any assignments you've made.

If you a copy, you have to either explicitly make a new array or explicitly make a copy.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...