]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(reactivity): call array subclass methods (#3624)
authorTheDro <andrewsc32@protonmail.com>
Thu, 15 Jul 2021 21:17:13 +0000 (17:17 -0400)
committerGitHub <noreply@github.com>
Thu, 15 Jul 2021 21:17:13 +0000 (17:17 -0400)
fix #2314, close #2315

packages/reactivity/__tests__/reactiveArray.spec.ts
packages/reactivity/src/baseHandlers.ts

index da3dc1f101ab68e040f719aef0f1b90bd54daac9..9402f3c5d6ebedd394ba2e8a023a7c0dc450998c 100644 (file)
@@ -171,4 +171,45 @@ describe('reactivity/reactive/Array', () => {
       expect(original.indexOf(ref)).toBe(1)
     })
   })
+
+  describe('Array subclasses', () => {
+    class SubArray<T> extends Array<T> {
+      lastPushed: undefined | T
+      lastSearched: undefined | T
+
+      push(item: T) {
+        this.lastPushed = item
+        return super.push(item)
+      }
+
+      indexOf(searchElement: T, fromIndex?: number | undefined): number {
+        this.lastSearched = searchElement
+        return super.indexOf(searchElement, fromIndex)
+      }
+    }
+
+    test('calls correct mutation method on Array subclass', () => {
+      const subArray = new SubArray(4, 5, 6)
+      const observed = reactive(subArray)
+
+      subArray.push(7)
+      expect(subArray.lastPushed).toBe(7)
+      observed.push(9)
+      expect(observed.lastPushed).toBe(9)
+    })
+
+    test('calls correct identity-sensitive method on Array subclass', () => {
+      const subArray = new SubArray(4, 5, 6)
+      const observed = reactive(subArray)
+      let index
+
+      index = subArray.indexOf(4)
+      expect(index).toBe(0)
+      expect(subArray.lastSearched).toBe(4)
+
+      index = observed.indexOf(6)
+      expect(index).toBe(2)
+      expect(observed.lastSearched).toBe(6)
+    })
+  })
 })
index a6db361d28938bec188be88877fb2b16994fa77a..8ce7f756e1349018fd999b84acb18c7f702dc0ed 100644 (file)
@@ -49,17 +49,16 @@ function createArrayInstrumentations() {
   // instrument identity-sensitive Array methods to account for possible reactive
   // values
   ;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => {
-    const method = Array.prototype[key] as any
     instrumentations[key] = function(this: unknown[], ...args: unknown[]) {
-      const arr = toRaw(this)
+      const arr = toRaw(this) as any
       for (let i = 0, l = this.length; i < l; i++) {
         track(arr, TrackOpTypes.GET, i + '')
       }
       // we run the method using the original args first (which may be reactive)
-      const res = method.apply(arr, args)
+      const res = arr[key](...args)
       if (res === -1 || res === false) {
         // if that didn't work, run it again using raw values.
-        return method.apply(arr, args.map(toRaw))
+        return arr[key](...args.map(toRaw))
       } else {
         return res
       }
@@ -68,10 +67,9 @@ function createArrayInstrumentations() {
   // instrument length-altering mutation methods to avoid length being tracked
   // which leads to infinite loops in some cases (#2137)
   ;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
-    const method = Array.prototype[key] as any
     instrumentations[key] = function(this: unknown[], ...args: unknown[]) {
       pauseTracking()
-      const res = method.apply(this, args)
+      const res = (toRaw(this) as any)[key].apply(this, args)
       resetTracking()
       return res
     }