Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES6 系列之模拟实现一个 Set 数据结构 #71

Open
yangtao2o opened this issue Apr 6, 2020 · 0 comments
Open

ES6 系列之模拟实现一个 Set 数据结构 #71

yangtao2o opened this issue Apr 6, 2020 · 0 comments

Comments

@yangtao2o
Copy link
Owner

yangtao2o commented Apr 6, 2020

ES6 系列之模拟实现一个 Set 数据结构

Set 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

let set = new Set([1, 2, 3, 4, 4]);
console.log(set); // Set(4) {1, 2, 3, 4}

set = new Set(new Set([1, 2, 3, 4]));
console.log(set.size); // 4

操作方法有:

  • add(value):添加某个值,返回 Set 结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为 Set 的成员。
  • clear():清除所有成员,无返回值。

遍历方法有:

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员,无返回值

注意 keys()、values()、entries() 返回的是遍历器

属性

  • Set.prototype.constructor:构造函数,默认就是 Set 函数。
  • Set.prototype.size:返回 Set 实例的成员总数。

模拟实现一个 Set 数据结构:

(function(global) {
  var NaNSymbol = Symbol("NaN");

  var encodeVal = function(value) {
    return value !== value ? NaNSymbol : value;
  };

  var decodeVal = function(value) {
    return value === NaNSymbol ? NaN : value;
  };

  var makeIterator = function(array, iterator) {
    var nextIndex = 0;

    // new Set(new Set()) 会调用这里
    var obj = {
      next: function() {
        return nextIndex < array.length
          ? { value: iterator(array[nextIndex++]), done: false }
          : { value: void 0, done: true };
      }
    };

    // [...set.keys()] 会调用这里
    obj[Symbol.iterator] = function() {
      return obj;
    };

    return obj;
  };

  function forOf(obj, cb) {
    let iterable, result;

    if (typeof obj[Symbol.iterator] !== "function")
      throw new TypeError(obj + " is not iterable");
    if (typeof cb !== "function") throw new TypeError("cb must be callable");

    iterable = obj[Symbol.iterator]();

    result = iterable.next();
    while (!result.done) {
      cb(result.value);
      result = iterable.next();
    }
  }

  function Set(data) {
    this._values = [];
    this.size = 0;

    forOf(data, item => {
      this.add(item);
    });
  }

  Set.prototype["add"] = function(value) {
    value = encodeVal(value);
    if (this._values.indexOf(value) == -1) {
      this._values.push(value);
      ++this.size;
    }
    return this;
  };

  Set.prototype["has"] = function(value) {
    return this._values.indexOf(encodeVal(value)) !== -1;
  };

  Set.prototype["delete"] = function(value) {
    var idx = this._values.indexOf(encodeVal(value));
    if (idx == -1) return false;
    this._values.splice(idx, 1);
    --this.size;
    return true;
  };

  Set.prototype["clear"] = function(value) {
    this._values = [];
    this.size = 0;
  };

  Set.prototype["forEach"] = function(callbackFn, thisArg) {
    thisArg = thisArg || global;
    for (var i = 0; i < this._values.length; i++) {
      callbackFn.call(thisArg, this._values[i], this._values[i], this);
    }
  };

  Set.prototype["values"] = Set.prototype["keys"] = function() {
    return makeIterator(this._values, function(value) {
      return decodeVal(value);
    });
  };

  Set.prototype["entries"] = function() {
    return makeIterator(this._values, function(value) {
      return [decodeVal(value), decodeVal(value)];
    });
  };

  Set.prototype[Symbol.iterator] = function() {
    return this.values();
  };

  Set.prototype["forEach"] = function(callbackFn, thisArg) {
    thisArg = thisArg || global;
    var iterator = this.entries();

    forOf(iterator, item => {
      callbackFn.call(thisArg, item[1], item[0], this);
    });
  };

  Set.length = 0;

  global.Set = Set;
})(this);

测试:

let set = new Set(new Set([1, 2, 3]));
console.log(set.size); // 3

console.log([...set.keys()]); // [1, 2, 3]
console.log([...set.values()]); // [1, 2, 3]
console.log([...set.entries()]); // [1, 2, 3]

原文链接:ES6 系列之模拟实现一个 Set 数据结构

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant