From: edison Date: Mon, 19 Jan 2026 00:50:35 +0000 (+0800) Subject: fix(reactivity): collection iteration should inherit iterator instance methods (... X-Git-Tag: v3.5.27~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3c8b2fc836b2f60c90c2459933e66b2fd9fb8c08;p=thirdparty%2Fvuejs%2Fcore.git fix(reactivity): collection iteration should inherit iterator instance methods (#12644) close #12615 --- diff --git a/packages/reactivity/__tests__/collections/Map.spec.ts b/packages/reactivity/__tests__/collections/Map.spec.ts index a0de8feaf3..41aea9ffc2 100644 --- a/packages/reactivity/__tests__/collections/Map.spec.ts +++ b/packages/reactivity/__tests__/collections/Map.spec.ts @@ -471,5 +471,30 @@ describe('reactivity/collections', () => { const result = map.set('a', 'a') expect(result).toBe(map) }) + + it('should wrapped iterator inherit all iterator properties', () => { + const raw = new Map([['key', 'value']]) + const map = reactive(raw) + + const rawIterator = raw.entries() + const wrappedIterator = map.entries() + + // Wrapped iterator should have the same properties as original iterator + expect(typeof wrappedIterator.next).toBe('function') + expect(typeof wrappedIterator[Symbol.iterator]).toBe('function') + expect(wrappedIterator[Symbol.iterator]()).toBe(wrappedIterator) + + // Check inherited iterator helper methods if they exist on the original + for (const key of Object.getOwnPropertyNames( + Object.getPrototypeOf(rawIterator), + )) { + expect(key in wrappedIterator).toBe(true) + } + for (const key of Object.getOwnPropertySymbols( + Object.getPrototypeOf(rawIterator), + )) { + expect(key in wrappedIterator).toBe(true) + } + }) }) }) diff --git a/packages/reactivity/src/collectionHandlers.ts b/packages/reactivity/src/collectionHandlers.ts index ffc3289f2e..a74f30433d 100644 --- a/packages/reactivity/src/collectionHandlers.ts +++ b/packages/reactivity/src/collectionHandlers.ts @@ -55,22 +55,22 @@ function createIterableMethod( ) // return a wrapped iterator which returns observed versions of the // values emitted from the real iterator - return { - // iterator protocol - next() { - const { value, done } = innerIterator.next() - return done - ? { value, done } - : { - value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), - done, - } - }, - // iterable protocol - [Symbol.iterator]() { - return this + return extend( + // inheriting all iterator properties + Object.create(innerIterator), + { + // iterator protocol + next() { + const { value, done } = innerIterator.next() + return done + ? { value, done } + : { + value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), + done, + } + }, }, - } + ) } }