1

Experiencing a weird Javascript bug it'd be great to get some insight to. I've managed to debug it to know what the issue is, I just haven't been able to figure out the why yet and a non-hackey way to resolve it.

I'm trying to create a new instance of an array as a variable inside a function, so I can manipulate it without affecting the main array. Instead I'm getting some kind of reference, so doing operations on my new variable ids also affects the array that ids equals.

I've simplified my code to demonstrate the issue more clearly:

var defence = {

    selectedIDs: new Array(),

    toggleTerm: function(term, id) {

        // add to the main array
        this.selectedIDs.push(5);

        // adds to this.selectedIDs
        this.showTweet();

    },

    showTweet: function() {

        // copy the array as a new variable in the scope of the function
        var ids = this.selectedIDs;

        if (ids.length == 1) {
            ids.push(10); // this pushes to 'ids' AND 'this.selectedIDs'
        }
        console.log(this.selectedIDs); // outputs [5, 10]

    }

}

Also in JSFiddle

It's always been my understand that var ids = this.selectedIDs would effectively copy the contents of this.selectedIDs into that new instance - however this doesn't seem to be the case.

Any ideas on why this is happening, and the best way to get around it (beyond manually recreating it through something like a for loop)?

2 Answers 2

2

It's always been my understand that var ids = this.selectedIDs would effectively copy the contents

OK, but your understanding is wrong. It's an assignment.

Consider this instead:

var ids = this.selectedIDs.slice()
Sign up to request clarification or add additional context in comments.

3 Comments

Note that JS has a lot of array-like things that don't necessarily have the full Array API. E.g. you can't call slice() on the arguments object. You have to do something like Array.prototype.slice.call(arguments).
Good point, @broofa -- the most noticeable (to me) example: arguments
NodeLists as well (e.g. returned by document.getElementsByClassName())
0

It's always been my understand that var ids = this.selectedIDs would effectively copy the contents of this.selectedIDs into that new instance - however this doesn't seem to be the case.

I don’t know how to describe this except “no, that doesn’t happen at all”. JavaScript isn’t C++; when you assign something to a variable, it is never copied. You always get a reference, except in the case of primitives, which are immutable, making the point moot. (Heh.)

You could use concat, but if this isn’t the actual situation, there might be something more appropriate.

showTweet: function() {
    var ids = this.selectedIDs;

    if (ids.length === 1) {
        ids = ids.concat(10); // Array.prototype.concat returns a new array
    }

    console.log(this.selectedIDs); // outputs [5]
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.