gpt4 book ai didi

javascript - 在 JavaScript 中,一个可迭代对象应该重复迭代吗?

转载 作者:行者123 更新时间:2023-12-04 15:28:47 26 4
gpt4 key购买 nike

我发现一些迭代可以重复迭代:

const iterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 3;
yield 5;
}
}

console.log([...iterable]);
console.log([...iterable]);
console.log([...iterable]);


虽然有些不能:

function* generatorFn() {
yield 1;
yield 3;
yield 5;
}

const iterable = generatorFn();

console.log([...iterable]);
console.log([...iterable]);
console.log([...iterable]);


是否有一个可迭代对象是否应该重复迭代的规则?

我理解为什么它们的行为不同(这是因为第二种情况,当调用 iterable[Symbol.iterator]函数时,返回相同的迭代器(即 iterable本身。可以尝试 iterable[Symbol.iterator]() === iterable,它会返回 trueiterable.next也是一个函数。所以在这种情况下, iterable是一个生成器对象、一个迭代器和一个迭代器,所有这三个。但我想知道迭代器是一种对象类型,是否有明确定义的行为它应该或不应该重复迭代。)

最佳答案

好的,我想我会总结我们在评论中学到的一些东西并添加更多内容,然后通过写下您的具体问题的答案来结束。

[...x]语法
[...x]语法适用于支持 iterables 的东西界面。而且,支持可迭代接口(interface)所需要做的就是支持 Symbol.iterator属性来提供一个函数(当被调用时)返回一个迭代器。

内置迭代器也是可迭代的

Javascript 中内置的所有迭代器都源自相同的 IteratorPrototype .迭代器不需要这样做,这是内置迭代器做出的选择。

这个内置IteratorPrototype也是一个 Iterable。它支持Symbol.iterator属性是一个函数,它只是做 return this .这是 by specification .

这意味着所有内置迭代器,例如 someSet.values()将与 [...x] 一起使用句法。我不确定为什么这非常有用,但它肯定会导致混淆 Iterable 可以做什么以及 Iterator 可以做什么,因为这些内置迭代器可以表现得如此。

它会导致一些奇怪的行为,因为如果你这样做:

let s = new Set([1,2,3]);
let iter = s.values(); // gets an iterator
let x = [...iter];
let y = [...iter];
console.log(x);
console.log(y);


第二个 [...iter]是一个空数组,因为这里只有一个迭代器。事实上, x === y .于是第一个 let x = [...iter];耗尽迭代器。它坐在 done并且无法再次迭代集合。这是因为内置迭代器的这种时髦行为,它们表现为可迭代,但只是 return this .他们不会创建一个新的迭代器,它可以像使用实际的集合迭代器那样再次迭代集合。每次访问 s[Symbol.iterator]() 时,此集合迭代器都会返回一个全新的迭代器如下所示:

let s = new Set([1,2,3]);
let x = [...s];
let y = [...s];
console.log(x);
console.log(y);


普通迭代器不适用于 [...x]

要成为迭代器,您需要实现的只是支持 .next()方法并用适当的对象进行响应。实际上,这是一个符合规范的 super 简单迭代器:
const iter = { 
i: 1,
next: function() {
if (this.i <= 3) {
return { value: this.i++, done: false };
} else {
return { value: undefined, done: true };
}
}
}

如果你尝试做 let x = [...iter]; ,它会抛出这个错误:
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))

但是,如果您通过添加适当的 [Symbol.iterator] 使其成为可迭代的属性,它将作为 [...iter] 工作;

const iter = { 
i: 1,
next: function() {
if (this.i <= 3) {
return { value: this.i++, done: false };
} else {
return { value: undefined, done: true };
}
},
[Symbol.iterator]: function() { return this; }
}

let x = [...iter];
console.log(x);


然后,它可以作为 [...iter] 工作因为它现在也是一个可迭代的。

发电机

Generator 函数在被调用时返回一个 Generator 对象。每 spec ,该 Generator 对象的行为既是 Iterator和一个 Iterable .故意无法判断这个迭代器/迭代器是否来自生成器,这显然是 done on purpose .调用代码只知道它是一个 Iterator/Iterable生成器函数只是创建对调用代码透明的序列的一种方式。它像任何其他迭代器一样被迭代。

你的两个迭代器的故事

在您的原始问题中,您展示了两个迭代器,一个重复运行,一个不重复运行。这里有两件事在起作用。

首先,一些迭代器“消耗”了它们的序列,并且无法重复迭代相同的序列。这些将是制造序列,而不是静态集合。

其次,在您的第一个代码示例中:
const iterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 3;
yield 5;
}
}

console.log([...iterable]);
console.log([...iterable]);
console.log([...iterable]);

单独的迭代器

那个迭代器是一个迭代器。它不是迭代器。您可以通过调用 iterable[Symbol.iterator]() 来要求它提供迭代器。这是什么 [...iterable]做。但是,当您这样做时,它会返回一个全新的 Generator 对象,该对象是一个全新的迭代器。每次拨打 iterable[Symbol.iterator]()或使用 [...iterable] 调用它,你会得到一个新的和不同的迭代器。

你可以在这里看到:

    const iterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 3;
yield 5;
}
}

let iterA = iterable[Symbol.iterator]();
let iterB = iterable[Symbol.iterator]();

// shows false, separate iterators on separate generator objects
console.log(iterA === iterB);


因此,您正在为每个迭代器创建一个全新的序列。它新鲜地调用生成器函数以获取新的生成器对象。

相同的迭代器

但是,用你的第二个例子:
function* generatorFn() {
yield 1;
yield 3;
yield 5;
}

const iterable = generatorFn();

console.log([...iterable]);
console.log([...iterable]);
console.log([...iterable]);

这是不同的。你叫什么 iterable这是我喜欢认为的 pseudo-iterable .它同时实现了 IterableIterator接口(interface),但是当您向它索要 Iterator 时喜欢 [...iterable]确实,它每次(本身)都返回相同的对象。所以,每次你做 [...iterable] ,它在同一个迭代器上运行。但是那个迭代器已经筋疲力尽了,坐在 done第一次执行后的状态 [...iterable] .所以,后两个 [...iterable]是空数组。迭代器没有什么可提供的。

您的问题

Is there a rule whether an iterable should or should not be repeatedly iterable?



并不真地。首先,一个给定的迭代器最终到达 done状态(一个非无限迭代器)一旦到达 done 就会给出任何结果。状态。根据迭代器的定义。

所以,无论是否是 Iterable表示某种静态序列可以重复迭代取决于 Iterator它在每次询问迭代器时提供的都是新的和唯一的,我们在上面的两个例子中已经看到, Iterable可以走任何一条路。

它每次都可以产生一个新的、唯一的迭代器,每次都通过序列呈现一个新的迭代。

或者,一个 Iterable可以生产完全一样的 Iterator每一次。如果这样做,一旦该迭代器到达 done状态,它被困在那里。

还请记住,某些 Iterable 表示可能不可重复的动态集合/序列。对于 Set 之类的东西来说,情况并非如此。或 Map ,但更多自定义类型的 Iterables 可能会在迭代时“消耗”它们的集合,当它完成时,没有更多,即使你得到一个新的迭代器。

想象一个迭代器给你一个值(value) 1 美元到 10 美元之间的随机金额的代码,并在每次你向迭代器询问下一个值时从你的银行余额中减去它。在某些时候,您的银行余额达到 $0并且迭代器已经完成,即使获得一个新的迭代器仍然需要处理相同的 $0银行余额(没有更多值(value))。那将是一个迭代器的例子
“消耗”值或一些资源,只是不可重复。

But I wonder iterable being an object type, is there a well-defined behavior as to whether it should or should not be repeatedly iterable.



不。它是特定于实现的,完全取决于您要迭代的内容。使用像 Set 这样的静态集合或 MapArray ,您可以获取一个新的迭代器并每次生成一个新的迭代。但是,我称之为 psuedo-iterable (每次请求时都返回相同迭代器的可迭代对象)或在迭代时“消耗”序列的可迭代对象可能无法重复迭代。所以,它可以是故意的。没有标准的方法。这取决于正在迭代的内容。

测试您所拥有的

这里有一些有用的测试,可以帮助人们理解一些事情:
// could do a more comprehensive test by calling `obj.next()` to see if
// it returns an appropriate object with appropriate properties, but
// that is destructive to the iterator (consumes that value)
// so we keep this one non-destructive
function isLikeAnIterator(obj) {
return typeof obj === "object" && typeof obj.next === "function)";
}

function isIterable(obj) {
if (typeof obj === "object" && typeof obj[Symbol.iterator] === "function") {
let iter = obj[Symbol.iterator]();
return isLikeAnIterator(iter);
}
return false;
}

// A pseudo-iterable returns the same iterator each time
// Sometimes, the pseudo-iterable returns itself as the iterator too
function isPseudoIterable(obj) {
if (isIterable(obj) {
let iterA = obj[Symbol.iterator]();
if (iterA === this) {
return true;
}
let iterB = obj[Symbol.iterator]();
return iterA === iterB;
}
return false;
}

function isGeneratorObject(obj) {
if (!isIterable(obj) !! !isLikeAnIterator(obj) {
// does not meet the requirements of a generator object
// which must be both an iterable and an iterator
return false;
}
throw new Error("Can't tell if it's a generator object or not by design");
}

关于javascript - 在 JavaScript 中,一个可迭代对象应该重复迭代吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59595512/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com