没有合适的资源?快使用搜索试试~ 我知道了~
继续随着核心类的初始化展开探索其他的模块,这一篇来研究一下Vue的状态初始化。这里的状态初始化指的就是在创建实例的时候,在配置对象里定义的属性、数据变量、方法等是如何进行初始处理的。由于随后的数据更新变动都交给观察系统来负责,所以在事先弄明白了数据绑定的原理之后,就只需要将目光集中在这一部分。 来仔细看看在核心类中首先执行的关于 state 部分的源码: initState // 定义并导出initState函数,接收参数vm export function initState (vm: Component) { // 初始化实例的私有属性_watchers // 这就是在观察系统里会
资源推荐
资源详情
资源评论
Vue源码探究之状态初始化源码探究之状态初始化
继续随着核心类的初始化展开探索其他的模块,这一篇来研究一下Vue的状态初始化。这里的状态初始化指的就是在创建实例
的时候,在配置对象里定义的属性、数据变量、方法等是如何进行初始处理的。由于随后的数据更新变动都交给观察系统来负
责,所以在事先弄明白了数据绑定的原理之后,就只需要将目光集中在这一部分。
来仔细看看在核心类中首先执行的关于 state 部分的源码:
initState
// 定义并导出initState函数,接收参数vm
export function initState (vm: Component) {
// 初始化实例的私有属性_watchers
// 这就是在观察系统里会使用到的存储所有显式监视器的对象
vm._watchers = [] // 获取实例的配置对象
const opts = vm.$options
// 如果定义了props,则初始化props
if (opts.props) initProps(vm, opts.props)
// 如果定义了methods,则初始化methods
if (opts.methods) initMethods(vm, opts.methods)
// 如果定义了data,则初始化data
if (opts.data) {
initData(vm)
} else {
// 否则初始化实例的私有属性_data为空对象,并开启观察
observe(vm._data = {}, true /* asRootData */)
}
// 如果定义了computed,则初始化计算属性
if (opts.computed) initComputed(vm, opts.computed)
// 如果定义了watch并且不是nativeWatch,则初始化watch
// nativeWatch是火狐浏览器下定义的对象的原型方法
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
这段代码非常直白,主要用来执行配置对象里定义的了状态的初始化。这里分别有 props、data、methods、computed、
watch 五个配置对象,分别有各自的初始化方法。在仔细研究它们的具体实现之前,先来看一段将在各个初始化函数里用到的
辅助函数。
// 定义共享属性定义描述符对象sharedPropertyDefinition
// 描述符对象的枚举和可配置属性都设置为true
// get、set方法设置为空函数
const sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
}
// 定义并导出proxy函数,该函数用来为在目标对象上定义并代理属性
// 接收目标对象target,路径键名sourceKey,属性键名三个参数
export function proxy (target: Object, sourceKey: string, key: string) {
// 设置属性描述符对象的get方法
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key] }
// 设置属性描述性对象的set犯法
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val
}
// 在目标对象上定义属性
Object.defineProperty(target, key, sharedPropertyDefinition)
}
proxy 函数的定义非常重要,在下面要探究的各个初始化函数中它,它会将我们在配置对象中设置的属性全部定义到实例对象
中,但是我们对这些属性的操作是通过各部分相应的代理属性上来执行的。get 和 set 方法的实现非常明白的表示出这一过
程,然后再将属性定义到实例中。由这个函数作为基础,继续来看看其他五个状态的初始化函数的内容。
initProps
// 定义initProps函数,接收vm,propsOptions两个参数
function initProps (vm: Component, propsOptions: Object) {
// 赋值propsData,propsData是全局扩展传入的赋值对象
// 在使用extend的时候会用到,实际开发里运用较少
const propsData = vm.$options.propsData || {}
// 定义实例的_props私有属性,并赋值给props
const props = vm._props = {}
// 缓存prop键,以便将来props更新可以使用Array而不是动态对象键枚举进行迭代。
// cache prop keys so that future props updates can iterate using Array
// instead of dynamic object key enumeration.
const keys = vm.$options._propKeys = [] // 是否是根实例
const isRoot = !vm.$parent
// 对于非根实例,关闭观察标识
// root instance props should be converted
if (!isRoot) {
toggleObserving(false)
}
// 遍历props配置对象
for (const key in propsOptions) {
// 向缓存键值数组中添加键名
keys.push(key)
// 验证prop的值,validateProp执行对初始化定义的props的类型检查和默认赋值
// 如果有定义类型检查,布尔值没有默认值时会被赋予false,字符串默认undefined
// 对propsOptions的比较也是在使用extend扩展时才有意义
// 具体实现可以参考 src/core/util/props.js,没有难点这里不详细解释
const value = validateProp(key, propsOptions, propsData, vm)
// 非生产环境下进行检查和提示
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
// 进行键名的转换,将驼峰式转换成连字符式的键名
const hyphenatedKey = hyphenate(key)
// 对与保留变量名冲突的键名给予提示
if (isReservedAttribute(hyphenatedKey) ||
config.isReservedAttr(hyphenatedKey)) {
warn(
`"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
vm
)
}
// 对属性建立观察,并在直接使用属性时给予警告
defineReactive(props, key, value, () => {
if (vm.$parent && !isUpdatingChildComponent) {
warn(
`Avoid mutating a prop directly since the value will be ` +
`overwritten whenever the parent component re-renders. ` +
`Instead, use a data or computed property based on the prop's ` +
`value. Prop being mutated: "${key}"`,
vm
)
}
})
} else {
// 非生产环境下直接对属性进行存取器包装,建立依赖观察
defineReactive(props, key, value)
}
// 使用Vue.extend()方法扩展属性时,已经对静态属性进行了代理
// 这里只需要针对实例化时的属性执行代理操作
// static props are already proxied on the component's prototype
// during Vue.extend(). We only need to proxy props defined at
// instantiation here.
// 当实例上没有同名属性时,对属性进行代理操作
// 将对键名的引用指向vm._props对象中
if (!(key in vm)) {
proxy(vm, `_props`, key)
}
}
// 开启观察状态标识
toggleObserving(true)
}
initProps 函数的最主要内容有两点,一是对定义的数据建立观察,二是对数据进行代理,这就是私有变量 _props 的作用,之
后获取和设置的变量都是作为 _props 的属性被操作。
另外初始化 props 的过程中有针对 extend 方法会使用到的 propsData 属性的初始化。具体使用是在扩展对象时定义一些
剩余7页未读,继续阅读
资源评论
weixin_38728555
- 粉丝: 3
- 资源: 921
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 该项目是一个使用TypeScript实现的简易版Web系统框架,旨在提供一套搭建Web应用程序的基础设施 它具备以下主要特点和功能1. 虚拟文件系统2. 语言系统3. 常用接口集合.zip
- 网页编辑器,拖拽读取文件,保存文件,支持大部分编程语言文件编辑,简单易用,无需安装,这正是我想要的.zip
- 电力系统分析:基于VBA的分布式电源最佳接入点判定方法与程序实现
- MATLAB实现线性代数方程组直接解法算法解析与实践案例
- 基于MATLAB的线性代数方程组雅克比迭代解法研究与应用
- 基于MATLAB实现的线性代数方程组高斯消去法解析与应用
- MATLAB实现拉格朗日插值多项式的数值计算方法
- 数值计算方法中艾特肯插值法的MATLAB实现与应用
- pure-bash-bible-zh_CN-字符串循环左移
- SCUI-vue框架开发资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功