【问题标题】:Can you make properties enumerable but not iterable in javascript?你能在javascript中使属性可枚举但不可迭代吗?
【发布时间】:2014-07-22 01:21:12
【问题描述】:

我只是想知道是否有一种方法可以让对象属性像 for in 循环中那样可枚举,但不会出现在 for of loop 之类的类似中

Object.defineProperty({},'prop',{
    enumerable:true,
    iterable:false
}

如果没有,是否有计划实施这样的功能?还是for of 循环使用了可枚举属性

【问题讨论】:

  • 我已经用谷歌搜索了...我没有发现任何暗示会有一个具有该确切名称的属性。我只是想知道他们是否有计划实施一种使值可迭代且键不可编号的方法,我将更新我的问题以使其更加清晰
  • 那你可能问错地方了。在 ES6 邮件列表上提问更有可能给你想要的答案。 Stackoverflow 最重要的是用代码答案提出代码问题。
  • @Mike'Pomax'Kamermans 不必对此无礼。除了态度,这个问题没有什么离题的。在形成 C++11 时,我们看到了大量类似的问题。

标签: javascript ecmascript-6


【解决方案1】:

我在 Mozilla 开发网络 (MDN) 上进行了一些研究。

原来对象有一个obj.propertyIsEnumerable(prop) 方法来检查属性是否可枚举。从 MDN 中给出的示例来看,通过原型链继承的属性是不可枚举的,因此该方法对这些属性返回 false。

不可枚举属性的一个例子是构造函数和数组的属性length

对于问题的可迭代部分,我将引用 MDN:“ECMAScript 6 中的可迭代是一个接口(或者换句话说,一个协议),而不是像 Array 或 Map 这样的对象类型”。

也就是说,对象需要实现这个接口,才能使其属性可迭代。对于 String、Array、Map、Set、WeakSet 和 Generator 对象等内置可迭代对象就是这种情况。

以下代码说明了这一点:

var aString = "hello"
typeof aString[Symbol.iterator] // "function"
aString[Symbol.iterator]() + "" // "[object String Iterator]"
[...aString]                    // ["h", "e", "l", "l", "o"]

当然,您可以定义自己的迭代器实现。

回到问题,附加到对象或其原​​型的属性(直接,意味着不通过继承)将在for...in 循环中显示为可枚举。对于可迭代对象,您需要一个实现,可以是前面提到的实现,也可以是您自己的实现。这是来自 MDN 的一个很好的例子。

let arr = [ 3, 5, 7 ];
arr.foo = "hello";

for (let i in arr) {
   console.log(i); // logs "0", "1", "2", "foo" these are property names or indexes
}

for (let i of arr) {
   console.log(i); // logs "3", "5", "7" these are actual values of an
                   // iterable implementation provided by the array prototype
}

let 关键字在此上下文中等同于 var 定义(尽管它具有更多含义,但它们超出了本文的范围)。

如您所见,数组已经实现了iterable 接口(来自数组原型),因此在使用for...of 循环时它会产生它的值,而foo 属性没有显示(两者都没有)值或属性名称)。

因此,如果您的对象没有实现 iterable 接口,则它不应该是可迭代的(原则上),因此它将在 for...of 循环中显示其属性。

【讨论】:

    【解决方案2】:

    for in and for of evaluations 的区别在于一个使用obj.[[enumerate]] 而另一个使用GetIterator(obj) 来确定循环项。 [[enumerate]] does(除非 obj 是代理)

    返回一个Iterator object,其next 方法迭代obj 的可枚举属性的所有字符串值键。

    GetIterator 将(尝试)调用@@iterate method - 但是,普通对象不实现此接口。

    因此,除非您明确声明,否则for of 循环中不会显示任何属性:

    function defineIterableProperty(obj, prop, desc) {
        let old = obj[Symbol.iterate];
        Object.defineProperty(obj, prop, desc);
        obj[Symbol.iterate] = function* () {
            if (old) yield* old.call(this);
            yield prop;
        };
        return obj;
    }
    

    (未经测试,但我希望你明白)

    【讨论】:

      猜你喜欢
      • 2013-09-03
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-21
      • 1970-01-01
      • 2012-07-12
      • 2012-05-02
      相关资源
      最近更新 更多