【问题标题】:Unexpected behavior using getters and setters使用 getter 和 setter 的意外行为
【发布时间】:2013-08-24 23:32:47
【问题描述】:

看这段代码:

<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>

第一次将对象“产品”推入对象“订单”时,一切看起来都很好。 当您为对象“Product”设置新值时,对象本身会覆盖对象“Order”的先前值。最终结果是一个重复值的数组。正常吗?有解决方法吗?只是尝试了我所知道的一切,但没有成功。谢谢。

【问题讨论】:

  • 好吧,你正在重用同一个对象。对象永远不会被复制。您实际上并没有对象本身,而是对它的引用。所以你要添加对数组的引用,然后通过引用更新对象,然后再次添加它。

标签: javascript setter getter overwrite


【解决方案1】:

Crazy Train 已经在 cmets 中回答了这个问题。列出的问题有 0 个答案,因此我将其添加为答案。

将包含对象的变量添加到数组时,您会添加对变量的引用,当您重新分配变量时,引用会被破坏。

将包含对象的变量添加到数组然后重新分配变量不会更改数组中的对象:

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

将包含对象的变量添加到数组中,然后更改该变量包含的对象的内部值确实会更改数组中的对象:

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

因此,要更正您的代码,您可以执行以下操作:

为要添加的产品创建一个新变量:

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

或者按顺序断开您的产品变量和产品数组之间的引用:

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));

我不会定义members of an object in a constructor function with var,因为 JavaScript 不支持私有成员。您可以通过创建闭包来模拟它们,但是当您有特定于实例的私有(如您的情况)时,这有它自己的问题。如果函数需要访问私有实例变量,则不能使用原型,除非您有公共访问器,否则无法克隆它,继承和覆盖函数将很痛苦。

Here 是有关使用构造函数的更多信息。

如果您有 Chrome 或 Firefox(带有 Firebug),那么您可以按 F12 打开控制台。您分离控制台窗口(拥有它自己的窗口),然后在前面提到的答案中复制代码并将它们粘贴到控制台的命令行中。在那里您可以运行并重新运行代码,更改并查看输出以更好地了解 JS 行为。

【讨论】:

    【解决方案2】:

    您只是覆盖了对象中的变量。我会这样做,更简单:

    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 : {}
    };
    

    那么你可以这样做

    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);
    

    工作演示: http://jsfiddle.net/techsin/tjDVv/2/

    【讨论】:

      猜你喜欢
      • 2019-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-26
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多