Skip to content

Commit 7953f5e

Browse files
committed
Added config option for working with computed properties; also changed the implementation to no longer do function calls for normal attributes
1 parent 0b1be55 commit 7953f5e

File tree

4 files changed

+48
-29
lines changed

4 files changed

+48
-29
lines changed

src/config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ module.exports = {
3030

3131
warnExpressionErrors: true,
3232

33+
/**
34+
* Whether or not to handle fully object properties which
35+
* are already backed by getters and seters. Depending on
36+
* use case and environment, this might introduce non-neglible
37+
* performance penalties.
38+
*/
39+
convertAllProperties: true,
40+
3341
/**
3442
* Internal flag to indicate the delimiters have been
3543
* changed.

src/observer/index.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var _ = require('../util')
2+
var config = require('../config')
23
var Dep = require('./dep')
34
var arrayMethods = require('./array')
45
var arrayKeys = Object.getOwnPropertyNames(arrayMethods)
@@ -173,10 +174,21 @@ function copyAugment (target, src, keys) {
173174
function defineReactive (obj, key, val) {
174175
var dep = new Dep()
175176

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())
177+
var target = {
178+
val: val
179+
}
180+
181+
if (config.convertAllProperties) {
182+
var property = Object.getOwnPropertyDescriptor(obj, key)
183+
if (property && property.get && property.set) {
184+
Object.defineProperty(target, 'val', {
185+
get: property.get.bind(obj),
186+
set: property.set.bind(obj)
187+
})
188+
}
189+
}
190+
191+
var childOb = Observer.create(target.val)
180192
Object.defineProperty(obj, key, {
181193
enumerable: true,
182194
configurable: true,
@@ -186,18 +198,18 @@ function defineReactive (obj, key, val) {
186198
if (childOb) {
187199
childOb.dep.depend()
188200
}
189-
if (_.isArray(getter())) {
190-
for (var e, i = 0, l = getter().length; i < l; i++) {
191-
e = getter()[i]
201+
if (_.isArray(target.val)) {
202+
for (var e, i = 0, l = target.val.length; i < l; i++) {
203+
e = target.val[i]
192204
e && e.__ob__ && e.__ob__.dep.depend()
193205
}
194206
}
195207
}
196-
return getter()
208+
return target.val
197209
},
198210
set: function metaSetter (newVal) {
199-
if (newVal === getter()) return
200-
setter(newVal)
211+
if (newVal === target.val) return
212+
target.val = newVal
201213
childOb = Observer.create(newVal)
202214
dep.notify()
203215
}

test/unit/lib/util.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@ var scope = typeof window === 'undefined'
22
? global
33
: window
44

5+
// Some versions of phantomjs doesn't have bind defined.
6+
// See https://github.com/ariya/phantomjs/issues/10522
7+
Function.prototype.bind = Function.prototype.bind || function (thisp) {
8+
var fn = this;
9+
return function () {
10+
return fn.apply(thisp, arguments);
11+
};
12+
};
13+
514
scope.hasWarned = function (_, msg, silent) {
615
var count = _.warn.calls.count()
716
while (count--) {

test/unit/specs/observer/observer_spec.js

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,16 @@ describe('Observer', function () {
112112
})
113113

114114
it('observing object prop change on defined property', function () {
115-
var obj = { }
116-
var val = { b: 2 }
115+
var obj = { val: 2 }
117116
Object.defineProperty(obj, 'a', {
118117
configurable: true,
119118
enumerable: true,
120119
get: function () {
121-
return val
120+
return this.val
122121
},
123122
set: function (v) {
124-
val = v
123+
this.val = v
124+
return this.val
125125
}
126126
})
127127

@@ -137,22 +137,12 @@ describe('Observer', function () {
137137
}
138138
// collect dep
139139
Dep.target = watcher
140-
obj.a.b
140+
expect(obj.a).toBe(2) // Make sure 'this' is preserved
141141
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)
142+
obj.a = 3
143+
expect(obj.val).toBe(3) // make sure 'setter' was called
144+
obj.val = 5
145+
expect(obj.a).toBe(5) // make sure 'getter' was called
156146
})
157147

158148
it('observing set/delete', function () {

0 commit comments

Comments
 (0)