[英]Unexpected behavior using getters and setters
看看這段代碼:
<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”時,一切看起來都很好。 當您為對象“Product”設置新值時,對象本身會覆蓋對象“Order”的先前值。 最終結果是一系列重復值。 這是正常的嗎? 有解決方法嗎? 剛嘗試了我所知道的一切都沒有成功 謝謝。
Crazy Train已經在評論中回答了這個問題。 列出的問題有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));
或者按順序打破產品變量和products數組之間的引用:
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));
我不會在構造函數中使用var
定義對象的成員,因為JavaScript不支持私有成員。 您可以通過創建閉包來模擬它們,但是當您具有特定於實例的私有時(例如您的情況),它會有自己的問題。 如果函數需要訪問私有實例變量,則無法使用原型,除非有公共訪問器,否則無法克隆它,繼承和覆蓋函數將是一件痛苦的事。
以下是有關使用構造函數的更多信息。
如果您有Chrome或Firefox(使用Firebug),則可以按F12打開控制台。 您可以分離控制台窗口(擁有自己的窗口),然后在前面提到的答案中復制代碼並將其粘貼到控制台的命令行中。 在那里,您可以運行並重新運行代碼,更改並查看輸出以更好地理解JS行為。
您只是覆蓋對象中的變量。 我這樣做,更簡單:
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/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.