vue源码解析
文件夹的基本功能
compiler
- vue使用字符串做为模板
- 在编辑文件夹存放对模板字符串的解析的算法
core
- 核心内容,vue构造函数,以及生命周期
plateforms
针对运行的环境有不同的实现,也是vue的入口
server
服务端,主要用于将vue用在服务端的处理代码(忽略)
sfc
单文件组件(忽略)
shared
公共工具和方法(utils.ts)在工具中随处可以用(仅展示部分)
//生成一个带有缓存的函数,用于判断数据是否是缓存中的数据,代表判断字符串是否是内置的HTML标签
export function makeMap(
str: string,
expectsLowerCase?: boolean
): (key: string) => true | undefined {
const map = Object.create(null)
const list: Array<string> = str.split(',')
for (let i = 0; i < list.length; i++) {
map[list[i]] = true
}
return expectsLowerCase ? val => map[val.toLowerCase()] : val => map[val]
}
//生成带有缓存的函数(闭包的应用)
export function cached<R>(fn: (str: string) => R): (sr: string) => R {
const cache: Record<string, R> = Object.create(null)
return function cachedFn(str: string) {
const hit = cache[str]//如果有缓存,hit就是有数据的,如果有缓存hit就是undefine
return hit || (cache[str] = fn(str))
}
}
//比较俩个对象是不是相等,一般是比较对象中的各个属性值都相等,那么该对象相等,而不能用==进行判断
export function looseEqual(a: any, b: any): boolean {
if (a === b) return true
const isObjectA = isObject(a)
const isObjectB = isObject(b)
if (isObjectA && isObjectB) {
try {
const isArrayA = Array.isArray(a)
const isArrayB = Array.isArray(b)
if (isArrayA && isArrayB) {
return (
a.length === b.length &&
a.every((e: any, i: any) => {
return looseEqual(e, b[i])
})
)
} else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime()//单独处理时间类型,比时间戳
} else if (!isArrayA && !isArrayB) {
const keysA = Object.keys(a)
const keysB = Object.keys(b)
return (
keysA.length === keysB.length &&
keysA.every(key => {
return looseEqual(a[key], b[key])
})
)
} else {
/* istanbul ignore next */
return false
}
} catch (e: any) {
/* istanbul ignore next */
return false
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}
//vue运行在浏览器中要考虑性能;每次数据更新都会伴随虚拟DOM生成,将会涉及到模板解析,会将经常使用的字符串和算法进行缓存,在垃圾回收机制中有一个统计现象,使用的越多的数据,一般会频繁使用
//1.每次创建一个数据,会考虑是否将其回收
//2.数据使用达到限额,就需要回收,判断对象是否进行回收,需要便利,将对象进行划分、统计
//3.一个对象如果在一次回收之后保留下来,统计的结果则是该数据会被永久贮存在内存中。
//4.在内存中,常常使用指令,在vue中一个“xxx-xxx-xxx"的形式出现的属性。
//5.每次数据的更新都会带来指令的解析,所以解析就是字符串的解析
const hyphenateRE = /\B([A-Z])/g
export const hyphenate = cached((str: string): string => {
return str.replace(hyphenateRE, '-$1').toLowerCase()
})
//让一个事件只允许被调用一次
export function once<T extends (...args: any[]) => any>(fn: T): T {
let called = false
return function () {
if (!called) {
called = true
fn.apply(this, arguments as any)
}
} as any
}
content.ts展示vue所有的生命周期钩子
源码学习第一天,打卡成功!