Look this code:

<script>
    function dbg (object) {
        var _string = "";

        for (var a in object) {
            _string += a + ":\n";

            for (var b in object[a])
                if (/^get_/.test (b))
                    _string += "\t" + b + " - " + object[a][b] () + "\n";
        }

        return _string;
    }

    function Order () {
        var products = [];

        this.get_products = function () {return products;}

        this.set_products = function (_products) {products = _products;}
    }

    function Product () {
        var id = null;
        var name = null;

        this.get_id = function () {return id;}
        this.get_name = function () {return name;}

        this.set_id = function (_id) {id = _id;}
        this.set_name = function (_name) {name = _name}
    }

    var order = new Order ();
    var product = new Product ();

    product.set_id (1);
    product.set_name ("Banana");

    order.set_products (order.get_products ().concat (product));

    alert (dbg (order.get_products ())); // Ok

    product.set_id (2);
    product.set_name ("Orange");

    order.set_products (order.get_products ().concat (product));

    alert (dbg (order.get_products ())); // Duplicated values! What?
</script>

The first time you push the object "Product" into the object "Order", everything looks fine. When you set new values to the object "Product", the object itself overwrites the previous values of the object "Order". The final result is a array of duplicated values. Is it normal ? Is there a workaround? Just tried everything I knew without success. Thanks.

有帮助吗?

解决方案

Crazy Train has already answered it in the comments. The question is listed having 0 answers so I'll add it as an answer.

When adding a variable containing an object to an array you add a reference to the variable, when you re assign the variable the reference is broken.

Adding a variable containing an object to an array then re assigning the variable doesn't change the object in the array:

var arr=[];
var object={name:"John"};
arr.push(object);
object=33;
console.log(arr);//=[Object {name="john"}]

Adding a variable containing an object to an array then changing the internal values of the object that the variable contains does change the object in the array:

var arr=[];
var object={name:"John"};
arr.push(object);
object.name="Jane";
console.log(arr);//=[Object {name="Jane"}]

So to correct your code you could do the following:

Create a new variable for the product to be added:

var product2=new Product();
product2.set_id (2);
product2.set_name ("Orange");
order.set_products (order.get_products ().concat (product2));

Or break the reference between your product variable and the products array in order:

product=null;//product has no ref to order.products
product=new Product();
product.set_id (2);
product.set_name ("Orange");
order.set_products (order.get_products ().concat (product));

I would not define members of an object in a constructor function with var as JavaScript doesn't support private members. You can simulate them by creating closures but that has it's own problem when you have instance specific privates (as is your case). You can't use prototype if the functions need to access private instance variables, you can't clone it unless you have public accesssors, inheritance and overriding functions will be a pain.

Here is some more info on using constructor functions.

If you have Chrome or Firefox (with Firebug) then you can press F12 to open the console. You an detach the console window (have it's own window) then copy code in the before mentioned answers and paste them in the commandline of the console. There you can run and re run the code, change and see the output to better understand JS behavior.

其他提示

You are just overriding the variables in object. I'd do it like this, much simpler:

var products = {
    set : function(name,id) {
            products.list.push({name:name,id:id});
    },
    get : function(id) {
        var r;
            if(typeof id === 'number'){
                products.list.forEach(function(e,i){ if(e.id==id) r= products.list[i];});
            } else {
                products.list.forEach(function(e,i){ if(e.name==id) r = products.list[i];});

            }
                return r;
    },
    list : []
};

var order={
    set : function(p) {
            order.list[p.id]=p;
    },
    get : function(id) {
            return order.list[id];
    },    
    delete : function(id) {
            return delete order.list[id];
    },
    list : {}
};

then you can do this

products.set('apple',34);
products.set('orange',4);
products.set('mango',1);

var x = products.get(1);
var y = products.get('orange');

order.set(x);
order.set(y);

working demo: http://jsfiddle.net/techsin/tjDVv/2/

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top