Skip to content

Commit 0b1be55

Browse files
committed
Added support for properties which were created with defineProperty outside of vue
1 parent 6ce6e0c commit 0b1be55

File tree

2 files changed

+84
-7
lines changed

2 files changed

+84
-7
lines changed

src/observer/index.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,11 @@ function copyAugment (target, src, keys) {
172172

173173
function defineReactive (obj, key, val) {
174174
var dep = new Dep()
175-
var childOb = Observer.create(val)
175+
176+
var property = Object.getOwnPropertyDescriptor(obj, key)
177+
var getter = (property && property.get) || function () { return val }
178+
var setter = (property && property.set) || function (v) { val = v }
179+
var childOb = Observer.create(getter())
176180
Object.defineProperty(obj, key, {
177181
enumerable: true,
178182
configurable: true,
@@ -182,18 +186,18 @@ function defineReactive (obj, key, val) {
182186
if (childOb) {
183187
childOb.dep.depend()
184188
}
185-
if (_.isArray(val)) {
186-
for (var e, i = 0, l = val.length; i < l; i++) {
187-
e = val[i]
189+
if (_.isArray(getter())) {
190+
for (var e, i = 0, l = getter().length; i < l; i++) {
191+
e = getter()[i]
188192
e && e.__ob__ && e.__ob__.dep.depend()
189193
}
190194
}
191195
}
192-
return val
196+
return getter()
193197
},
194198
set: function metaSetter (newVal) {
195-
if (newVal === val) return
196-
val = newVal
199+
if (newVal === getter()) return
200+
setter(newVal)
197201
childOb = Observer.create(newVal)
198202
dep.notify()
199203
}

test/unit/specs/observer/observer_spec.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,35 @@ describe('Observer', function () {
3838
expect(ob2).toBe(ob)
3939
})
4040

41+
it('create on already observed object', function () {
42+
// on object
43+
var obj = {}
44+
var val = 0
45+
Object.defineProperty(obj, 'a', {
46+
configurable: true,
47+
enumerable: true,
48+
get: function () {
49+
return val
50+
},
51+
set: function (v) {
52+
val = v
53+
}
54+
})
55+
56+
var ob = Observer.create(obj)
57+
expect(ob instanceof Observer).toBe(true)
58+
expect(ob.value).toBe(obj)
59+
expect(obj.__ob__).toBe(ob)
60+
61+
// should return existing ob on already observed objects
62+
var ob2 = Observer.create(obj)
63+
expect(ob2).toBe(ob)
64+
65+
// should call underlying setter
66+
obj.a = 10
67+
expect(val).toBe(10)
68+
})
69+
4170
it('create on array', function () {
4271
// on object
4372
var arr = [{}, {}]
@@ -82,6 +111,50 @@ describe('Observer', function () {
82111
expect(watcher.update.calls.count()).toBe(3)
83112
})
84113

114+
it('observing object prop change on defined property', function () {
115+
var obj = { }
116+
var val = { b: 2 }
117+
Object.defineProperty(obj, 'a', {
118+
configurable: true,
119+
enumerable: true,
120+
get: function () {
121+
return val
122+
},
123+
set: function (v) {
124+
val = v
125+
}
126+
})
127+
128+
Observer.create(obj)
129+
// mock a watcher!
130+
var watcher = {
131+
deps: [],
132+
addDep: function (dep) {
133+
this.deps.push(dep)
134+
dep.addSub(this)
135+
},
136+
update: jasmine.createSpy()
137+
}
138+
// collect dep
139+
Dep.target = watcher
140+
obj.a.b
141+
Dep.target = null
142+
expect(watcher.deps.length).toBe(3) // obj.a + a.b + b
143+
obj.a.b = 3
144+
expect(watcher.update.calls.count()).toBe(1)
145+
// swap object
146+
obj.a = { b: 4 }
147+
expect(watcher.update.calls.count()).toBe(2)
148+
watcher.deps = []
149+
Dep.target = watcher
150+
obj.a.b
151+
Dep.target = null
152+
expect(watcher.deps.length).toBe(3)
153+
// set on the swapped object
154+
obj.a.b = 5
155+
expect(watcher.update.calls.count()).toBe(3)
156+
})
157+
85158
it('observing set/delete', function () {
86159
var obj = { a: 1 }
87160
var ob = Observer.create(obj)

0 commit comments

Comments
 (0)