从vue源码看props
前言
平时写vue的时候知道props
有很多种用法,今天我们来看看vue内部是怎么处理props
中那么多的用法的。
vue提供的props的用法
1. 数组形式
props: ['name', 'value']
2. 对象形式
对象形式内部也提供了三种写法:
props: {
// 基础的类型检查
name: String,
// 多个可能的类型
value: [String, Number],
// 对象形式
id: {
type: Number,
required: true
}
}
props实现的原理
function normalizeProps (options: Object, vm: ?Component) {
const props = options.props
if (!props) return
const res = {}
let i, val, name
if (Array.isArray(props)) {
...
} else if (isPlainObject(props)) {
...
} else if (process.env.NODE_ENV !== 'production') {
...
}
options.props = res
}
normalizeProps
函数就是vue实际处理props
的地方,从函数名的翻译我们可以看出该函数的功能就是标准化props
的值。该函数主要分成3部分:① 从options
对象中获取props
的值并且定义一个res空对象;②几个if ... else
,分别根据props
值的不同类型来处理res
对象;③ 用处理后的res
对象覆盖原来options
对象的props
属性的值。
接下来看看那几个if ... else
的代码:
if (Array.isArray(props)) {
i = props.length
while (i--) {
val = props[i]
if (typeof val === 'string') {
name = camelize(val)
res[name] = { type: null }
} else if (process.env.NODE_ENV !== 'production') {
warn('props must be strings when using array syntax.')
}
}
}
这个代码实际就是处理props的值为数组的情况,例如: props: ['name', 'value']
。使用while遍历该数组,如果数组内元素的类型不是字符串并且不是生产环境,那么就抛错:‘props的值类型为数组时,数组里面的元素的类型就必须是字符串’。如果是字符串的情况下,使用camelize
函数处理一下val
的值,并且赋值给name
变量。这里的camelize
函数的实际作用就是将'-'
转换为驼峰。camelize
函数具体的实现方式在后面分析。然后在res
对象上面添加一个为name
变量的属性,该属性的值为空对象 { type: null }
。
props: ['name', 'value']
这种写法经过上面的处理后就会变成了下面这样:
props: {
name: {
type: null
},
value: {
type: null
}
}
接下来看看下面这个else if(isPlainObject(props))
,这里的isPlainObject
函数实际就是返回props
的值是否为object
,isPlainObject
函数的具体实现我们也在后面分析。
else if (isPlainObject(props)) {
for (const key in props) {
val = props[key]
name = camelize(key)
res[name] = isPlainObject(val)
? val
: { type: val }
}
}
使用for...in
遍历props对象,和上面一样使用camelize
函数将'-'
转换为驼峰。这里有个三目运算:
res[name] = isPlainObject(val) ? val : { type: val }
判断了一下val
如果是object
,那么在res对象上面添加一个为name变量的属性,并且将该属性的值设置为val。这个其实就是处理下面这种props的写法:
props: {
// 对象形式
id: {
type: Number,
required: true
}
}
如果val
不是object
,那么也在res对象上面添加一个为name变量的属性,并且将该属性的值设置为{ type: val }。这个其实就是处理下面这种props的写法:
props: {
// 基础的类型检查
name: String,
// 多个可能的类型
value: [String, Number],
}
经过处理后props会变成了下面这样:
props: {
name: {
type: String
},
value: {
type: [String, Number]
}
}
所以不管我们使用vue提供的props
哪种写法,最终vue都会帮我们转换成下面这种类型:
props: {
name: {
...,
type: '类型'
}
}
接下来看看上面提到的util函数isPlainObject
,先把源码贴出来。
const _toString = Object.prototype.toString
export function isPlainObject (obj: any): boolean {
return _toString.call(obj) === '[object Object]'
}
其实Object.prototype.toString.call(obj)
的值为obj对象的类型。例如:
Object.prototype.toString.call({a: 1}) // [object Object]
Object.prototype.toString.call(new Date) // [object Date]
Object.prototype.toString.call([1]) // [object Array]
Object.prototype.toString.call(null) // [object Null]
接下来看看上面提到的util函数camelize
,还是先把源码贴出来。
export function cached<F: Function> (fn: F): F {
const cache = Object.create(null)
return (function cachedFn (str: string) {
const hit = cache[str]
return hit || (cache[str] = fn(str))
}: any)
}
const camelizeRE = /-(\w)/g
export const camelize = cached((str: string): string => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
这里定义了两个函数,分别是cached
和camelize
,其中camelize
就是我们上面调用的,cached
是在camelize
函数内部调用的。
我们先来看看camelize
函数,其实camelize
函数就是执行cached
后返回的一个函数。调用cached
时传入了一个箭头函数,箭头函数内部是调用了正则的replace
方法,将传入的str
变量中匹配/-(\w)/g
的变成大写字母,并且返回replace
后的值。(也就是将-
转换成驼峰)。
再来看看cached
函数,该函数传入的变量其实就是camelize
那里的箭头函数,首先定义了一个cache
空对象,然后直接返回了cachedFn
函数。我们在外部调用camelize(key)
时,其实就是执行了这里的了cachedFn
函数,str
的值就是传入的key
的值。很明显这里是一个闭包,可以在外部调用camelize
函数的时候可以修改或者读取这里定义的cache
对象的值。获取cache
对象中key
为str
变量值的属性值赋值给hit
变量。如果有hit变量的值,那么就直接返回hit的值,如果没有就执行camelize
传入的箭头函数,并且将箭头函数的返回值赋值给catche
对象的str
属性。如果下次调用camelize
函数时传入了相同的str
,那么就不会执行箭头函数,直接返回闭包中的cache
对象的str
属性的值。这里是性能优化的一种手段。
例如:第一次调用 camelize('name')
后,cache
对象的值就变成了{name: 'name'}。然后在其他地方再次调用 camelize('name')
时再次执行cachedFn
函数,此时hit
变量的值为'name'。直接返回hit
变量的值,不会执行传入的箭头函数。
从vue源码看props的更多相关文章
- 从vue源码看Vue.set()和this.$set()
前言 最近死磕了一段时间vue源码,想想觉得还是要输出点东西,我们先来从Vue提供的Vue.set()和this.$set()这两个api看看它内部是怎么实现的. Vue.set()和this.$se ...
- Vue源码后记-更多options参数(1)
我是这样计划的,写完这个还写一篇数据变动时,VNode是如何更新的,顺便初探一下diff算法. 至于vue-router.vuex等插件源码,容我缓一波好吧,vue看的有点伤. 其实在之前讲其余内置指 ...
- Vue源码后记-其余内置指令(3)
其实吧,写这些后记我才真正了解到vue源码的精髓,之前的跑源码跟闹着玩一样. go! 之前将AST转换成了render函数,跳出来后,由于仍是字符串,所以调用了makeFunction将其转换成了真正 ...
- Vue源码后记-钩子函数
vue源码的马拉松跑完了,可以放松一下写点小东西,其实源码讲20节都讲不完,跳了好多地方. 本人技术有限,无法跟大神一样,模拟vue手把手搭建一个MVVM框架,然后再分析原理,只能以门外汉的姿态简单过 ...
- 【vuejs深入二】vue源码解析之一,基础源码结构和htmlParse解析器
写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. vuejs是一个优秀的前端mvvm框架,它的易用性和渐进式的理念可以使每一个前端开发人员感到舒服,感到easy.它内 ...
- 【一套代码小程序&Native&Web阶段总结篇】可以这样阅读Vue源码
前言 前面我们对微信小程序进行了研究:[微信小程序项目实践总结]30分钟从陌生到熟悉 在实际代码过程中我们发现,我们可能又要做H5站又要做小程序同时还要做个APP,这里会造成很大的资源浪费,如果设定一 ...
- 读 vue 源码一 (为什么this.message能够访问data里面的message)
12月离职后,打算在年后再找工作了,最近陆陆续续的看了黄轶老师的vue源码解析,趁着还有几天过年时间记录一下. 目标:vue如何实现通过this.key,就能直接访问data,props,method ...
- vue源码逐行注释分析+40多m的vue源码程序流程图思维导图 (diff部分待后续更新)
vue源码业余时间差不多看了一年,以前在网上找帖子,发现很多帖子很零散,都是一部分一部分说,断章的很多,所以自己下定决定一行行看,经过自己坚持与努力,现在基本看完了,差ddf那部分,因为考虑到自己要换 ...
- Vue源码学习1——Vue构造函数
Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...
随机推荐
- ln -s软链接文件算文件吗
场景: 开发A在windows环境下完成了开发,配置管理员cm搭建jenkins在centos环境下编译,cm编译失败,但是开发A在他的windows环境下可以编译过,最后发现是某几个so文件的软链接 ...
- PyAutoGUI——让所有GUI都自动化
2015-08-17:输入中文bug没有解决,目前的解决方案是Python 2.X环境下安装pyperclip和pyautogui,用复制粘贴来实现. In [ ]: import pyperclip ...
- AWS 移动推送到iOS设备,Amazon Pinpoint
前言 第一次对接aws,遇到的坑是真多.现在记录一下.本文主要用到的是[Amazon Pinpoint]推送. 开发人员的指南:https://docs.aws.amazon.com/zh_cn/pi ...
- Cocos Creator 生命周期回调(官方文档摘录)
Cocos Creator 为组件脚本提供了生命周期的回调函数.用户通过定义特定的函数回调在特定的时期编写相关 脚本.目前提供给用户的声明周期回调函数有: onLoad start update la ...
- Linux基础命令---tload显示系统负载
tload tload指令以字符的方式显示当前系统的平均负载情况. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.Fedora.SUSE.openSUSE. 1.语法 ...
- window 10 删除带有管理员权限的Oracle文件夹
因为文件已经被删除就不附图解释了 因为文件安装的方式错误,所以本是按照正常步骤卸载Oracle,前面的禁用Orace服务与删除Oracle注册表都没有出错,但到最后一步---------Oracle文 ...
- hdu2054 通过率低是有理由的
这虽然是一道水题,但却巨坑,他题面上不说数据范围,也没有说数据类型,事实就是数据范围巨大,整型实型都有,所以必须用字符串去写,但是又涉及到小数,所以还要删除小数后面多余的0,比如1==1.0000,这 ...
- 新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)A Red Rover
题目链接 大概意思就是,找出一个字串,将其所有出现的地方替换成一个字母M后的长度len1,然后再加上这个字串的长度t_len得到一个新的长度len,求这个len最小等于多少. 当然,也可以不找这个串, ...
- 编译原理 #01# 简易词法分析器(js实现)
// 实验存档 效果图: 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...
- Laravel用post提交表单常见的两个错误
最近在自学Laravel,测试用post方法提交表单时碰到两个错误: 1.获取传入的值时,报错如下图所示: 在stackFlow找答案时各种解释都有,但认真读一下报错信息,意思大概是:获取Http传入 ...