vue.js 源代码学习笔记 ----- 工具方法 props
/* @flow */
import { hasOwn, isObject, isPlainObject, capitalize, hyphenate } from 'shared/util'
import { observe, observerState } from '../observer/index'
import { warn } from './debug'
type PropOptions = {
type: Function | Array<Function> | null,
default: any,
required: ?boolean,
validator: ?Function
};
export function validateProp (
key: string,
propOptions: Object,
propsData: Object,
vm?: Component
): any {
const prop = propOptions[key]
//如果 key不在 propsData中
const absent = !hasOwn(propsData, key)
let value = propsData[key]
// handle boolean props
//如果 传入的属性是 bool类型
if (isType(Boolean, prop.type)) {
if (absent && !hasOwn(prop, 'default')) {
value = false
} else if (!isType(String, prop.type) && (value === '' || value === hyphenate(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
}
/**
* Get the default value of a prop.
*/
function getPropDefaultValue (vm: ?Component, prop: PropOptions, key: string): any {
// no default, return undefined
if (!hasOwn(prop, 'default')) {
return undefined
}
const def = prop.default
// warn against non-factory defaults for Object & Array
if (process.env.NODE_ENV !== 'production' && isObject(def)) {
warn(
'Invalid default value for prop "' + key + '": ' +
'Props with type Object/Array must use a factory function ' +
'to return the default value.',
vm
)
}
// the raw prop value was also undefined from previous render,
// return previous default value to avoid unnecessary watcher trigger
if (vm && vm.$options.propsData &&
vm.$options.propsData[key] === undefined &&
vm._props[key] !== undefined) {
return vm._props[key]
}
// call factory function for non-Function types
// a value is Function if its prototype is function even across different execution context
return typeof def === 'function' && getType(prop.type) !== 'Function'
? def.call(vm)
: def
}
/**
* Assert whether a prop is valid.
*/
function assertProp (
prop: PropOptions,
name: string,
value: any,
vm: ?Component,
absent: boolean
) {
if (prop.required && absent) {
warn(
'Missing required prop: "' + name + '"',
vm
)
return
}
if (value == null && !prop.required) {
return
}
let type = prop.type
let valid = !type || type === true
const expectedTypes = []
if (type) {
if (!Array.isArray(type)) {
type = [type]
}
for (let i = 0; i < type.length && !valid; i++) {
const assertedType = assertType(value, type[i])
expectedTypes.push(assertedType.expectedType || '')
valid = assertedType.valid
}
}
if (!valid) {
warn(
'Invalid prop: type check failed for prop "' + name + '".' +
' Expected ' + expectedTypes.map(capitalize).join(', ') +
', got ' + Object.prototype.toString.call(value).slice(8, -1) + '.',
vm
)
return
}
const validator = prop.validator
if (validator) {
if (!validator(value)) {
warn(
'Invalid prop: custom validator check failed for prop "' + name + '".',
vm
)
}
}
}
/**
* Assert the type of a value
*/
function assertType (value: any, type: Function): {
valid: boolean,
expectedType: ?string
} {
let valid
let expectedType = getType(type)
if (expectedType === 'String') {
valid = typeof value === (expectedType = 'string')
} else if (expectedType === 'Number') {
valid = typeof value === (expectedType = 'number')
} else if (expectedType === 'Boolean') {
valid = typeof value === (expectedType = 'boolean')
} else if (expectedType === 'Function') {
valid = typeof value === (expectedType = 'function')
} else if (expectedType === 'Object') {
valid = isPlainObject(value)
} else if (expectedType === 'Array') {
valid = Array.isArray(value)
} else {
valid = value instanceof type
}
return {
valid,
expectedType
}
}
/**
* Use function string name to check built-in types,
* because a simple equality check will fail when running
* across different vms / iframes.
Number.toString()
"function Number() { [native code] }"
Boolean.toString()
"function Boolean() {[native code]}" toString 深入研究*/
function getType (fn) {
const match = fn && fn.toString().match(/^\s*function (\w+)/)
return match && match[1]
}
//如果传入的是数组, 只要数组中有一个是type, 就判断为相等, 因为如果type: [Boolean, Fuction, Number] 说明这个组件的属性满足其中一个即可
function isType (type, fn) {
if (!Array.isArray(fn)) {
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
}
vue.js 源代码学习笔记 ----- 工具方法 props的更多相关文章
- vue.js 源代码学习笔记 ----- 工具方法 env
/* @flow */ /* globals MutationObserver */ import { noop } from 'shared/util' // can we use __proto_ ...
- vue.js 源代码学习笔记 ----- 工具方法 option
/* @flow */ import Vue from '../instance/index' import config from '../config' import { warn } from ...
- vue.js 源代码学习笔记 ----- 工具方法 share
/* @flow */ /** * Convert a value to a string that is actually rendered. { .. } [ .. ] 2 => '' */ ...
- vue.js 源代码学习笔记 ----- 工具方法 lang
/* @flow */ // Object.freeze 使得这个对象不能增加属性, 修改属性, 这样就保证了这个对象在任何时候都是空的 export const emptyObject = Obje ...
- vue.js 源代码学习笔记 ----- 工具方法 perf
import { inBrowser } from './env' export let mark export let measure if (process.env.NODE_ENV !== 'p ...
- vue.js 源代码学习笔记 ----- 工具方法 error
import config from '../config' import { warn } from './debug' import { inBrowser } from './env' // 这 ...
- vue.js 源代码学习笔记 ----- 工具方法 debug
import config from '../config' import { noop } from 'shared/util' let warn = noop let tip = noop let ...
- vue.js 源代码学习笔记 ----- instance state
/* @flow */ import Dep from '../observer/dep' import Watcher from '../observer/watcher' import { set ...
- vue.js 源代码学习笔记 ----- observe
参考 vue 2.2.6版本 /* @flow */ //引入订阅者模式 import Dep from './dep' import { arrayMethods } from './array' ...
随机推荐
- Cisco 交换Trunk配置
交换Trunk配置 #进入直连端口下 config)#int f0/1 #配置trunk封装协议 config)#switchport trunk encapsulation dot1q #配置为tr ...
- 解读:CombineFileInputFormat类
MR-Job默认的输入格式FileInputFormat为每一个小文件生成一个切片.CombineFileInputFormat通过将多个“小文件”合并为一个"切片"(在形成切片的 ...
- POJ_1159 Palindrome (线性动态规划+滚动数组)
题意是说,给定一个字符串,问至少还需要插入多少个字符才能使得该字符串成为回文字符串. 这道题一开始做的时候用了一个简单的动态规划,开了一个5000*5000的数组,用递归形式实现,代码如下: 其中d[ ...
- 浅析ProcessBuilder
概述 ProcessBuilder类是J2SE 1.5在java.lang中新添加的一个新类,此类用于创建操作系统进程,它提供一种启动和管理进程(也就是应用程序)的方法.在J2SE 1.5之前,都是由 ...
- 异步:asyncio和aiohttp的一些应用(1)
1. asyncio 1.1asyncio/await 用法 async/await 是 python3.5中新加入的特性, 将异步从原来的yield 写法中解放出来,变得更加直观. 在3.5之前,如 ...
- 解题报告:hdu2191汶川地震 - 多重背包模板
2017-09-03 17:01:36 writer:pprp 这是一道多重背包裸题 - 记得是从右向左进行,还有几点需要注意啊,都在代码中表示出来了 代码如下: /* @theme:hdu2191 ...
- linux主机之间无密钥ssh访问
ssh-keygen -t rsa ssh-copy-id -i /root/.ssh/id-rsa.pub root@10.0.0.109 # 实现和109互通 vim /etc/hosts DNS ...
- hdu 4857 逃生 拓扑排序+逆向建图
逃生 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Descr ...
- Java默认提供的线程池
Java的线程池都是通过ThreadPoolExecutor来构建. public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, ...
- 定时模块app_timer用法及常见问题—nRF5 SDK模块系列二
app_timer是大家经常用到的一个库,app_timer的功能就是定时,也就是说,你在某一时刻启动一个app timer并设定超时时间,超时时间一到,app_timer就会回调timeout ha ...