起因
偶然看到一个有趣的 issue
出于好奇,重新整理了一份测试代码
小结
从结果上来看,给组件设置 props
属性时,如果 type
属性值
- 是
Boolean
类型,如果没有设置default
属性,那么默认返回false
- 是
String
类型,如果没有设置default
属性,那么默认返回undefined
- 其它类型,同理
String
官方文档 components.html#Prop-Validation
源码
src/core/instance/state.js
function initProps (vm: Component, propsOptions: Object) {
const propsData = vm.$options.propsData || {}
const props = vm._props = {}
// cache prop keys so that future props updates can iterate using Array
// instead of dynamic object key enumeration.
const keys = vm.$options._propKeys = []
const isRoot = !vm.$parent
// root instance props should be converted
observerState.shouldConvert = isRoot
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm) // ========= 关键位置
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
if (isReservedProp[key] || config.isReservedAttr(key)) {
warn(
`"${key}" is a reserved attribute and cannot be used as component prop.`,
vm
)
}
defineReactive(props, key, value, () => {
if (vm.$parent && !observerState.isSettingProps) {
warn(
`Avoid mutating a prop directly since the value will be ` +
`overwritten whenever the parent component re-renders. ` +
`Instead, use a data or computed property based on the prop's ` +
`value. Prop being mutated: "${key}"`,
vm
)
}
})
} else {
defineReactive(props, key, value)
}
// static props are already proxied on the component's prototype
// during Vue.extend(). We only need to proxy props defined at
// instantiation here.
if (!(key in vm)) {
proxy(vm, `_props`, key)
}
}
observerState.shouldConvert = true
}
src/core/util/props.js
export function validateProp (
key: string,
propOptions: Object,
propsData: Object,
vm?: Component
): any {
const prop = propOptions[key]
const absent = !hasOwn(propsData, key)
let value = propsData[key]
// handle boolean props
if (isType(Boolean, prop.type)) { // ======= 关键代码
if (
absent &&
!hasOwn(prop, 'default') // 如果不存在 defalut 属性
) {
value = false
} else if (
!isType(String, prop.type) && // 疑问1:这里是否会多此一举,上一层判断已经得出结果
(
value === '' || // 如果传入的值是空字符串,潜意识中 js 的类型转换会转成 false,容易误导
value === hyphenate(key) // 如果传入的值经过 `kebab-case` 转换后和 key 相等,不知道什么场景下会这么用
)
) {
value = true
}
}
// check default value
if (value === undefined) {
value = getPropDefaultValue(vm, prop, key)
// since the default value is a fresh copy,
// make sure to observe it.
const prevShouldConvert = observerState.shouldConvert
observerState.shouldConvert = true
observe(value)
observerState.shouldConvert = prevShouldConvert
}
if (process.env.NODE_ENV !== 'production') {
assertProp(prop, key, value, vm, absent)
}
return value
}
自我解疑
疑问1
src/core/util/props.js
/**
* Use function string name to check built-in types,
* because a simple equality check will fail when running
* across different vms / iframes.
*/
function getType (fn) {
const match = fn && fn.toString().match(/^\s*function (\w+)/)
return match ? match[1] : ''
}
function isType (type, fn) {
if (!Array.isArray(fn)) { // 关键代码:prop.type 可以接收一个数组,例如 [Boolean, String]
return getType(fn) === getType(type)
}
for (let i = 0, len = fn.length; i < len; i++) {
if (getType(fn[i]) === getType(type)) {
return true
}
}
/* istanbul ignore next */
return false
}