最新要闻
- 播报:院线票房止步9000万:《中国乒乓》官宣3月17日登陆线上平台
- 华硕发布新款迷你主机:高配i7-13700H、配备雷电4
- 网传梅西要来 黄牛提前卖票!阿根廷国家足球队辟谣“中国行”
- 【新要闻】315白皮书:价格刺客成消费者年度最关注现象、购物平台为年度被投诉最多行业
- 环球时讯:西安机场为首次坐飞机旅客安排指引服务:佩戴专属手环 全程有人引导
- 速度10倍于普通U盘!联想小新原厂颗粒固态U盘发售:USB 3.2双口
- 12万买C6?想多了!雪铁龙都是套路:想提车先交29万
- 微贺卡
- 《黑暗荣耀2》热播!演员透露拍摄细节:剧里的蛇是真蛇
- 82版《西游记》编剧戴英禄逝世 六小龄童发文悼念
- 当前关注:理想汽车L8首批车主调研:300名中车主开BBA的最多
- 环球播报:国产车崛起 豪华车丝毫不怂:市场份额继续增 有钱人多
- 最新资讯:努比亚Z50 Ultra首销卖爆:获京东/天猫平台销量销售额冠军
- 卡塔尔世界杯官方授权:富光1.5L顿顿桶29元发车
- 焦点精选!零碳排放!我国首款双源智能重卡成功下线:自带大辫子
- 视焦点讯!全球打广告最划算的一块屏?登上纽约时代广场屏幕只需40美元
广告
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
Vue——mergeOptions【四】
【资料图】
前言
前面我们简单的了解了 vue 初始化时的一些大概的流程,这里我们详细的了解下具体的内容;这块建议搭建可以根据 demo 进行 debugger 来观察;
内容
这一块主要围绕init.ts
中的mergeOptions
进行剖析。
mergeOptions
mergeOptions
的方法位于scr/core/util/options.ts
中,除了resolveAsset
未被调用外,其他都在这一层级会被调用;
/** * Option overwriting strategies are functions that handle * how to merge a parent option value and a child option * value into the final value. * 选项合并策略 处理合并parent选项值和child选项值并转为最终的值 */const strats = config.optionMergeStrategies/** * Options with restrictions * */if (__DEV__) { strats.el = strats.propsData = function ( parent: any, child: any, vm: any, key: any ) { if (!vm) { warn( `option "${key}" can only be used during instance ` + "creation with the `new` keyword." ) } return defaultStrat(parent, child) }}/** * Helper that recursively merges two data objects together. * * 合并data选项 * */function mergeData( to: Record, from: Record | null, recursive = true): Record { if (!from) return to let key, toVal, fromVal const keys = hasSymbol ? (Reflect.ownKeys(from) as string[]) : Object.keys(from) for (let i = 0; i < keys.length; i++) { key = keys[i] // in case the object is already observed... // 跳过已经存在响应式的对象 if (key === "__ob__") continue toVal = to[key] fromVal = from[key] if (!recursive || !hasOwn(to, key)) { // 对数据进行响应式处理 set(to, key, fromVal) } else if ( toVal !== fromVal && isPlainObject(toVal) && isPlainObject(fromVal) ) { // 如果parent和child都有值却不相等而且两个都是对象的时候,继续递归合并 mergeData(toVal, fromVal) } } return to}/** * Data * * 合并作为函数的data */export function mergeDataOrFn( parentVal: any, childVal: any, vm?: Component): Function | null { // 判断是否存在vue实例 if (!vm) { // in a Vue.extend merge, both should be functions // 在Vue.extend的合并中,两个参数都应该是函数 if (!childVal) { return parentVal } if (!parentVal) { return childVal } // when parentVal & childVal are both present, // 当parentVal和childVal都存在的时候 // we need to return a function that returns the // 我们需要返回一个函数 // merged result of both functions... no need to // 该函数返回两者合并的结果 // check if parentVal is a function here because // 不需要去检查parentVal是否是一个函数因为 // it has to be a function to pass previous merges. // 他肯定是先前合并的函数 return function mergedDataFn() { // 合并data数据 return mergeData( isFunction(childVal) ? childVal.call(this, this) : childVal, isFunction(parentVal) ? parentVal.call(this, this) : parentVal ) } } else { // 合并实例data函数 return function mergedInstanceDataFn() { // instance merge // child 数据 const instanceData = isFunction(childVal) ? childVal.call(vm, vm) : childVal // 默认数据 const defaultData = isFunction(parentVal) ? parentVal.call(vm, vm) : parentVal // 如果child存在数据则进行合并否则直接返回默认数据 if (instanceData) { return mergeData(instanceData, defaultData) } else { return defaultData } } }}strats.data = function ( parentVal: any, childVal: any, vm?: Component): Function | null { if (!vm) { // dev环境下会判断child是否为函数,不是的话则发出警告并返回parentVal if (childVal && typeof childVal !== "function") { __DEV__ && warn( "The "data" option should be a function " + "that returns a per-instance value in component " + "definitions.", vm ) return parentVal } return mergeDataOrFn(parentVal, childVal) } return mergeDataOrFn(parentVal, childVal, vm)}/** * Hooks and props are merged as arrays. * * 生命周期合并策略会将生命周期内的钩子函数和props转化为数组格式并合并到一个数组中 */export function mergeLifecycleHook( parentVal: Array | null, childVal: Function | Array | null): Array | null { const res = childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal return res ? dedupeHooks(res) : res}function dedupeHooks(hooks: any) { const res: Array = [] for (let i = 0; i < hooks.length; i++) { if (res.indexOf(hooks[i]) === -1) { res.push(hooks[i]) } } return res}LIFECYCLE_HOOKS.forEach(hook => { strats[hook] = mergeLifecycleHook})/** * Assets * * When a vm is present (instance creation), we need to do * a three-way merge between constructor options, instance * options and parent options. * 当存在vm(实例创建)时,我们需要在构造函数选项、实例和父选之间进行三方合并 * */function mergeAssets( parentVal: Object | null, childVal: Object | null, vm: Component | null, key: string): Object { const res = Object.create(parentVal || null) if (childVal) { __DEV__ && assertObjectType(key, childVal, vm) // 将child合并到parentVal中会进行覆盖 return extend(res, childVal) } else { return res }}ASSET_TYPES.forEach(function (type) { strats[type + "s"] = mergeAssets})/** * Watchers. * * Watchers hashes should not overwrite one * another, so we merge them as arrays. *监听不应该被覆盖,所以使用数组格式进行合并 * * watch合并 */strats.watch = function ( parentVal: Record | null, childVal: Record | null, vm: Component | null, key: string): Object | null { // work around Firefox"s Object.prototype.watch... // nativeWatch 兼容火狐浏览器,因为火狐浏览器原型上存在watch //@ts-expect-error work around if (parentVal === nativeWatch) parentVal = undefined //@ts-expect-error work around if (childVal === nativeWatch) childVal = undefined /* istanbul ignore if */ if (!childVal) return Object.create(parentVal || null) if (__DEV__) { assertObjectType(key, childVal, vm) } if (!parentVal) return childVal const ret: Record = {} extend(ret, parentVal) for (const key in childVal) { let parent = ret[key] const child = childVal[key] if (parent && !isArray(parent)) { parent = [parent] } ret[key] = parent ? parent.concat(child) : isArray(child) ? child : [child] } return ret}/** * Other object hashes. * * 对象合并,存在childVal的话以childVal为准 */strats.props = strats.methods = strats.inject = strats.computed = function ( parentVal: Object | null, childVal: Object | null, vm: Component | null, key: string ): Object | null { if (childVal && __DEV__) { assertObjectType(key, childVal, vm) } if (!parentVal) return childVal const ret = Object.create(null) extend(ret, parentVal) if (childVal) extend(ret, childVal) return ret }/** * provide合并 */strats.provide = function (parentVal: Object | null, childVal: Object | null) { if (!parentVal) return childVal return function () { const ret = Object.create(null) mergeData(ret, isFunction(parentVal) ? parentVal.call(this) : parentVal) if (childVal) { // 不进行递归合并 mergeData( ret, isFunction(childVal) ? childVal.call(this) : childVal, false // non-recursive ) } return ret }}/** * Default strategy. * 默认值策略 | 避免parentVal被未定义的childVal覆盖 */const defaultStrat = function (parentVal: any, childVal: any): any { return childVal === undefined ? parentVal : childVal}/** * Validate component names * 校验组件名是否合法 | 避免组件名称使用保留的关键字或者不符合html5规范 */function checkComponents(options: Record) { for (const key in options.components) { validateComponentName(key) }}export function validateComponentName(name: string) { if ( !new RegExp(`^[a-zA-Z][\\-\\.0-9_${unicodeRegExp.source}]*$`).test(name) ) { warn( "Invalid component name: "" + name + "". Component names " + "should conform to valid custom element name in html5 specification." ) } if (isBuiltInTag(name) || config.isReservedTag(name)) { warn( "Do not use built-in or reserved HTML elements as component " + "id: " + name ) }}/** * Ensure all props option syntax are normalized into the * Object-based format. * * 格式化object对象 | 确保所有的props选项的语法都符合对象格式 */function normalizeProps(options: Record, vm?: Component | null) { const props = options.props // 不存在props则直接return if (!props) return const res: Record = {} let i, val, name // 判断是否是数组 if (isArray(props)) { i = props.length while (i--) { val = props[i] if (typeof val === "string") { // 使用驼峰来代替-连字符 name = camelize(val) res[name] = { type: null } } else if (__DEV__) { // 如果是dev环境则发出警告,提示在数组语法下props必须为字符串 warn("props must be strings when using array syntax.") } } } else if (isPlainObject(props)) { // 判断是否为对象 for (const key in props) { val = props[key] // 使用驼峰来代替-连字符 name = camelize(key) res[name] = isPlainObject(val) ? val : { type: val } } } else if (__DEV__) { // 如果是dev环境则发出警告,提示props应该是一个数组或者对象 warn( `Invalid value for option "props": expected an Array or an Object, ` + `but got ${toRawType(props)}.`, vm ) } options.props = res}/** * Normalize all injections into Object-based format * * 将所有的inject格式化object对象 */function normalizeInject(options: Record, vm?: Component | null) { const inject = options.inject if (!inject) return const normalized: Record = (options.inject = {}) if (isArray(inject)) { for (let i = 0; i < inject.length; i++) { normalized[inject[i]] = { from: inject[i] } } } else if (isPlainObject(inject)) { for (const key in inject) { const val = inject[key] normalized[key] = isPlainObject(val) ? extend({ from: key }, val) : { from: val } } } else if (__DEV__) { // 开发环境下如果inject格式不是数组或者对象则发出警告 warn( `Invalid value for option "inject": expected an Array or an Object, ` + `but got ${toRawType(inject)}.`, vm ) }}/** * Normalize raw function directives into object format. * *将原始的指令函数转为object对象格式 */function normalizeDirectives(options: Record) { const dirs = options.directives if (dirs) { for (const key in dirs) { const def = dirs[key] if (isFunction(def)) { dirs[key] = { bind: def, update: def } } } }}// 开发环境下,会进行检测,如果不是对象的话发出警告function assertObjectType(name: string, value: any, vm: Component | null) { if (!isPlainObject(value)) { warn( `Invalid value for option "${name}": expected an Object, ` + `but got ${toRawType(value)}.`, vm ) }}/** * Merge two option objects into a new one. * Core utility used in both instantiation and inheritance. * * 将两个option对象合并成一个新的对象 * 用于实例化和继承的核心工具 */export function mergeOptions( parent: Record, child: Record, vm?: Component | null): ComponentOptions { // dev环境下会检查组件名称是否合法 if (__DEV__) { checkComponents(child) } // 检查option是否是函数,是的话直接将options赋值给child if (isFunction(child)) { // @ts-expect-error child = child.options } // 格式化props为object对象 | 检测格式是否为数组和对象,并使用驼峰代替-连字符,开发环境下如果格式存在问题会发出警告 normalizeProps(child, vm) // 格式化inject为object对象 | 检测格式是否为数组和对象,开发环境下如果格式存在问题会发出警告 normalizeInject(child, vm) // 格式化directive为object对象 normalizeDirectives(child) // Apply extends and mixins on the child options, // 在子选项上去应用 extends和mixins // but only if it is a raw options object that isn"t // the result of another mergeOptions call. // 前提是它是一个原始选项对象,而不是另一个mergeOptions的结果 // Only merged options has the _base property. // 只合并具有_base属性的合并选项 if (!child._base) { // 合并extends到parent if (child.extends) { parent = mergeOptions(parent, child.extends, vm) } // 合并mixins到parent if (child.mixins) { for (let i = 0, l = child.mixins.length; i < l; i++) { parent = mergeOptions(parent, child.mixins[i], vm) } } } const options: ComponentOptions = {} as any let key for (key in parent) { mergeField(key) } for (key in child) { if (!hasOwn(parent, key)) { mergeField(key) } } // 合并parent和child选项 function mergeField(key: any) { const strat = strats[key] || defaultStrat options[key] = strat(parent[key], child[key], vm, key) } return options}/** * Resolve an asset. * 解析资源 * This function is used because child instances need access * to assets defined in its ancestor chain. * 使用这个函数是因为子实例中需要访问其祖先中定义的资源 */export function resolveAsset( options: Record, type: string, id: string, warnMissing?: boolean): any { /* istanbul ignore if */ if (typeof id !== "string") { return } const assets = options[type] // check local registration variations first if (hasOwn(assets, id)) return assets[id] const camelizedId = camelize(id) if (hasOwn(assets, camelizedId)) return assets[camelizedId] const PascalCaseId = capitalize(camelizedId) if (hasOwn(assets, PascalCaseId)) return assets[PascalCaseId] // fallback to prototype chain const res = assets[id] || assets[camelizedId] || assets[PascalCaseId] if (__DEV__ && warnMissing && !res) { warn("Failed to resolve " + type.slice(0, -1) + ": " + id) } return res}
关键词:
-
环球热点评!.NET中比肩System.Text.Json序列化反序列化组件MessagePack
简介官方定义:MessagePack是一种高效的二进制序列化格式。它允许您像JSON一样在多个语言之间交换数据。...
来源: Vue——mergeOptions【四】
播报:院线票房止步9000万:《中国乒乓》官宣3月17日登陆线上平台
华硕发布新款迷你主机:高配i7-13700H、配备雷电4
环球热点评!.NET中比肩System.Text.Json序列化反序列化组件MessagePack
路飞-项目上线
今亮点!分布式架构-可观测性-事件日志
【全球热闻】教你用Python画个可爱的皮卡丘!(附完整源码)
每日资讯:Educational Codeforces Round 123 (Rated for Div. 2)
网传梅西要来 黄牛提前卖票!阿根廷国家足球队辟谣“中国行”
【新要闻】315白皮书:价格刺客成消费者年度最关注现象、购物平台为年度被投诉最多行业
环球时讯:西安机场为首次坐飞机旅客安排指引服务:佩戴专属手环 全程有人引导
速度10倍于普通U盘!联想小新原厂颗粒固态U盘发售:USB 3.2双口
12万买C6?想多了!雪铁龙都是套路:想提车先交29万
记录--你不知道的forEach函数
智能勘探 | AIRIOT智慧油田管理解决方案
环球聚焦:NOI春季测试游记
微贺卡
《黑暗荣耀2》热播!演员透露拍摄细节:剧里的蛇是真蛇
82版《西游记》编剧戴英禄逝世 六小龄童发文悼念
当前关注:理想汽车L8首批车主调研:300名中车主开BBA的最多
环球播报:国产车崛起 豪华车丝毫不怂:市场份额继续增 有钱人多
最新资讯:努比亚Z50 Ultra首销卖爆:获京东/天猫平台销量销售额冠军
报道:第一章 软件工程概述
每日看点!centos7.9离线升级openssl和openssh9.2
python语言基础
每日焦点!Mysql数据库未添加索引引发的生产事故
对极几何的理解和原理推导
卡塔尔世界杯官方授权:富光1.5L顿顿桶29元发车
焦点精选!零碳排放!我国首款双源智能重卡成功下线:自带大辫子
视焦点讯!全球打广告最划算的一块屏?登上纽约时代广场屏幕只需40美元
《狂飙》后 张译宣传新剧《他是谁》:今晚优酷、央视开播
获赔近100万 报废奔驰翻新再销售被判退1赔3 网友:C级秒变大S
每日快讯!10Wqps 超高并发 API网关 架构演进之路
Egg.js 学习笔记01
世界快看:git提交规范
【全球速看料】早起、冥想、阅读、写作、运动
焦点讯息:观察者模式——学习笔记
天天最新:dnf游戏闪退怎么解决方法_dnf游戏闪退
停车场闸机防骗能力太弱鸡:博主实测一部手机、一张纸均可通行
曾模仿东方甄选直播带货 好未来旗下学而思大规模重启线下招生
白皮书:购物平台为2022年度消费者投诉最多的行业
天天播报:315前海鲜加工厂的狠活被曝光:硼砂泡出黄金鲍 系明令禁止食品添加剂
世界焦点!两只售价3899元:华硕ROG推出魔方幻路由器月曜白限定版
卷起来!!!看了这篇文章我才知道MySQL事务&MVCC到底是啥?
蓝牙Mesh简介(一)设备标识:UUID和Mesh地址
开源免费:分享powershell读写k8s的etcd的脚本库
环球速递!冲击全球的“硅谷银行破产”到底咋回事?会不会引爆危机?
视点!国产AYA新掌机Ayaneo 2 IGN9分好评:价格贵 但很好用!
【聚看点】央视3·15晚会官宣明晚举办 这次谁会被曝光?
世界最资讯丨配置大升级!新款比亚迪唐DM-i/汉EV冰川蓝实车亮相:绝对吸睛
上海测试9辆自动驾驶清扫车 可替代25名环卫工人
干货来袭!3天0基础Python实战项目快速学会人工智能必学数学基础全套(含源码)(第3天)概率分析篇:条件概率、全概率与贝叶斯公式
韩国电视台剪掉杨紫琼获奖感言:鼓励女性部分没了
腾讯会议重大调整!取消免费300人不限时会议使用
世界看热讯:斥资10亿美元!NASA将开发太空拖船:实现国际空间站受控坠落
那些曾被315点过名的品牌怎么样了?英菲尼迪道歉并更换变速箱 汉堡王被罚
实时焦点:车圈大V杨学良晒魅族20 Pro真机:极简设计 好看又好用!
与微软聊天机器人对话
Vue项目迁移小程序,实操干货分享
戴尔PC要100%离开中国!完整时间表曝光:真着急
天天微资讯!韩媒称特斯拉停止与比亚迪合作 马斯克:虚假报道、双方关系积极
魔兽世界将推出全新硬核玩法:一命通关、挂了就得重来
ai文件怎么打开?ai文件用什么软件打开和编辑?
斐讯k1支持千兆吗?斐讯k1路由器怎么设置?
windows如何一键还原?windows截图保存在哪里?
声卡怎么调试?声卡什么牌子的音质比较好?
笔记本fn键在哪里?fn键怎么开启和关闭?
每日短讯:可插拔组件设计机制—SPI
今日热讯:Vim 备忘清单_开发速查表分享
世界头条:Linux进程的创建与销毁
鲨鱼求偶被误认吃“同事” 官方回应:是繁殖行为 撕咬有分寸
天天热文:减肥不吃主食?医生提醒:可致大脑功能衰退
全球热消息:《小丑2》Lady Gaga小丑女新片场照 造型太好看了
全球报道:极速直追中国高铁!碳陶瓷刹车套件特斯拉Model S Plaid打破单圈纪录
【全球报资讯】一键开盖:哈尔斯600ml水杯9.9元狂促 Tritan材质款23.9元
天天热头条丨阳高县气象台发布大风蓝色预警【Ⅳ级/一般】
全球微头条丨java操作excel文件——POI
天天讯息:剑指 Offer 68 - II. 二叉树的最近公共祖先(java解题)
分布式架构-可观测性
obs studio 插件
看热讯:小米子公司发通告:拼多多、京东、淘宝上的“紫米官旗”不是我
硅谷银行停业没影响!贾跃亭要“翻身”:4月26日FF91终极发布
世界今日讯!德国反对2035禁售燃油车!欧盟做出让步:内燃机还有活路
天天观热点:Intel要求电源厂商使用单一规格制作12VHPWR接头
马斯克减肥神药遭疯抢!欧洲药管局警告:2023年都会短缺
天天热讯:DockQuery | 基于E-R图的数据建模功能使用实践
宝马iX3高速撞车 车主:车道纠偏系统和自己抢方向盘酿事故
环球最新:公司回应因给客户倒水太满开除员工:该走啥程序走啥程序
新机型“无可奉告”:任天堂称对Switch未来充满信心
【全球速看料】史上最大规模!魅族领克无界生态发布会官宣:魅族20系列、Flyme 10来了
全球视点!一加逆袭!成为2023年销量增速最快的品牌:友商普遍下滑
共314套房源!昌平区公租房配租公告来了
焦点资讯:GO语言学习笔记-测试篇 Study for Go ! Chapter ten- Test
要闻速递:面试官:怎么删除 HashMap 中的重复元素?第 3 种实现思路,99% 的人不会!
世界快消息!k8s的Helm 工具安装
RPC框架JMH测试-chatgpt自动生成
前端设计模式——代理模式
全球视讯!特斯拉叫停与比亚迪合作?比亚迪回应:不实信息
环球即时:苹果人事巨震:11位高管扎堆离职 库克也要降薪40%
微头条丨燃油车 真凉透了吗