Skip to content

Commit e314db1

Browse files
flytreeleftyyx990803
flytreeleft
authored andcommitted
Fix error when recursively traverse an object (vuejs#2686)
* fix 'Maximum call stack size exceeded' when recursively traverse an object * remove semicolon * simplify assignment expression * add unit test for circular references detected in Watcher#traverse
1 parent cfad423 commit e314db1

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

src/watcher.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,14 +334,25 @@ Watcher.prototype.teardown = function () {
334334
* @param {*} val
335335
*/
336336

337-
function traverse (val) {
337+
function traverse (val, walkedObjs) {
338338
var i, keys
339+
340+
walkedObjs = walkedObjs || {}
339341
if (isArray(val)) {
340342
i = val.length
341-
while (i--) traverse(val[i])
343+
while (i--) traverse(val[i], walkedObjs)
342344
} else if (isObject(val)) {
345+
if (val.__ob__) {
346+
var depId = val.__ob__.dep.id
347+
if (walkedObjs[depId]) {
348+
return
349+
} else {
350+
walkedObjs[depId] = true
351+
}
352+
}
353+
343354
keys = Object.keys(val)
344355
i = keys.length
345-
while (i--) traverse(val[keys[i]])
356+
while (i--) traverse(val[keys[i]], walkedObjs)
346357
}
347358
}

test/unit/specs/watcher_spec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,23 @@ describe('Watcher', function () {
286286
})
287287
})
288288

289+
it('deep watch with circular references', function (done) {
290+
new Watcher(vm, 'b', spy, {
291+
deep: true
292+
})
293+
Vue.set(vm.b, '_', vm.b)
294+
nextTick(function () {
295+
expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
296+
expect(spy.calls.count()).toBe(1)
297+
vm.b._.c = 1
298+
nextTick(function () {
299+
expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
300+
expect(spy.calls.count()).toBe(2)
301+
done()
302+
})
303+
})
304+
})
305+
289306
it('fire change for prop addition/deletion in non-deep mode', function (done) {
290307
new Watcher(vm, 'b', spy)
291308
Vue.set(vm.b, 'e', 123)

0 commit comments

Comments
 (0)