Skip to content

Commit 1cfe290

Browse files
authored
fix(reactivity): call array subclass methods (#3624)
fix #2314, close #2315
1 parent 299f7c0 commit 1cfe290

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

packages/reactivity/__tests__/reactiveArray.spec.ts

+41
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,45 @@ describe('reactivity/reactive/Array', () => {
171171
expect(original.indexOf(ref)).toBe(1)
172172
})
173173
})
174+
175+
describe('Array subclasses', () => {
176+
class SubArray<T> extends Array<T> {
177+
lastPushed: undefined | T
178+
lastSearched: undefined | T
179+
180+
push(item: T) {
181+
this.lastPushed = item
182+
return super.push(item)
183+
}
184+
185+
indexOf(searchElement: T, fromIndex?: number | undefined): number {
186+
this.lastSearched = searchElement
187+
return super.indexOf(searchElement, fromIndex)
188+
}
189+
}
190+
191+
test('calls correct mutation method on Array subclass', () => {
192+
const subArray = new SubArray(4, 5, 6)
193+
const observed = reactive(subArray)
194+
195+
subArray.push(7)
196+
expect(subArray.lastPushed).toBe(7)
197+
observed.push(9)
198+
expect(observed.lastPushed).toBe(9)
199+
})
200+
201+
test('calls correct identity-sensitive method on Array subclass', () => {
202+
const subArray = new SubArray(4, 5, 6)
203+
const observed = reactive(subArray)
204+
let index
205+
206+
index = subArray.indexOf(4)
207+
expect(index).toBe(0)
208+
expect(subArray.lastSearched).toBe(4)
209+
210+
index = observed.indexOf(6)
211+
expect(index).toBe(2)
212+
expect(observed.lastSearched).toBe(6)
213+
})
214+
})
174215
})

packages/reactivity/src/baseHandlers.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,16 @@ function createArrayInstrumentations() {
4949
// instrument identity-sensitive Array methods to account for possible reactive
5050
// values
5151
;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => {
52-
const method = Array.prototype[key] as any
5352
instrumentations[key] = function(this: unknown[], ...args: unknown[]) {
54-
const arr = toRaw(this)
53+
const arr = toRaw(this) as any
5554
for (let i = 0, l = this.length; i < l; i++) {
5655
track(arr, TrackOpTypes.GET, i + '')
5756
}
5857
// we run the method using the original args first (which may be reactive)
59-
const res = method.apply(arr, args)
58+
const res = arr[key](...args)
6059
if (res === -1 || res === false) {
6160
// if that didn't work, run it again using raw values.
62-
return method.apply(arr, args.map(toRaw))
61+
return arr[key](...args.map(toRaw))
6362
} else {
6463
return res
6564
}
@@ -68,10 +67,9 @@ function createArrayInstrumentations() {
6867
// instrument length-altering mutation methods to avoid length being tracked
6968
// which leads to infinite loops in some cases (#2137)
7069
;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
71-
const method = Array.prototype[key] as any
7270
instrumentations[key] = function(this: unknown[], ...args: unknown[]) {
7371
pauseTracking()
74-
const res = method.apply(this, args)
72+
const res = (toRaw(this) as any)[key].apply(this, args)
7573
resetTracking()
7674
return res
7775
}

0 commit comments

Comments
 (0)