- 此為翻譯文章
在程式語言世界中通常有兩種型別的相等:
- reference equality
- value equality
#引入
思考下面的程式碼:
var x = 12,
y = 12;
var object = { x: 1, y: 2 };
var object2 = { x: 1, y: 2 };
複製程式碼
正如你看到的,object
和object2
有相同的值。如果你看一下object
和object2
中的每個鍵以及它們對應的值,它們是相同的。在object和object2中,x
的值是1,y
的值是2。
但是當你想要在你的程式中檢查object和object2是否相等,你會發現:這兩個物件是不一樣的。
object == object2 // false
object === object2 // false
複製程式碼
這是為什麼呢?
#reference equality
Objects是灰常複雜的資料結構。它們可以有很多key,這些key可以執行不同的值。這些值也可以是objects,所以objects是可以巢狀的。
如果你考慮事物的相等行,事實上你需要考慮兩件事情:
- 一個事物是否意味著與另一個事物相同?
- 一個事物與其它東西完全一樣?
如果我從現實世界中舉一個例子:想象一下你有一個紅色的跑車,你的鄰居也有和你的車一樣的車,相同的顏色,相同的發動機,相同的牌子。如果陌生人經過你的家,他們會說:嘿,這些人有相同的車。
但是,你鄰居的車不是你的。你不會坐上鄰居車,認為這是你的,對吧,或者至少你不應該。如果你撞壞了鄰居的車,你可能會有一個不快樂的鄰居,當然還有一些法律問題:)
區分你的車和鄰居的車的最明顯的地方是車牌。
事實上, JavaScript objects的內建了這種“牌照”,每個object的獨特特性稱為reference
(引用)。
當你在js中比較object時,它們通過reference比較
object == object2;
object === object2;
複製程式碼
問題:object和object2是相等嗎?實際上你分配變數的時候,也分配了reference。 你可以很容易的檢查這個:
object = object2;
object == object2; // true
object === object2; // true
複製程式碼
也會有一些有趣的結果,程式碼如下:
object = object2;
object.x = 12;
object.x; // 12
object2.x; // 12
複製程式碼
在這個例子中,你做了一次將x
這個key分配給object這個物件。object和object2指向相同的引用,所以只要一個變數更改,另一個變數也會更改。
JavaScript中的複雜的資料結構都遵循reference equality
的原則,這包括arrays和objetcs,實際上通過typeof檢視array的型別,得到的結果也是object。
還有一些值像:numbers, strings, booleans or null / undefined,它們都遵循一種相等:value equality。
#value equality
像前面說的,reference equality回答的是object1和object2是否一樣?這種檢查很簡單,它們非常有效。
說到Javascript中的primitives(這個我也不知道怎麼翻譯18.12.21更新:上面的primitives指的是Primitive types(基本型別), 指的是上面的numbers等),它們是不可以巢狀的。這種不能巢狀其它結構的結構稱為shallow data structures(淺資料結構)。在這樣的結構中,你可以以有效的方式執行value equality。
但是什麼是value equality?思考下面的程式碼:
var x = 12,
y = 12;
複製程式碼
在相等方面,數字是最簡單的。你可以清楚的說x變數的值等於y變數的值(12在數學中等於12)但是如果這些變數遵循reference equality,它們是不一樣的,因為它們是在不同的地方建立的。所以它們的引用是不同的。x的12可能是和y的12是不一樣的。這真是太亂了。
幸運的是,members在JavaScript中是primitives,primitives在javascri中使用的是value equality進行比較。 所以看到這是不奇怪的:
x == y; // true
x === y; // true
複製程式碼
value equality回答的是這個疑問:一個事物是否意味著與另一個事物相同?
巢狀的資料結構是的相等更加難以比較。Objects有任意的key和value,它可以包含其他的objects。為了比較兩個objects的相等,你可能需要下面的演算法:
/ Input: an object1 and object2
// Output: true if an object1 is equal in terms of values to object2
valueEqual(object1, object2):
object1keys = <list of keys of object1>
object2keys = <list of keys of object2>
return false if length(object1keys) != length(object2keys)
for each key in object1keys:
return false if key not in object2keys
return false if typeof(object1[key]) != typeof(object2[key])
if object1[key] is an object:
keyEqual = valueEqual(object1[key], object2[key])
return false if keyEqual != false
if object1[key] is a primitive:
return false if object1[key] != object2[key]
return true
複製程式碼
呼,這裡面有好多相等檢查,這是一個遞迴演算法。它在比較兩個object是會執行上千次相等檢查,這樣的相等檢查通常被稱作 deep equality checks(深比較)。 更糟糕的是,這個演算法是不會完成的。這是因為你可能建立了迴圈的引用物件。