最近利用空闲时间又翻看了一遍Vue的源码,只不过这次不同的是看了Flow版本的源码。说来惭愧,最早看的第一遍时对Flow不了解,因此阅读的是打包之后的vue文件,大家可以想象这过程的痛苦,没有类型的支持,看代码时摸索了很长时间,所以我们这次对Vue源码的剖析是Flow版本的源码,也就是从Github上下载下来的源码中src目录下的代码。不过,在分析之前,我想先说说阅读Vue源码所需要的一些知识点,掌握这些知识点之后,相信再阅读源码会较为轻松。
前置知识点
function sum(a: number, b:number) {
return a + b;
}
export function renderList (
val: any,
render: (
val: any,
keyOrIndex: string | number,
index?: number
) => VNode
): ?Array<VNode>{
...
}
val是any代表可以传入的类型是任何类型, keyOrIndex是string|number类型,
代表要不是string类型,要不是number,不能是别的;index?:number这个我们想想
正则表达式中?的含义---0个或者1个,这里其实意义也是一致的,但是要注意?的
位置是在冒号之前还是冒号之后--因为这两种可能性都有,上面代码中问号是跟在冒
号前面,代表index可以不传,但是传的话一定要传入数字类型;如果问号是在冒号
后面的话,则代表这个参数必须要传递,但是可以是数字类型也可以是空。这样是
不是顿时感觉严谨多了?同时,代码意义更明确了。为啥这么说呢? 之前看打包后
的vue源码,其中看到观察者模式实现时由于没有类型十分难看懂,但是看了这个
Flow版本的源码,感觉容易懂
原型与原型继承
涉及到父子组件了。组件其实初始化过程都是一样的,显然有些方法是可以继承的。
Vue代码中是使用原型继承的方式实现父子组件共享初始化代码的
Object.defineProperty
这个方法在js中十分强大,Vue正是使用了它实现了响应式数据功能。
我们先瞄一眼Vue中定义响应式数据的代码
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
.....
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !
== value))
{
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter)
{
customSetter()
}
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
})
}
其中我们看到Object.defineProperty这个函数的运用,其中第一个参数代表要设置的对象,第二个参数代表要设置的对象的键值,第三个参数是一个配置对象,对象里面可以设置参数如下:
value: 对应key的值,无需多言
configurable:是否可以删除该key或者重新配置该key
enumerable:是否可以遍历该key
writable:是否可以修改该key
get: 获取该key值时调用的函数
set: 设置该key值时调用的函数
我们通过一个例子来了解一下这些属性
let x = {}
x['name'] = 'vue'
console.log(Object.getOwnPropertyDescriptor(x,'name'))
打印结果如下:
{
value: "vue",
writable: true,
enumerable: true,
configurable: true
}