簡體   English   中英

javascript的Set和常規普通對象之間有什么區別?

[英]What are the differences between javascript's Set and a regular plain object?

在嘗試解決此問題時 ,我了解了javascript的Set對象的存在。 然后,我檢查了MDN的Set文檔 ,然后立即彈出我在這里提出的問題。

這場辯論始於上述問題的答案評論。 我發現線索也有助於辯論。

到目前為止,我本人可以從辯論中得出的結論是:

  • Set在其API中提供了“清除”方法,這是一項很好的功能

  • Set確保添加的元素的順序得以保留。 普通對象沒有。

任何人都可以提供明確的結論嗎? 也許我不應該將兩者進行比較...但是我仍然認為這是一個合理的問題,其他人很可能在了解Set后會問同樣的問題。

無論如何,最初促使我問這個問題的是編輯 MDN的Set規范,並添加從此處獲得的結論。 但是在這里開發完線程之后,我認為我不應該這樣做,也許Set的規范實際上不應提及“最終提供相似功能的普通對象該如何處理”。 至少有人問自己這個問題,仍然可以在SO中找到它,並享受這里添加的見解/貢獻。

首先, 這是一篇包含代碼的文章 ,該文章顯示了如何開始將純Javascript對象用於類似集合的行為(有一些限制)。

並且,這是一組對象 (在ES5中可用),用於獲得更多類似集合的行為。

並且,這里是ES5中實現的Set對象的部分ES6 polyfill

如果學習這些代碼,您會發現普通的Javascript對象在很多方面都遠不及ES6集,而這需要大量額外的代碼來解決。


這里有幾個問題:

  1. 將對象分配為鍵將無法正常工作,因為所有對象都將轉換為字符串"[object Object]"因此所有對象在類似集合的Javascript對象中都具有相同的鍵。

  2. 將數字分配為鍵將轉換為字符串表示形式,因此鍵4"4"將發生沖突。

ES6 Set對象沒有這些限制。 這是關於這兩個問題的更多討論:

如果您看一下先前文章的答案以及該答案中的代碼 ,則可以看到如何將底層Javascript對象用作類似集合的行為的查找機制。 盡管沒有很多其他編碼,但是它有一些局限性,因為Javascript對象需要使用字符串作為查找鍵。 ES6集沒有 因此,開箱即用的ES6集支持將對象作為元素。 將Javascript對象用作窮人的集合不支持將對象作為集合中的元素。

當您要將對象添加到基於Javascript的普通對象集中時,這變得最重要。

// create a set-like object
var mySet = {};

// create an object and put it in the set
var myObj = {greeting: "hello"};
mySet[myObj] = true;

因為Javascript對象需要一個字符串鍵,所以它將調用myObj.toString()來獲得這樣的鍵。 如果沒有toString()方法的自定義覆蓋,它將以“ [object Object]”的形式出現,這根本不是您想要的。 請參閱此處的演示。 它似乎適用於一個對象,但是一旦集合中有多個對象或為另一個對象設置了集合,則它將根本不起作用,因為所有對象都將使用相同的鍵進行索引。

另一方面,有了一個實際的ES6集,它就可以自然地接受並與對象一起工作-您不必做任何特殊的事情。

如果您想了解如何使用普通Javascript對象作為查找機制來盡可能接近地模擬ES6集,請閱讀此答案 更多信息位於github上 ,您可以其中看到要使常規的基於Javascript對象的集實現支持此ObjectSet實現的 Java對象的操作。 這里甚至還有一個ES6 Set polyfill 它使用底層Javacript對象作為其存儲機制。


第二個問題是基於Javascript對象的集合實現,這也是由於字符串鍵的要求。 如果您這樣做:

var mySet = {};
mySet[4] = true;
mySet["4"] = true;

您將最終只得到其中一個項目。 這是因為mySet[4] = true; 4轉換為字符串"4"以用作鍵。 如果您僅在集合中使用字符串或僅在集合中使用數字,則可以輕松解決此問題,但是如果集合中同時包含字符串和數字,則javascript對象庫集合實現無法區分4"4"因此不會將它們視為集合中的單獨項目。 ES6確實做到了這一點。

同樣,有可能使用更多代碼來解決此問題。 如果您手動進行toString()轉換以創建密鑰,則可以在密鑰值前添加一些類型信息,以便在上面的示例中,數字4的密鑰變為"num_4"而不僅僅是“ 4”。 為了防止與字符串““ num_4”`發生沖突,您還必須對字符串類型執行相同的操作。 而數字並不是這個問題的唯一類型。 實際上,在此ES6 Set polyfill中,您可以在此處看到正在生成的唯一密鑰。 然后,必須重新生成該唯一密鑰,並將其用於集合中的任何查找。

集不重復,看到這個小提琴

var mySet = new Set();

mySet.add(1);
mySet.add(5);
mySet.add("some text");


console.log('after adding duplicate  values ')
console.log('size='+mySet.size ) // size is 3


mySet.add("some text"); // adding duplicate value
console.log('after adding duplucate  value ')
console.log('size='+mySet.size ) // size is still 3

集合實例是對象。 如果構造一個Set,則可以自由地向其添加屬性,就像Date或Array的實例一樣:

var s = new Set();
s.name = "Herman";
s.shoeSize = 12;
console.dir(s); // just like an Object!
s.add(17);
if (s.has(17)) alert("yup!"); // yup!
if (17 in s) alert("yup!"); // no alert here!

Set原型公開的行為提供的功能實際上與對象的性質無關,除了對對象的引用屬於可以與該API一起使用的各種值。 通過該API在集合中添加或刪除值對集合對象的普通屬性沒有影響。

如果希望只使用ES5工具來實現Set工具之類的工具,則您必須執行一些操作,例如維護值數組或按值類型排列一組數組。 .add().has()等方法可能必須通過搜索在該值列表上強加集合成員資格的規則。 可能可以進行一些優化以提高搜索效率,但是ES6運行時具有優勢,最顯着的是運行時內部可以訪問原始對象引用值和其他類似內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM