wang1dot0 / personal-note

记录工作中遇到的个人觉得比较有意思的小问题
https://github.com/wang1dot0/personal-note
0 stars 0 forks source link

[..obj]引发的思考 #19

Open wang1dot0 opened 5 years ago

wang1dot0 commented 5 years ago
var obj = { a: 1, b: 11, c: 22 };
[...obj]

结果: 1568623998 因为[...iterat]中iterat必须是可迭代的iterable,而对象默认并不是迭代器,所以,会报错。而默认提供iterable接口的有数组,字符串和新加入的Set和Map等。 它的实现是内置了@@iterator对象,我们可以通过调用[Symbol.iterator]方法访问。 因此,要实现上述功能:

方法一

Object.defineProperty(obj, Symbol.iterator, {
  writable: true,
  configuable: true,
  value: function () {
    let _copy = this,
        keys = Object.keys(_copy),
        i = 0;
    return {
      next() {
    let res = _copy[keys[i++]];
    if (i === keys.length) {
      return { value: undefined, done: true }; 
    }
    return { value: res, done: false };
      },
    };
  },
});

缺点很明显,比较臃肿,而且还丑陋地锁定this的指向。

方法二


obj[Symbol.iterator] = function *foo() {
const arr = Object.keys(this);

for (idx of arr) { yield this[idx]; } }

> 明显利用了generator/yield本身也是一个迭代器的特性,比方法一简化了很多。

#### 方法三
```js
obj[Symbol.iterator] = function *foo() {
  var arr = Object.values(this);
  yield *arr;
}

发现yield *的用法,它是一种委托,如果后面跟的是一个迭代器,它会默认委托执行该迭代器,于是有了上面的方法。