/* @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的更多相关文章

  1. vue.js 源代码学习笔记 ----- 工具方法 env

    /* @flow */ /* globals MutationObserver */ import { noop } from 'shared/util' // can we use __proto_ ...

  2. vue.js 源代码学习笔记 ----- 工具方法 option

    /* @flow */ import Vue from '../instance/index' import config from '../config' import { warn } from ...

  3. vue.js 源代码学习笔记 ----- 工具方法 share

    /* @flow */ /** * Convert a value to a string that is actually rendered. { .. } [ .. ] 2 => '' */ ...

  4. vue.js 源代码学习笔记 ----- 工具方法 lang

    /* @flow */ // Object.freeze 使得这个对象不能增加属性, 修改属性, 这样就保证了这个对象在任何时候都是空的 export const emptyObject = Obje ...

  5. vue.js 源代码学习笔记 ----- 工具方法 perf

    import { inBrowser } from './env' export let mark export let measure if (process.env.NODE_ENV !== 'p ...

  6. vue.js 源代码学习笔记 ----- 工具方法 error

    import config from '../config' import { warn } from './debug' import { inBrowser } from './env' // 这 ...

  7. vue.js 源代码学习笔记 ----- 工具方法 debug

    import config from '../config' import { noop } from 'shared/util' let warn = noop let tip = noop let ...

  8. vue.js 源代码学习笔记 ----- instance state

    /* @flow */ import Dep from '../observer/dep' import Watcher from '../observer/watcher' import { set ...

  9. vue.js 源代码学习笔记 ----- observe

    参考 vue 2.2.6版本 /* @flow */ //引入订阅者模式 import Dep from './dep' import { arrayMethods } from './array' ...

随机推荐

  1. 用C#连接SFTP服务器并进行上传下载文件

    1.使用软件连接可采用WinSCP进行: 文件协议选择SFTP,端口号默认22 2.使用C#代码操作 参考:http://www.cnblogs.com/binw/p/4065642.html 主要引 ...

  2. MySQL多版本并发控制机制(MVCC)-源码浅析

    MySQL多版本并发控制机制(MVCC)-源码浅析 前言 作为一个数据库爱好者,自己动手写过简单的SQL解析器以及存储引擎,但感觉还是不够过瘾.<<事务处理-概念与技术>>诚然 ...

  3. 20145328 《Java程序设计》第2周学习总结

    20145328 <Java程序设计>第2周学习总结 教材学习内容总结 掌握了上周没有学会的IDEA的用法 掌握了一些快捷键用法,在用IDEA编写程序的过程中的体验比直接使用cmd进行编写 ...

  4. 20145329 吉东云《Java程序设计》第二周学习总结

    教材学习内容总结 第三章 基础语法 基本类型 1.整数(short.int.long) 2.字节(byte),可表示-128~127的整数 3.浮点数(float/double),主要储存小数数值 4 ...

  5. linux内核第二周

    chapter 1 知识点梳理 (一)计算机是如何工作的?(总结)——三个法宝 ①存储程序计算机工作模型,计算机系统最最基础性的逻辑结构: ②函数调用堆栈,高级语言得以运行的基础,只有机器语言和汇编语 ...

  6. 学Git,用Git ①

    本月开始接触到Git版本管理工具,觉得很有意思,在这里总结一下学习Git的一些心得体会. 要在Mac上完整的使用git进行版本管理,需要熟悉Mac终端操作命令和Git操作命令两种命令,索性两种命令加在 ...

  7. DataReader 连接数据库完整过程和代码(Sql Server)

    数据库名叫:Bu 有个表:A 里面有一列:ID 需要引用 using System.Data.SqlClient; 代码部分如下: SqlConnection sqlCon=new SqlConnec ...

  8. 关于JBoss的一些项目配置

    1. 如何使用 IP:port 的形式访问项目 : [1] 在standalone.xml文件中,查找<interfaces>标签,添加如下节点 : <interface name= ...

  9. Memcached append 命令

    Memcached append 命令用于向已存在 key(键) 的 value(数据值) 后面追加数据 . 语法: append 命令的基本语法格式如下: append key flags expt ...

  10. 手机端页面自适应解决方案—rem布局(进阶版,附源码示例)

    转自:https://segmentfault.com/a/1190000007350680 一年前笔者写了一篇 <手机端页面自适应解决方案—rem布局>,意外受到很多朋友的关注和喜欢.但 ...