zoukankan      html  css  js  c++  java
  • Set.js--创建无重复值的无序集合

    Set 集合,不同于 Array,是一种没有重复值的集合。

    以下代码出自于《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 类,它可以向集合中添加元素,也可以删除元素,还可以查询某个元素是否在该集合中等等。下面我们就来测试一下:

    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 集合不会添加重复值。

    其它示例:

        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 这个构造函数,主要还是为了加深对类的理解。这其中在函数上定义自定义属性这一操作,是我在之前的代码中没有用到过的,它可以解决一些全局变量的问题,又可以和对应的函数紧密关联在一起,我觉得非常有用。

    作者不才,文中若有错误,望请指正,避免误人子弟。

  • 相关阅读:
    文件系统管理
    软件包管理
    用户和用户组管理
    权限管理
    漏洞验证系列--MongoDB未授权访问
    【Jenkins】三、设置定时任务
    在CentOS Linux 7.5上安装MySQL
    CentOS7使用yum时File contains no section headers.解决办法
    Windows批处理(cmd/bat)常用命令学习
    Fiddler抓包工具总结
  • 原文地址:https://www.cnblogs.com/sarahwang/p/9121136.html
Copyright © 2011-2022 走看看