• vue.js 源代码学习笔记 ----- 工具方法 option


    /* @flow */
    
    import Vue from '../instance/index'
    import config from '../config'
    import { warn } from './debug'
    import { set } from '../observer/index'
    import {
      extend,
      isPlainObject,
      hasOwn,
      camelize,
      capitalize,
      isBuiltInTag
    } from 'shared/util'
    
    /**
     * Option overwriting strategies are functions that handle
     * how to merge a parent option value and a child option
     * value into the final value.
    覆盖策略是一个函数, 定义如何覆盖父级的对象
    */ const strats = config.optionMergeStrategies /** * Options with restrictions */ if (process.env.NODE_ENV !== 'production') {
    strats.el
    = strats.propsData = function (parent, child, vm, key) { if (!vm) {
        // key 这个配置只能在 new 一个实例的时候使用, 必须传入你创建的vm new Vue warn( `option
    "${key}" can only be used during instance ` + 'creation with the `new` keyword.' ) }
      
       //优先使用child的值
    return defaultStrat(parent, child)
    } }
    /** * Helper that recursively merges two data objects together.
    一个小助手, 能递归合并两个数据对象在一起, 如果这个对象已经被监控, 会触发双向绑定
    */ function mergeData (to: Object, from: ?Object): Object {
    //节省时间
    if (!from) return to
    let key, toVal, fromVal const keys
    = Object.keys(from)
    for (let i = 0; i < keys.length; i++) { key = keys[i] toVal = to[key] fromVal = from[key]
    if (!hasOwn(to, key)) {

       //这个方法是给to的属性key赋值,
    // 如果to有__ob__属性, 还会把新合并的这个值设置成监控模式 , 并且即刻通知更新
        // 会调用这两个方法
    defineReactive(ob.value, key, val) ob.dep.notify()
          set(to, key, fromVal)
    }
    else if (isPlainObject(toVal) && isPlainObject(fromVal)) {
       //如果val都是对象,继续合并 mergeData(toVal, fromVal) }
    }
    return to } /** * Data */ strats.data = function ( parentVal: any, childVal: any, vm?: Component ): ?Function {
    if (!vm) { // in a Vue.extend merge, both should be functions
      //节省时间
    if (!childVal) { return parentVal }

       //childVal必须是函数
    if (typeof childVal !== 'function') { process.env.NODE_ENV !== 'production' && warn( 'The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm ) return parentVal }
    //节省时间
    if (!parentVal) { return childVal }
    // when parentVal & childVal are both present, // 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 // it has to be a function to pass previous merges.
      
      // 当父子都到位, 我们需要返回一个函数, 这个函数返回了两个合并的几个
    // 不需要确认 parentval是个函数 因为它必须是传递给前一个合并的函数?
    return function mergedDataFn () { return mergeData( childVal.call(this), parentVal.call(this) ) } } else if (parentVal || childVal) {
    return function mergedInstanceDataFn () { // instance merge 合并 const instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal const defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined if (instanceData) { return mergeData(instanceData, defaultData) } else { return defaultData }
    }
    } }
    /** * Hooks and props are merged as arrays. */ function mergeHook ( parentVal: ?Array<Function>, childVal: ?Function | ?Array<Function> ): ?Array<Function> {
     
    //如果有child, 看看有没有parent, 如果有合并parent和 child, 如果没有, 返回child数组
    return childVal ? parentVal ? parentVal.concat(childVal) : Array.isArray(childVal) ? childVal : [childVal] : parentVal } config._lifecycleHooks.forEach(hook => { strats[hook] = mergeHook }) /** * Assets * * When a vm is present (instance creation), we need to do * a three-way merge between constructor options, instance * options and parent options.

    合并构造函数Object的配置 和 实例的配置 和 父级的配置
    */ function mergeAssets (parentVal: ?Object, childVal: ?Object): Object { const res = Object.create(parentVal || null) return childVal ? extend(res, childVal) : res } config._assetTypes.forEach(function (type) { strats[type + 's'] = mergeAssets }) /** * Watchers. * * Watchers hashes should not overwrite one * another, so we merge them as arrays.
    避免覆盖另一个, 这里把他们合并成数组
    */ strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object { /* istanbul ignore if */
     //节省时间
    if (!childVal) return Object.create(parentVal || null) if (!parentVal) return childVal
    const ret
    = {} //复制父级 extend(ret, parentVal)

     //最终合并成数组形式
    for (const key in childVal) { let parent = ret[key] const child = childVal[key] if (parent && !Array.isArray(parent)) { parent = [parent] } ret[key] = parent ? parent.concat(child) : [child] } return ret } /** * Other object hashes.
    简单的合并对象
    */ strats.props = strats.methods = strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object { if (!childVal) return Object.create(parentVal || null) if (!parentVal) return childVal const ret = Object.create(null) extend(ret, parentVal) extend(ret, childVal) return ret } /** * Default strategy.

    选择其中一个作为默认
    */ const defaultStrat = function (parentVal: any, childVal: any): any { return childVal === undefined ? parentVal : childVal } /** * Validate component names
    检测不能使用vue保留字
    */ function checkComponents (options: Object) { for (const key in options.components) { const lower = key.toLowerCase() if (isBuiltInTag(lower) || config.isReservedTag(lower)) { warn( 'Do not use built-in or reserved HTML elements as component ' + 'id: ' + key ) } } } /** * Ensure all props option syntax are normalized into the * Object-based format.
      确保所有的属性选项标签语法 都规范化, 都基于对象格式 , 如果key的val不存在 会设置一个默认的val => { type : null }
     
    */ function normalizeProps (options: Object) {
    const props
    = options.props if (!props) return const res = {} let i, val, name

    //[key1,key2]
    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.')
    } } }
    else if (isPlainObject(props)) {
    //{key1:val1, key2:val2}
    for (const key in props) { val = props[key] name = camelize(key)
    res[name]
    = isPlainObject(val) ? val : { type: val } }
    } options.props
    = res
    }
    /** * Normalize raw function directives into object format.

    指令格式化

    { direct1: fn1, direct2: fn2 } => { direct1: { bind: fn1, update, fn1 } ,...}
    */ function normalizeDirectives (options: Object) { const dirs = options.directives if (dirs) { for (const key in dirs) { const def = dirs[key] if (typeof def === 'function') { dirs[key] = { bind: def, update: def } } } } } /** * Merge two option objects into a new one. 合并两个配置对象 * Core utility used in both instantiation and inheritance.
    实例化和继承中使用的核心实用工具。
    */ export function mergeOptions ( parent: Object, child: Object, vm?: Component ): Object { if (process.env.NODE_ENV !== 'production') { checkComponents(child) } normalizeProps(child) normalizeDirectives(child) const extendsFrom = child.extends
    if (extendsFrom) { parent = typeof extendsFrom === 'function' ? mergeOptions(parent, extendsFrom.options, vm) : mergeOptions(parent, extendsFrom, vm) }
    if (child.mixins) { for (let i = 0, l = child.mixins.length; i < l; i++) { let mixin = child.mixins[i] if (mixin.prototype instanceof Vue) { mixin = mixin.options } parent = mergeOptions(parent, mixin, vm) } }
    const options
    = {} let key
    for (key in parent) { mergeField(key) }
    for (key in child) { if (!hasOwn(parent, key)) { mergeField(key) } }
    function mergeField (key) { 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: Object, 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 (process.env.NODE_ENV !== 'production' && warnMissing && !res) { warn( 'Failed to resolve ' + type.slice(0, -1) + ': ' + id, options ) } return res }

    各种合并配置项, 不知道为什么要这么多种方式

  • 相关阅读:
    Android高性能ORM数据库DBFlow入门
    PHP数据库操作
    Smarty模板技术学习(二)
    Smarty模板技术学习
    微信开发简单实例
    支持IE6只是其一!Web开发的十大噩梦
    前端构建工具发展及其比较
    React通过redux-persist持久化数据存储
    vue中Axios的封装和API接口的管理
    yarn使用教程
  • 原文地址:https://www.cnblogs.com/dhsz/p/7064951.html
Copyright © 2020-2023  润新知