Set.js--建立無重複值的無序集合

Set 集合,不一樣於 Array,是一種沒有重複值的集合。es6

如下代碼出自於《JavaScript 權威指南(第六版)》P217,注意:這裏並非指 es6 / es2015 中的 Set 集合。它只是提供了一種實現類的例子,由於代碼寫得很巧妙,我就想記錄下來並分享給你們。數組

// 定義一個 Set 構造函數
function Set() {
  this.values = {};  // values 以鍵值對的形式表示集合的數據
  this.n = 0;  // n 集合中值的個數
  // arguments 是實際參數的一個類數組對象
  // 保證在 new Set(1,'sarah',{}) 初始化構造函數時調用原型上的 add 方法,將傳入的參數添加到集合中
  this.add.apply(this, arguments);  
}

// 將每一個參數添加至集合中
Set.prototype.add = function() {
  // 遍歷每個參數
  for (var i = 0; i < arguments.length; i++) {
    var val = arguments[i],  //
        str = Set._v2s(val); // 鍵:經過值獲得相應的鍵
    // 保證集合無重複值
    if (!this.values.hasOwnProperty(str)) {
      this.values[str] = val;
      this.n++; // 集合中值的計數加一
    }
  }
  return this; // 支持鏈式調用
}

// 刪除元素
Set.prototype.remove = function() {
  // 遍歷每個參數
  for (var i = 0; i < arguments.length; i++) {
    var str = Set._v2s(arguments[i]); // 經過值獲得相應的鍵
    if (this.values.hasOwnProperty(str)) { // 若 values 集合中存在該屬性
      delete this.values[str];  // 刪除元素
      this.n--; // 集合中值的計數減一
    }
  }
  return this; // 支持鏈式調用
}

// 檢測是否包含某個值
Set.prototype.contains = function(value) {
  return this.values.hasOwnProperty(Set._v2s(value));
}

// 返回集合的大小
Set.prototype.size = function() {
  return this.n;
}

// 遍歷集合中的全部元素,在指定的上下文中調用回調函數 f
Set.prototype.foreach = function(f, context) {
  for (var s in this.values) {
    if (this.values.hasOwnProperty(s)) {
      f.call(context, this.values[s]);
    }
  }
}

// 在 Set 方法上定義一個自定義屬性 _v2s
// 該屬性的值是一個方法,用於將傳入的值轉成對應的字符串(其實就像是打標籤)
Set._v2s = function(val) {
  switch (val) {
    case undefined: return 'u';  // 若是是 undefined,就返回 'u'
    case null: return 'n';
    case true: return 't';
    case false: return 'f';
    default: switch (typeof val) {
      case 'number': return '#' + val;  // 若是是數字,就添加 # 前綴 ,例如 #123, #0.5
      case 'string': return '"' + val;  // 若是是字符串,就添加 " 前綴 , 例如 "hello, "world
      default: return '@' + objectId(val); // 若是是數組、函數、對象等,就添加 @ 前綴,objectId 方法會返回一個特定數字,如:@100
    }
  }

  function objectId(o) {
    var prop = "|**objectid**|";  // 給數組/ 函數/ 對象定義一個私有屬性,用以存放 id
    if (!o.hasOwnProperty(prop)) { // 添加該屬性前先判斷該對象是否已經存在該屬性
      o[prop] = Set._v2s.next++; // 不存在則添加該屬性,值爲 next
    }
    return o[prop];
  }
}
// 在 Set._v2s.next 方法上定義一個自定義屬性 next,初始值爲 100
// 這樣作的好處是,避免了全局變量污染,而且將該屬性與對應的方法綁定在一塊兒
Set._v2s.next = 100;

 

以上代碼就定義好了一個 Set 類,它能夠向集合中添加元素,也能夠刪除元素,還能夠查詢某個元素是否在該集合中等等。下面咱們就來測試一下:app

var arr  = [3, 4, 5];
var set = new Set(1, 1, 3, 'sarah', null, undefined, function () {}, arr, {});
console.log(set);

打印 set,結果以下:  函數

我在 new Set ( ) 的時候傳入了 9 個參數,但打印結果中顯示 n = 8,而且參數 1 只出現了一次,即 #1 。這說明了,set 集合不會添加劇復值。測試

其它示例:this

    var arr  = [3, 4, 5];
    var set = new Set(1, 1, 3, 'sarah', null, undefined, function () {}, arr, {});

    console.log(set.remove(null)); // n = 7
    console.log(set.contains('sarah')); // true
    console.log(set.contains('lissy')); // false

    set.add([3, 4, 5]); // 能夠成功,由於數組是引用類型,當前添加的這個 [3, 4, 5] 跟以前的 arr 不是指向同一個引用
    console.log(set.size()); // 8

 

我寫這篇文章的目的不在於向你們提供 Set 這個構造函數,主要仍是爲了加深對類的理解。這其中在函數上定義自定義屬性這一操做,是我在以前的代碼中沒有用到過的,它能夠解決一些全局變量的問題,又能夠和對應的函數緊密關聯在一塊兒,我以爲很是有用。spa

 

做者不才,文中如有錯誤,望請指正,避免誤人子弟。prototype

相關文章
相關標籤/搜索