[英]What is the weird behavior of native objects caused by?
最近我開始學習JavaScript中的面向對象編程。 我所理解的是,在引用變量時,我們實際上並未引用它們的實際值,而是引用內存中的位置。 這就是為什么那些應該復制實例的“ 返回此 ”方法不起作用的原因。
那么,示例代碼:
//An example object with a simple property and
//failing "copy" function.
function MyObject()
{
this.myProperty = 123;
this.copy = function() { return this; };
}
var iOne = new MyObject();
var iTwo = iOne.copy();
iTwo.myProperty = 321;
現在iOne和iTwo的“myProperty”屬性等於321,因為“copy”方法返回了一個引用,而不是一個值。 這種行為是預期的,一切都很好。
現在,我嘗試使用本機對象類型Number進行相同操作。 讓我們以更加面向對象的程序員友好的方式創建它的實例:
var iOne = new Number(123);
var iTwo = iOne; //Equals "iTwo = iOne.copy()", except there isn't a copy method
iOne = 321;
現在,發生了一件可怕的事情。 iOne等於321,但iTwo保持其值,仍然等於123。
我不知道這是由什么造成的。 也許Number是某種“特殊”? 也許與之相關的十進制數不僅僅是一個屬性? 或者也許它應該讓沒有經驗的程序員的生活變得更容易? 最后一個選項與運營商有關。 如果有人對此有所了解,請不要讓我理解JavaScript的方式崩潰。
對象,數組和字符串通過引用(而不是通過副本)分配。 所有其他類型在分配時都是有效的副本(例如,它們創建一個與舊的無關的新變量)。
字符串是一種特殊情況,因為它們是不可變的,因此當您更改字符串時,它總是創建一個新字符串,因此即使前一個賦值是引用,它的行為也更像是復制它。
分配:
iOne = 321;
用簡單的原始數字類型替換iOne的值,因此它對任何其他變量都沒有影響。
var iOne = new Number(123);
var iTwo = iOne; //Equals "iTwo = iOne.copy()", except there isn't a copy method
iOne = 321;
您將覆蓋iOne
變量持有的對象引用,並使用不同的原始數字。
對象作為引用保留,但它們不是可以直接解除引用的指針,因此您無法替換該內存位置中保存的數據。 你只能改變它(如果對象是可變的) 。
具體來說, Number
對象包裝器不可變,或者至少它所擁有的原始值不能被替換。 您只能替換整個對象。
iOne = 321;
此代碼執行了預期的操作,您為變量iOne
分配了321
,覆蓋了它最初引用的內容。
Javascript中的“本機類型”和對象之間的行為沒有真正的區別(除了本機類型是不可變的)。
在你的第二個例子中,你只是簡單地改變iOne
指向的變量,為什么要改變另一個獨立的iTwo
變量所指向的?
在第一種情況下,你有兩個指向同一個對象的變量,如果你使用一個變量來改變對象,你也可以使用另一個變量來觀察變化(顯而易見......它指向同一個對象)。
在Javascript中,您可以想象一切都始終通過引用而從不通過值(復制)。 如果你想要復制一些東西你需要明確地...對於數組你可以使用x.slice()
來制作x
的淺表副本; 對於對象,沒有用於執行相同操作的原始函數,因此您必須調用構造函數。
一個常見的OOP模式是擁有一個成員函數.clone()
,它返回一個副本,因此需要副本的人不需要知道如何制作每個類的副本。
function P2d(x, y) {
this.x = x;
this.y = y;
}
P2d.prototype.clone = function() {
return new P2d(this.x, this.y);
}
另一種特定於Javascript的原型模型的可能性在某些情況下可能很有用,就是創建一個單獨的對象,它看起來像一個淺拷貝,可以在不影響原始的情況下進行變異,而是在讀取時引用原始對象:
function fakeCopy(x) {
function f() { }
f.prototype = x;
return new f;
}
p = new P2d(10, 20);
q = fakeCopy(p);
console.log(q.x); // Displays 10
q.y = 30;
console.log(q.y); // Displays 30
console.log(p.y); // Displays 20 -- original not changed
p.x = 99;
console.log(q.x); // Displays 99 (!)
發生這種情況是因為Javascript對象具有在訪問成員進行讀取時搜索的“原型鏈”。 q
被創建為一個空對象,以p
為原型,因此在查找屬性(用於讀取)時,如果在q
內找不到某些內容,它將在p
內搜索。 然而,在寫入時,將在q
內部設置屬性,不影響p
並且將返回q
存在的值的那一點,而不是必須在原型鏈中上升。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.