JavaScript 集合對象

1. 集合對象

1.1 Object

關於Object類型的建立和底層存儲原理我在另外一篇文章有說明: JavaScript 對象屬性底層原理javascript

咱們知道了大多數狀況下Object底層都是Hash結構,咱們再看看V8中從Object派生的繼承圖html

1.2 Array

數組是一種類列表對象,能夠存儲重複的對象,只能用整數做爲數組元素的索引。
在V8中數組繼承於Object,數據結構依然是Hash表。java

//An instance of the built-in array constructor (ECMA-262, 15.4.2).
//Definition at line 3562 of file v8.h
 class V8_EXPORT Array : public Object {
   public:
   uint32_t Length() const;
   /**
    * Creates a JavaScript array with the given length. If the length
    * is negative the returned array will have length 0.
    */
   static Local<Array> New(Isolate* isolate, int length = 0);
 
   V8_INLINE static Array* Cast(Value* obj);
  private:
   Array();
   static void CheckCast(Value* obj);
 };

1.3 Map

Map對象保存鍵值對,Key能夠是任何值(對象或原始值),Value也能夠是任何值。node

  • Key的比較是基於 "SameValueZero" 算法:NaN 是與 NaN 相等的(雖然 NaN !== NaN),剩下全部其它的值是根據 === 運算符的結果判斷是否相等。

根據ECMA6-262的定義c++

Map object must be implemented using either hash tables or other mechanisms that, on average, provide access times
that are sublinear on the number of elements in the collection.
Map能夠是hash表結構或相等訪問時間的結構.算法

根據如下定義,在V8中Map繼承於Object,數據結構依然是Hash表。數組

//An instance of the built-in Map constructor (ECMA-262, 6th Edition, 23.1.1).
 class V8_EXPORT Map : public Object {
  public:
   size_t Size() const;
   void Clear();
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,Local<Value> key);
   V8_WARN_UNUSED_RESULT MaybeLocal<Map> Set(Local<Context> context,Local<Value> key,Local<Value> value);
   V8_WARN_UNUSED_RESULT Maybe<bool> Has(Local<Context> context,Local<Value> key);
   V8_WARN_UNUSED_RESULT Maybe<bool> Delete(Local<Context> context,Local<Value> key);
 
   /**
    * Returns an array of length Size() * 2, where index N is the Nth key and
    * index N + 1 is the Nth value.
    */
   Local<Array> AsArray() const;
 
   /**
    * Creates a new empty Map.
    */
   static Local<Map> New(Isolate* isolate);
 
   V8_INLINE static Map* Cast(Value* obj);
 
  private:
   Map();
   static void CheckCast(Value* obj);
 };

Object VS Map

1. 相同

都容許你按鍵存取一個值、刪除鍵、檢測一個鍵是否綁定了值數據結構

2. 不一樣

  • Object的鍵只能是字符串或者Symbols. Map的鍵能夠是任意值,包括函數、對象、基本類型。
  • Map中的鍵值是有序的, 而Object中的鍵則不是。當遍歷時,Map對象是按插入的順序返回鍵值。
  • Map能夠經過size屬性獲取鍵值對個數, Object則不行。
    注: ES5中的Object.keys()能夠返回普通對象的全部屬性,可是若是是方法對象,定義在原型鏈上的屬性沒法經過該方法獲取
  • Map內置有Iterator能夠直接迭代,而Object的迭代須要先獲取它的鍵的數組,而後再進行迭代。
  • Map在涉及頻繁增刪鍵值對的場景下會相對Object性能較好。

1.4 Set

Set對象容許你存儲任何類型的惟一值,不管是原始值或者是對象引用。ide

根據ECMA6-262的定義函數

Set objects must be implemented using either hash tables or other mechanisms that, on average, provide access times
that are sublinear on the number of elements in the collection.
Distinct values are discriminated using the SameValueZero comparison algorithm.

  • Set能夠是hash表結構或相等訪問時間的結構
  • Key的比較是基於 "SameValueZero" 算法

根據如下定義,在V8中Set繼承於Object,數據結構依然是Hash表。

//An instance of the built-in Set constructor (ECMA-262, 6th Edition, 23.2.1).
class V8_EXPORT Set : public Object {
  public:
   size_t Size() const;
   void Clear();
   V8_WARN_UNUSED_RESULT MaybeLocal<Set> Add(Local<Context> context,Local<Value> key);
   V8_WARN_UNUSED_RESULT Maybe<bool> Has(Local<Context> context,Local<Value> key);
   V8_WARN_UNUSED_RESULT Maybe<bool> Delete(Local<Context> context,Local<Value> key);
 
   /**
    * Returns an array of the keys in this Set.
    */
   Local<Array> AsArray() const;
 
   /**
    * Creates a new empty Set.
    */
   static Local<Set> New(Isolate* isolate);
 
   V8_INLINE static Set* Cast(Value* obj);
 
  private:
   Set();
   static void CheckCast(Value* obj);
 };

1.5 WeakMap

WeakMap 對象是一組鍵/值對的集合,其中的鍵是弱引用的。其鍵必須是對象,而值能夠是任意的。
與Map相比區別:

  1. Map內部有兩個數組(一個存放鍵,一個存放值), 給map 設置值時會同時將鍵和值添加到這兩個數組的末尾。從而使得鍵和值的索引在兩個數組中相對應,所以賦值和搜索操做都是 O(n) 的時間複雜度。
  2. 由於數組會一直引用着每一個鍵和值,這種引用使得垃圾回收算法不能回收處理他們,即便沒有其餘任何引用存在了。
  3. WeakMap 持有的是每一個鍵或值對象的「弱引用」,這意味着在沒有其餘引用存在時垃圾回收能正確進行。正因爲這樣的弱引用,WeakMap 的 key 是不可枚舉的 (沒有方法能給出全部的 key)。

1.6 WeakSet

它和 Set 對象的區別有兩點:

  1. WeakSet對象中只能存放對象引用, 不能存放值, 而 Set 對象均可以.
  2. WeakSet對象中存儲的對象值都是被弱引用的, 若是沒有其餘的變量或屬性引用這個對象值, 則這個對象值會被當成垃圾回收掉. 正由於這樣, WeakSet 對象是沒法被枚舉的, 沒有辦法拿到它包含的全部元素.

2. 集合對象的遍歷

2.1 For In

遍歷對象的可枚舉(enumerable爲true,非Symbol)屬性,以及對象從其構造函數原型中繼承的屬性。
原理:首先枚舉當前對象的enumerable爲true的全部屬性,而後枚舉從原型鏈中構造函數原型中繼承的屬性(更接近原型鏈中對象的屬性覆蓋原型屬性)。
ES 5標準,設計目的用於遍歷key
注:使用for in循環數組會有以下缺陷

  • 索引是字符串型的數字,於是不能直接進行幾何運算
  • 遍歷順序可能不是實際的內部順序
  • 會遍歷數組全部的可枚舉屬性,包括原型。例如的原型方法method和name屬性
//函數和實例的遍歷
function F0(){
  this.a = "1";
}
F0.b = "2";
for(var k in F0){
  console.log(k);//b
}
var fi0=new F0();
for(var k in fi0){
  console.log(k);//a
}

//函數繼承的遍歷
function F1(){
  this.a = "a";  
  this.c = "F1";
}
function F2(){
  this.b = "b";
  this.c = "F2"
}
F2.prototype=new F1();
var fi2 = new F2();
for(var k in fi2){
  console.log(k+":"+fi2[k]);//b:b,c:F2,a:a
}

//數組遍歷
var ar1 = [1,2,3];
ar1.a = "a";
for(var k in ar1){
  console.log(k);//0,1,2,a
}

2.2 For of

檢查對象是否具備Symbol.iterator屬性,若是存在,就調用該屬性返回的遍歷器方法。以上的集合都已經內置了該屬性,全部可使用For of遍歷。
ES 6標準,遍歷value
與for in相比,有以下區別

  • 處集合對象外,還支持類對象和字符串
  • 不支持遍歷普通對象,但可經過與Object.keys()搭配使用實現遍歷
  • 遍歷後的輸出結果爲數組元素的值
var ar2 = [1,2,3]
ar2.length = 5;
ar2.push(4);

for (var k in ar2) {
  console.log(ar2[k]); //1,2,3,4
}

for (var v of ar2) {
  console.log(v); //1,2,3,undefined,undefined,4
}

Refers:
http://www.ecma-international.org/publications/standards/Ecma-262.htm
https://v8docs.nodesource.com/node-10.6/annotated.html

相關文章
相關標籤/搜索