Procházet zdrojové kódy

fix(provide/inject): do not mutate original provide options during merge

fix #12854
Evan You před 3 roky
rodič
revize
d1899caf68

+ 19 - 3
src/core/util/options.ts

@@ -51,7 +51,8 @@ if (__DEV__) {
  */
 function mergeData(
   to: Record<string | symbol, any>,
-  from: Record<string | symbol, any> | null
+  from: Record<string | symbol, any> | null,
+  recursive = true
 ): Record<PropertyKey, any> {
   if (!from) return to
   let key, toVal, fromVal
@@ -66,7 +67,7 @@ function mergeData(
     if (key === '__ob__') continue
     toVal = to[key]
     fromVal = from[key]
-    if (!hasOwn(to, key)) {
+    if (!recursive || !hasOwn(to, key)) {
       set(to, key, fromVal)
     } else if (
       toVal !== fromVal &&
@@ -262,7 +263,22 @@ strats.props =
       if (childVal) extend(ret, childVal)
       return ret
     }
-strats.provide = mergeDataOrFn
+
+strats.provide = function (parentVal: Object | null, childVal: Object | null) {
+  if (!parentVal) return childVal
+  return function () {
+    const ret = Object.create(null)
+    mergeData(ret, isFunction(parentVal) ? parentVal.call(this) : parentVal)
+    if (childVal) {
+      mergeData(
+        ret,
+        isFunction(childVal) ? childVal.call(this) : childVal,
+        false // non-recursive
+      )
+    }
+    return ret
+  }
+}
 
 /**
  * Default strategy.

+ 8 - 0
test/unit/features/options/inject.spec.ts

@@ -712,4 +712,12 @@ describe('Options provide/inject', () => {
     await nextTick()
     expect(spy).toHaveBeenCalledWith(2)
   })
+
+  // #12854
+  test('should not mutate original provide options', () => {
+    const hairMixin = { provide: { hair: 'red' } }
+    const eyesMixin = { provide: { eyes: 'brown' } }
+    new Vue({ mixins: [hairMixin, eyesMixin], render() {} }).$mount()
+    expect(eyesMixin.provide).toStrictEqual({ eyes: 'brown' })
+  })
 })