(譯) js中的值相等和引用相等

飛翔的大象發表於2019-03-08
  • 此為翻譯文章

在程式語言世界中通常有兩種型別的相等:

  • reference equality
  • value equality

#引入

思考下面的程式碼:

var x = 12,
    y = 12;

var object = { x: 1, y: 2 };
var object2 = { x: 1, y: 2 };
複製程式碼

正如你看到的,objectobject2有相同的值。如果你看一下objectobject2中的每個鍵以及它們對應的值,它們是相同的。在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(深比較)。 更糟糕的是,這個演算法是不會完成的。這是因為你可能建立了迴圈的引用物件

相關文章