Skip to content

Commit 216e398

Browse files
committed
observer rewrite
1 parent 070d5c0 commit 216e398

File tree

2 files changed

+98
-111
lines changed

2 files changed

+98
-111
lines changed

src/observer.js

Lines changed: 97 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -86,26 +86,14 @@ for (var method in extensions) {
8686
def(ArrayProxy, method, extensions[method], !hasProto)
8787
}
8888

89-
/**
90-
* Watch an object based on type
91-
*/
92-
function watch (obj, path, observer) {
93-
var type = typeOf(obj)
94-
if (type === 'Object') {
95-
watchObject(obj, path, observer)
96-
} else if (type === 'Array') {
97-
watchArray(obj, path, observer)
98-
}
99-
}
100-
10189
/**
10290
* Watch an Object, recursive.
10391
*/
10492
function watchObject (obj, path, observer) {
10593
for (var key in obj) {
10694
var keyPrefix = key.charAt(0)
10795
if (keyPrefix !== '$' && keyPrefix !== '_') {
108-
bind(obj, key, path, observer)
96+
convert(obj, key, observer)
10997
}
11098
}
11199
}
@@ -131,33 +119,34 @@ function watchArray (arr, path, observer) {
131119
* so it emits get/set events.
132120
* Then watch the value itself.
133121
*/
134-
function bind (obj, key, path, observer) {
122+
function convert (obj, key, observer) {
135123
var val = obj[key],
136-
watchable = isWatchable(val),
137-
values = observer.values,
138-
fullKey = (path ? path + '.' : '') + key
139-
values[fullKey] = val
124+
values = observer.values
125+
values[key] = val
140126
// emit set on bind
141127
// this means when an object is observed it will emit
142128
// a first batch of set events.
143-
observer.emit('set', fullKey, val)
129+
observer.emit('set', key, val)
144130
Object.defineProperty(obj, key, {
145131
enumerable: true,
146132
get: function () {
133+
var value = values[key]
147134
// only emit get on tip values
148-
if (depsOb.active && !watchable) {
149-
observer.emit('get', fullKey)
135+
if (depsOb.active && !isWatchable(value)) {
136+
observer.emit('get', key)
150137
}
151-
return values[fullKey]
138+
return value
152139
},
153140
set: function (newVal) {
154-
values[fullKey] = newVal
155-
ensurePaths(key, newVal, values)
156-
observer.emit('set', fullKey, newVal)
157-
watch(newVal, fullKey, observer)
141+
var oldVal = values[key]
142+
unobserve(oldVal, key, observer)
143+
values[key] = newVal
144+
ensurePaths('', newVal, oldVal)
145+
observer.emit('set', key, newVal)
146+
observe(newVal, key, observer)
158147
}
159148
})
160-
watch(val, fullKey, observer)
149+
observe(val, key, observer)
161150
}
162151

163152
/**
@@ -175,14 +164,17 @@ function isWatchable (obj) {
175164
* the watch conversion and simply emit set event for
176165
* all of its properties.
177166
*/
178-
function emitSet (obj, observer, set) {
179-
if (typeOf(obj) === 'Array') {
180-
set('length', obj.length)
181-
} else {
182-
var key, val, values = observer.values
183-
for (key in observer.values) {
184-
val = values[key]
185-
set(key, val)
167+
function emitSet (obj) {
168+
var type = typeOf(obj),
169+
emitter = obj.__observer__
170+
if (type === 'Array') {
171+
emitter.emit('set', 'length', obj.length)
172+
} else if (type === 'Object') {
173+
var key, val
174+
for (key in obj) {
175+
val = obj[key]
176+
emitter.emit('set', key, val)
177+
emitSet(val)
186178
}
187179
}
188180
}
@@ -194,10 +186,10 @@ function emitSet (obj, observer, set) {
194186
* any given path.
195187
*/
196188
function ensurePaths (key, val, paths) {
197-
key += '.'
189+
key = key ? key + '.' : ''
198190
for (var path in paths) {
199-
if (!path.indexOf(key)) {
200-
ensurePath(val, path.replace(key, ''))
191+
if (!key || !path.indexOf(key)) {
192+
ensurePath(val, key ? path.replace(key, '') : path)
201193
}
202194
}
203195
}
@@ -222,68 +214,74 @@ function ensurePath (obj, key) {
222214
return obj[sec]
223215
}
224216

225-
module.exports = {
226-
227-
// used in v-repeat
228-
watchArray: watchArray,
229-
ensurePath: ensurePath,
230-
ensurePaths: ensurePaths,
231-
232-
/**
233-
* Observe an object with a given path,
234-
* and proxy get/set/mutate events to the provided observer.
235-
*/
236-
observe: function (obj, rawPath, observer) {
237-
if (isWatchable(obj)) {
238-
var path = rawPath + '.',
239-
ob, alreadyConverted = !!obj.__observer__
240-
if (!alreadyConverted) {
241-
def(obj, '__observer__', new Emitter())
242-
}
243-
ob = obj.__observer__
244-
ob.values = ob.values || utils.hash()
245-
var proxies = observer.proxies[path] = {
246-
get: function (key) {
247-
observer.emit('get', path + key)
248-
},
249-
set: function (key, val) {
250-
observer.emit('set', path + key, val)
251-
},
252-
mutate: function (key, val, mutation) {
253-
// if the Array is a root value
254-
// the key will be null
255-
var fixedPath = key ? path + key : rawPath
256-
observer.emit('mutate', fixedPath, val, mutation)
257-
// also emit set for Array's length when it mutates
258-
var m = mutation.method
259-
if (m !== 'sort' && m !== 'reverse') {
260-
observer.emit('set', fixedPath + '.length', val.length)
261-
}
262-
}
263-
}
264-
ob
265-
.on('get', proxies.get)
266-
.on('set', proxies.set)
267-
.on('mutate', proxies.mutate)
268-
if (alreadyConverted) {
269-
emitSet(obj, ob, proxies.set)
270-
} else {
271-
watch(obj, null, ob)
217+
/**
218+
* Observe an object with a given path,
219+
* and proxy get/set/mutate events to the provided observer.
220+
*/
221+
function observe (obj, rawPath, observer) {
222+
if (!isWatchable(obj)) return
223+
var path = rawPath ? rawPath + '.' : '',
224+
ob, alreadyConverted = !!obj.__observer__
225+
if (!alreadyConverted) {
226+
def(obj, '__observer__', new Emitter())
227+
}
228+
ob = obj.__observer__
229+
ob.values = ob.values || utils.hash()
230+
observer.proxies = observer.proxies || {}
231+
var proxies = observer.proxies[path] = {
232+
get: function (key) {
233+
observer.emit('get', path + key)
234+
},
235+
set: function (key, val) {
236+
observer.emit('set', path + key, val)
237+
},
238+
mutate: function (key, val, mutation) {
239+
// if the Array is a root value
240+
// the key will be null
241+
var fixedPath = key ? path + key : rawPath
242+
observer.emit('mutate', fixedPath, val, mutation)
243+
// also emit set for Array's length when it mutates
244+
var m = mutation.method
245+
if (m !== 'sort' && m !== 'reverse') {
246+
observer.emit('set', fixedPath + '.length', val.length)
272247
}
273248
}
274-
},
275-
276-
/**
277-
* Cancel observation, turn off the listeners.
278-
*/
279-
unobserve: function (obj, path, observer) {
280-
if (!obj || !obj.__observer__) return
281-
path = path + '.'
282-
var proxies = observer.proxies[path]
283-
obj.__observer__
284-
.off('get', proxies.get)
285-
.off('set', proxies.set)
286-
.off('mutate', proxies.mutate)
287-
observer.proxies[path] = null
288249
}
250+
ob
251+
.on('get', proxies.get)
252+
.on('set', proxies.set)
253+
.on('mutate', proxies.mutate)
254+
if (alreadyConverted) {
255+
emitSet(obj)
256+
} else {
257+
var type = typeOf(obj)
258+
if (type === 'Object') {
259+
watchObject(obj, null, ob)
260+
} else if (type === 'Array') {
261+
watchArray(obj, null, ob)
262+
}
263+
}
264+
}
265+
266+
/**
267+
* Cancel observation, turn off the listeners.
268+
*/
269+
function unobserve (obj, path, observer) {
270+
if (!obj || !obj.__observer__) return
271+
path = path + '.'
272+
var proxies = observer.proxies[path]
273+
obj.__observer__
274+
.off('get', proxies.get)
275+
.off('set', proxies.set)
276+
.off('mutate', proxies.mutate)
277+
observer.proxies[path] = null
278+
}
279+
280+
module.exports = {
281+
observe : observe,
282+
unobserve : unobserve,
283+
ensurePath : ensurePath,
284+
ensurePaths : ensurePaths,
285+
// used in v-repeat
286+
watchArray : watchArray,
289287
}

test/unit/specs/observer.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@ describe('UNIT: Observer', function () {
88

99
it('should not watch a ViewModel instance', function () {
1010
var obj = new Vue(), ob = new Emitter()
11-
ob.proxies = {}
1211
Observer.observe(obj, 'test', ob)
1312
assert.notOk(obj.__observer__)
1413
})
1514

1615
it('should attach hidden observer and values to the object', function () {
1716
var obj = {}, ob = new Emitter()
18-
ob.proxies = {}
1917
Observer.observe(obj, 'test', ob)
2018
assert.ok(obj.__observer__ instanceof Emitter)
2119
assert.ok(obj.__observer__.values)
@@ -55,7 +53,6 @@ describe('UNIT: Observer', function () {
5553
it('should emit set when first observing', function () {
5654
var obj = { a: 1, b: { c: 2} },
5755
ob = new Emitter(), i = 0
58-
ob.proxies = {}
5956
var expects = [
6057
{ key: 'test.a', val: obj.a },
6158
{ key: 'test.b', val: obj.b },
@@ -76,8 +73,6 @@ describe('UNIT: Observer', function () {
7673
ob1 = new Emitter(),
7774
ob2 = new Emitter(),
7875
i = 0
79-
ob1.proxies = {}
80-
ob2.proxies = {}
8176
Observer.observe(obj, 'test', ob1) // watch first time
8277

8378
var expects = [
@@ -86,6 +81,7 @@ describe('UNIT: Observer', function () {
8681
{ key: 'test.b.c', val: obj.b.c }
8782
]
8883
ob2.on('set', function (key, val) {
84+
console.log(key)
8985
var exp = expects[i]
9086
assert.strictEqual(key, exp.key)
9187
assert.strictEqual(val, exp.val)
@@ -101,7 +97,6 @@ describe('UNIT: Observer', function () {
10197

10298
var arr = [],
10399
ob = new Emitter()
104-
ob.proxies = {}
105100
Observer.observe(arr, 'test', ob)
106101

107102
it('should attach the hidden observer', function () {
@@ -371,8 +366,6 @@ describe('UNIT: Observer', function () {
371366
var ob1 = new Emitter(),
372367
ob2 = new Emitter(),
373368
obj = {a:1}
374-
ob1.proxies = {}
375-
ob2.proxies = {}
376369
Observer.observe(obj, 'test', ob1)
377370
Observer.observe(obj, 'test', ob2)
378371

@@ -399,8 +392,6 @@ describe('UNIT: Observer', function () {
399392
var ob1 = new Emitter(),
400393
ob2 = new Emitter(),
401394
obj = {a:1}
402-
ob1.proxies = {}
403-
ob2.proxies = {}
404395
Observer.observe(obj, 'test', ob1)
405396
Observer.observe(obj, 'test', ob2)
406397
Observer.unobserve(obj, 'test', ob1)
@@ -470,7 +461,6 @@ describe('UNIT: Observer', function () {
470461
i = 0,
471462
obj = opts.obj,
472463
expects = opts.expects
473-
ob.proxies = {}
474464
Observer.observe(obj, opts.path, ob)
475465
ob.on('set', function (key, val) {
476466
var expect = expects[i]
@@ -499,7 +489,6 @@ describe('UNIT: Observer', function () {
499489
i = 0,
500490
obj = opts.obj,
501491
expects = opts.expects
502-
ob.proxies = {}
503492
Observer.observe(obj, opts.path, ob)
504493
ob.on('get', function (key) {
505494
var expected = expects[i]

0 commit comments

Comments
 (0)