【问题标题】:How would you create Set.prototype.add() from scratch?您将如何从头开始创建 Set.prototype.add()?
【发布时间】:2020-07-02 01:20:09
【问题描述】:

在ECMAScript,它解释了如何创建添加原型。

采取以下步骤:

设 S 为 this 值。

如果 Type(S) 不是 Object,则抛出 TypeError 异常。

如果 S 没有 [[SetData]] 内部槽,则抛出 TypeError 异常。

让条目是列表,它是 S 的 [[SetData]] 内部槽的值。

对作为条目元素的每个 e 重复,

如果 e 不为空且 SameValueZero(e, value) 为真,则

返回 S。

如果值为-0,则令值为+0。

附加值作为条目的最后一个元素。

返回 S。”

我对 JS 还很陌生,不知道这意味着什么。如果我要创建一个这样的类

class mySet {
constructor(){
    this.set = {}
}
//adds a value to set
add(){
    
}

我将如何进行?

【问题讨论】:

    标签: javascript data-structures


    【解决方案1】:

    这是一个示例实现。它基本上只是遵循规范中概述的步骤。然而,我不完全确定 is empty 是什么意思,所以 (我将其视为 undefined。)

    要检查负零,您需要作弊并测试 -Infinity 或类似的东西。

    function isNegativeZero (x) {
      return 1 / x === -Infinity
    }
    
    function SameValueZero (a, b) {
        if (typeof a !== typeof b) return false
    
        if (typeof a === 'number') {
            if (Number.isNaN(a) && Number.isNaN(b)) return true;
            if (isNegativeZero(a) && b === 0) return true;
            if (isNegativeZero(b) && a === 0) return true;
            if (+a === +b) return true;
            return false
        }
        return a === b;
    }
    
    
    class MySet {
        constructor(){
            this[MySet.Symbols.SetData] = [];
        }
    
        //adds a value to set
        add(value){
            const S = this;
            
            if (typeof S !== 'object') throw new TypeError(`Type mismatch. Expected ${this} to be of type object`);
    
            const entries = this[MySet.Symbols.SetData];
            
            for (const e of entries) {
                if (typeof e !== 'undefined' && SameValueZero(e, value)) return S;
            }
    
            if (isNegativeZero (value)) value = 0;
    
            entries.push(value);
    
            return S;
        }
        toString() {
          return `MySet(${this[MySet.Symbols.SetData].length}) {${this[MySet.Symbols.SetData]}}`
        }
    }
    MySet.Symbols = {
        SetData: Symbol('SetData')
    }
    
    
    const mySet = new MySet();
    
    mySet.add(1);
    console.log(mySet + '');
    mySet.add(1);
    console.log(mySet + '');
    mySet.add(NaN);
    console.log(mySet + '');
    mySet.add(NaN);
    console.log(mySet + '');

    【讨论】:

    • 所以我对你为什么在构造函数中将集合设置为数组感到困惑。我认为集合是对象?
    • @PaulHan 在 Javascript 中几乎所有东西都是一个对象。数组也是一个对象。 Set objects are collections of values。 MySet 的实例当然是一个对象。它只是在内部使用一个数组来保存值的集合(这很方便,因为它保持了插入的顺序)。您只需要确保没有添加两次元素。您可以选择如何实施该集合。
    • @PaulHan 规范说“让条目是列表,它是 S 的 [[SetData]] 内部插槽的值。”。这意味着/声明内部值 [[Set Data]] 是一个列表。数组就是一个列表。
    【解决方案2】:

    这是一个想法。它不适用于undefined,因为该值用于指示空白区域。如果使用有孔数组,它可以与 undefined 一起使用,但这会产生性能成本。

    在此示例中,该值未作为数组的最后一个元素附加,而是附加在第一个空白区域的位置,以防止不必要地扩展数组。

    当然,JavaScript 代码不能访问内部槽,所以这里使用了一个属性。

    class MySet {
      setData = [];
    
      add(value) {
        if (!("setData" in this))
          throw new TypeError("add method called on incompatible Object");
    
        let firstEmptyIndex = -1;
        for (let i = 0; i < this.setData.length; i++) {
          const item = this.setData[i];
          if (firstEmptyIndex < 0 && item === undefined) {
            firstEmptyIndex = i;
            continue;
          }
    
          if ((typeof item === "number" && Number.isNaN(item) && typeof value === "number" && Number.isNaN(value)) || item === value) // Item already in the set
            return this;
        }
        
        if (firstEmptyIndex < 0)
          this.setData.push(value);
        else
          this.setData[firstEmptyIndex] = value;
        return this;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-21
      • 2021-04-12
      • 2021-11-18
      • 2018-08-04
      • 2011-12-25
      相关资源
      最近更新 更多