Skip to content

Commit eea0920

Browse files
javoskiyyx990803
authored andcommitted
fix: improve Vue.set/Vue.delete API to support multi type of array index (#5973)
related #5884
1 parent 458030a commit eea0920

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

src/core/observer/index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
def,
77
isObject,
88
isPlainObject,
9+
isValidArrayIndex,
910
hasProto,
1011
hasOwn,
1112
warn,
@@ -189,7 +190,7 @@ export function defineReactive (
189190
* already exist.
190191
*/
191192
export function set (target: Array<any> | Object, key: any, val: any): any {
192-
if (Array.isArray(target) && (typeof key === 'number' || /^\d+$/.test(key))) {
193+
if (Array.isArray(target) && isValidArrayIndex(key)) {
193194
target.length = Math.max(target.length, key)
194195
target.splice(key, 1, val)
195196
return val
@@ -219,7 +220,7 @@ export function set (target: Array<any> | Object, key: any, val: any): any {
219220
* Delete a property and trigger change if necessary.
220221
*/
221222
export function del (target: Array<any> | Object, key: any) {
222-
if (Array.isArray(target) && typeof key === 'number') {
223+
if (Array.isArray(target) && isValidArrayIndex(key)) {
223224
target.splice(key, 1)
224225
return
225226
}

src/shared/util.js

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export function isTrue (v: any): boolean %checks {
1717
export function isFalse (v: any): boolean %checks {
1818
return v === false
1919
}
20+
2021
/**
2122
* Check if value is primitive
2223
*/
@@ -47,6 +48,14 @@ export function isRegExp (v: any): boolean {
4748
return _toString.call(v) === '[object RegExp]'
4849
}
4950

51+
/**
52+
* Check if val is a valid array index.
53+
*/
54+
export function isValidArrayIndex (val: any): boolean {
55+
const n = parseFloat(val)
56+
return n >= 0 && Math.floor(n) === n && isFinite(val)
57+
}
58+
5059
/**
5160
* Convert a value to a string that is actually rendered.
5261
*/

test/unit/features/global-api/set-delete.spec.js

+28-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ describe('Global API: set/delete', () => {
3535
Vue.set(vm.list, 1, 'd')
3636
waitForUpdate(() => {
3737
expect(vm.$el.innerHTML).toBe('<div>0-a</div><div>1-d</div><div>2-c</div>')
38+
Vue.set(vm.list, '2', 'e')
39+
}).then(() => {
40+
expect(vm.$el.innerHTML).toBe('<div>0-a</div><div>1-d</div><div>2-e</div>')
41+
/* eslint-disable no-new-wrappers */
42+
Vue.set(vm.list, new Number(1), 'f')
43+
}).then(() => {
44+
expect(vm.$el.innerHTML).toBe('<div>0-a</div><div>1-f</div><div>2-e</div>')
45+
Vue.set(vm.list, '3g', 'g')
46+
}).then(() => {
47+
expect(vm.$el.innerHTML).toBe('<div>0-a</div><div>1-f</div><div>2-e</div>')
3848
}).then(done)
3949
})
4050

@@ -106,10 +116,26 @@ describe('Global API: set/delete', () => {
106116
Vue.delete(vm.lists, 1)
107117
waitForUpdate(() => {
108118
expect(vm.$el.innerHTML).toBe('<p>A</p><p>C</p>')
109-
Vue.delete(vm.lists, 1)
119+
Vue.delete(vm.lists, NaN)
120+
}).then(() => {
121+
expect(vm.$el.innerHTML).toBe('<p>A</p><p>C</p>')
122+
Vue.delete(vm.lists, -1)
123+
}).then(() => {
124+
expect(vm.$el.innerHTML).toBe('<p>A</p><p>C</p>')
125+
Vue.delete(vm.lists, '1.3')
126+
}).then(() => {
127+
expect(vm.$el.innerHTML).toBe('<p>A</p><p>C</p>')
128+
Vue.delete(vm.lists, true)
129+
}).then(() => {
130+
expect(vm.$el.innerHTML).toBe('<p>A</p><p>C</p>')
131+
Vue.delete(vm.lists, {})
132+
}).then(() => {
133+
expect(vm.$el.innerHTML).toBe('<p>A</p><p>C</p>')
134+
Vue.delete(vm.lists, '1')
110135
}).then(() => {
111136
expect(vm.$el.innerHTML).toBe('<p>A</p>')
112-
Vue.delete(vm.lists, 0)
137+
/* eslint-disable no-new-wrappers */
138+
Vue.delete(vm.lists, new Number(0))
113139
}).then(() => {
114140
expect(vm.$el.innerHTML).toBe('')
115141
}).then(done)

0 commit comments

Comments
 (0)