This is the sixth day of my participation in Gwen Challenge

beforeCreatedBefore initializing the bounds

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options? :Object) {
    const vm: Component = this. Set unique uid of Vue element, set _isVue of Vue object to avoid being observed... Parameter merge... Initialize thethisThe._renderProxy property, _self points to itselfthis
    initLifecycle(vm) // Initialize some parameters
    initEvents(vm) // Initialize the event
    initRender(vm) // Initialize the render function
    callHook(vm, 'beforeCreate')}}Copy the code

initLifecycleThe implementation of the

export function initLifecycle (vm: Component) {
  const options = vm.$options
  let parent = options.parent
  // Find the parent node and associate the current element with the parent node
  if(parent && ! options.abstract) {while(parent.$options.abstract && parent.$parent) { parent = parent.$parent } parent.$children.push(vm) } vm.$parent = parent  vm.$root = parent ? parent.$root : vm vm.$children = [] vm.$refs = {} vm._watcher =null
  vm._inactive = null
  vm._directInactive = false
  vm._isMounted = false
  vm._isDestroyed = false
  vm._isBeingDestroyed = false
}
Copy the code
  • initLifecycleThe main is to initialize some parameters, mainly for the currentvueThe object’sparentThe element is bound and has been set$rootThe properties of the

initEventsThe implementation of the

export function initEvents (vm: Component) {
  vm._events = Object.create(null)
  vm._hasHookEvent = false
  const listeners = vm.$options._parentListeners
  if (listeners) {
    updateComponentListeners(vm, listeners)  // Update the component's time monitor}}Copy the code
  • export function updateComponentListeners (
      vm: Component,
      listeners: Object,
      oldListeners: ?Object
    ) {
      target = vm
      updateListeners(listeners, oldListeners || {}, add, remove, createOnceHandler, vm) // Update the listener
      target = undefined
    }
    Copy the code
  • Effect: Updates the component’s event listener

initRenderThe implementation of the

export function initRender (vm: Component) {
  vm._vnode = null 
  vm._staticTrees = null 
  const options = vm.$options
  const parentVnode = vm.$vnode = options._parentVnode
  const renderContext = parentVnode && parentVnode.context
  
  vm.$slots = resolveSlots(options._renderChildren, renderContext)
  vm.$scopedSlots = emptyObject
   
   // Set the corresponding methods for the _c attribute and the $createElement attribute
  vm._c = (a, b, c, d) = > createElement(vm, a, b, c, d, false)
  vm.$createElement = (a, b, c, d) = > createElement(vm, a, b, c, d, true)
    
  const parentData = parentVnode && parentVnode.data
  // Add a responsive object to the VM object and verify the prompt
  if(process.env.NODE_ENV ! = ='production') {
    defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () = > {
      !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
    }, true)
    defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () = > {
      !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
    }, true)}else {
    defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null.true)
    defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null.true)}}Copy the code

To sum up: inbeforeCreatedThe previous initialization was mainly for some parameters, so data and this in options were not bound at this time


createdThe data is already bound to this

initInjections(vm) 
initState(vm)
initProvide(vm) 
callHook(vm, 'created') 
Copy the code
  • initInjectionsThe implementation of the

    • export function initInjections (vm: Component) {
        const result = resolveInject(vm.$options.inject, vm)  // Decompose the inject object
        if (result) {
          toggleObserving(false)
          Object.keys(result).forEach(key= > {
            if(process.env.NODE_ENV ! = ='production') {
              defineReactive(vm, key, result[key], () = > {
                warn(
                  `Avoid mutating an injected value directly since the changes will be ` +
                  `overwritten whenever the provided component re-renders. ` +
                  `injection being mutated: "${key}"`,
                  vm
                )
              })
            } else {
              defineReactive(vm, key, result[key])
            }
          })
          toggleObserving(true)}}Copy the code
      • The loop will decomposeinjectBound to thethisOn instance objects
    • export function resolveInject (inject: any, vm: Component): ?Object {
        if (inject) {
          const result = Object.create(null)
          const keys = hasSymbol
            ? Reflect.ownKeys(inject) 
            : Object.keys(inject)
          for (let i = 0; i < keys.length; i++) {
            const key = keys[i]
            if (key === '__ob__') continue
            const provideKey = inject[key].from // What is the private key used for?
            let source = vm
            // This _provided provides a function
            while (source) {
              if (source._provided && hasOwn(source._provided, provideKey)) {
                result[key] = source._provided[provideKey]
                break
              }
              source = source.$parent
            }
            if(! source) {if ('default' in inject[key]) {
                const provideDefault = inject[key].default
                result[key] = typeof provideDefault === 'function'
                  ? provideDefault.call(vm)
                  : provideDefault
              } else if(process.env.NODE_ENV ! = ='production') {
                warn(`Injection "${key}" not found`, vm)
              }
            }
          }
          return result
        }
      }
      Copy the code
      • This function is basically a decompositioninjectObject, specific intermediate content needs to be sorted out later
  • initStateThe implementation of the

    • export function initState (vm: Component) { 
        vm._watchers = []
        const opts = vm.$options
        if (opts.props) initProps(vm, opts.props) 
        if (opts.methods) initMethods(vm, opts.methods) 
        if (opts.data) {
          initData(vm) 
        } else {
          observe(vm._data = {}, true /* asRootData */)}if (opts.computed) initComputed(vm, opts.computed) 
        if(opts.watch && opts.watch ! == nativeWatch) { initWatch(vm, opts.watch) } }Copy the code
      • $optionsParameters of theprops|methods|data |computed|initWatchProperty to directly sum the data in these objectsthisInstance object for binding
    • function initProps (vm: Component, propsOptions: Object) {...for (const key in propsOptions) {
          const value = validateProp(key, propsOptions, propsData, vm) // Gets the value of the specified format
          if(process.env.NODE_ENV ! = ='production') {... Format the key and validate it// Set the keys in props to be listened to
            defineReactive(props, key, value, () = > {
              if(! isRoot && ! 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)
          }
          if(! (keyin vm)) {
            proxy(vm, `_props`, key) 
          }
        }
        toggleObserving(true)}Copy the code
    • function initMethods (vm: Component, methods: Object) {
        const props = vm.$options.props
        for (const key inmethods) { .... [key] = and verify the vmtypeofmethods[key] ! = ='function' ? noop : bind(methods[key], vm) // Bind the method to this instance object}}Copy the code
    • function initData (vm: Component) {
        let data = vm.$options.data
        const keys = Object.keys(data) ... Verify the data in data to check whether it has been registered in other methods/props. If it has been registered, a message is displayed indicating that the data in data is registeredthis. _data while forming [key] observe (data,true /* asRootData */) // Observe the data in data
      }
      Copy the code
    • function initComputed (vm: Component, computed: Object) {
        const watchers = vm._computedWatchers = Object.create(null)
        const isSSR = isServerRendering() //TODO:Determine if it was rendered by the service
        for (const key in computed) {
          const userDef = computed[key]
          const getter = typeof userDef === 'function'? userDef : userDef.get ... Check the}if(! isSSR) {// Create a listener for computed
            watchers[key] = new Watcher(
              vm,
              getter || noop,
              noop,
              computedWatcherOptions //{ lazy: true })}if(! (keyin vm)) { // Directly bind attributes in computed to this object
            defineComputed(vm, key, userDef) // Add a property for a computed key to the vUE instance object to listen for set and GET events}... Verify with other attributes to see if the name is duplicated}}Copy the code
      • Loop fetch firstcomputedThe custom execution function in, and then listens for each property setting
      • And then eachcomputedProperty bound tothisOn instance objects
    • function initWatch (vm: Component, watch: Object) {
        for (const key in watch) {
          const handler = watch[key]
          if (Array.isArray(handler)) {
            for (let i = 0; i < handler.length; i++) {
              createWatcher(vm, key, handler[i]) // Generate a listener}}else {
            createWatcher(vm, key, handler)// Call the $watch method to implement the function to listen on the element}}}function createWatcher (
        vm: Component,
        expOrFn: string | Function, handler: any, options? :Object
      ) {
        if (isPlainObject(handler)) {
          options = handler
          handler = handler.handler
        }
        if (typeof handler === 'string') {
          handler = vm[handler]
        }
        return vm.$watch(expOrFn, handler, options)
      }
      Copy the code

To sum up: foroptionsProperties in thethisInstance object, and reactive processing is set for the properties