Skip to content

Commit 145fed7

Browse files
committed
improve prop default value handling (close vuejs#1032)
1 parent 0d3b264 commit 145fed7

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

src/compiler/compile-props.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,7 @@ function makePropsLinkFn (props) {
106106
options = prop.options
107107
if (prop.raw === null) {
108108
// initialize absent prop
109-
vm._data[path] = options.type === Boolean
110-
? false
111-
: options.hasOwnProperty('default')
112-
? options.default
113-
: undefined
109+
_.initProp(vm, prop, getDefault(options))
114110
} else if (prop.dynamic) {
115111
// dynamic prop
116112
if (vm._context) {
@@ -139,3 +135,34 @@ function makePropsLinkFn (props) {
139135
}
140136
}
141137
}
138+
139+
/**
140+
* Get the default value of a prop.
141+
*
142+
* @param {Object} options
143+
* @return {*}
144+
*/
145+
146+
function getDefault (options) {
147+
// absent boolean value
148+
if (options.type === Boolean) {
149+
return false
150+
}
151+
// no default, return undefined
152+
if (!options.hasOwnProperty('default')) {
153+
return
154+
}
155+
var def = options.default
156+
// warn against non-factory defaults for Object & Array
157+
if (_.isObject(def)) {
158+
process.env.NODE_ENV !== 'production' && _.warn(
159+
'Object/Array as default prop values will be shared ' +
160+
'across multiple instances. Use a factory function ' +
161+
'to return the default value instead.'
162+
)
163+
}
164+
// call factory function for non-Function types
165+
return typeof def === 'function' && options.type !== Function
166+
? def()
167+
: def
168+
}

test/unit/specs/compiler/compile_spec.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,15 @@ if (_.inBrowser) {
167167
{
168168
name: 'boolean-absent',
169169
type: Boolean
170+
},
171+
{
172+
name: 'factory',
173+
type: Object,
174+
default: function () {
175+
return {
176+
a: 123
177+
}
178+
}
170179
}
171180
].map(function (p) {
172181
return typeof p === 'string' ? { name: p } : p
@@ -219,7 +228,7 @@ if (_.inBrowser) {
219228
expect(args[3]).toBe(def)
220229
// literal and one time should've been set on the _data
221230
// and numbers should be casted
222-
expect(Object.keys(vm._data).length).toBe(8)
231+
expect(Object.keys(vm._data).length).toBe(9)
223232
expect(vm.a).toBe(1)
224233
expect(vm._data.a).toBe(1)
225234
expect(vm.someOtherAttr).toBe(2)
@@ -228,10 +237,16 @@ if (_.inBrowser) {
228237
expect(vm._data.onetime).toBe('from parent: a')
229238
expect(vm.booleanLiteral).toBe('from parent: true')
230239
expect(vm._data.booleanLiteral).toBe('from parent: true')
240+
expect(vm.camelCase).toBe('hi')
231241
expect(vm._data.camelCase).toBe('hi')
242+
expect(vm.defaultValue).toBe(123)
232243
expect(vm._data.defaultValue).toBe(123)
244+
expect(vm.boolean).toBe(true)
233245
expect(vm._data.boolean).toBe(true)
246+
expect(vm.booleanAbsent).toBe(false)
234247
expect(vm._data.booleanAbsent).toBe(false)
248+
expect(vm.factory).toBe(vm._data.factory)
249+
expect(vm.factory.a).toBe(123)
235250
})
236251

237252
it('props on root instance', function () {

test/unit/specs/directives/prop_spec.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,24 @@ if (_.inBrowser) {
184184
expect(hasWarned(_, 'Props will not be compiled if no `el`')).toBe(true)
185185
})
186186

187+
it('warn object/array default values', function () {
188+
new Vue({
189+
el: el,
190+
props: {
191+
arr: {
192+
type: Array,
193+
default: []
194+
},
195+
obj: {
196+
type: Object,
197+
default: {}
198+
}
199+
}
200+
})
201+
expect(hasWarned(_, 'Use a factory function to return the default value')).toBe(true)
202+
expect(_.warn.calls.count()).toBe(2)
203+
})
204+
187205
it('teardown', function (done) {
188206
var vm = new Vue({
189207
el: el,

0 commit comments

Comments
 (0)