preface

When answering the interviewer asked the QUESTION of Vue, we in addition to the scripted answer, actually can also show according to a small amount of source code, to reflect your depth of understanding of Vue.

This article will be updated in succession. This time, it covers the following issues:

  1. “What does new Vue() do?”
  2. “At what stage can I access the DOM?”
  3. “Talk about your understanding of the Vue lifecycle.”
  4. Extension: What is the new lifecycle hook serverPrefetch?
  5. “How many vue-router routing modes are there?”
  6. “Tell me what you know about Keep-alive?”
  7. “Understand The new Vue2.6+ global API: Vue.Observable ()?”

1.”new Vue()Do what?”

The new keyword represent instantiate an object, the Vue is actually a class, source location is/SRC/core/instance/index. Js.

function Vue (options) {
  if(process.env.NODE_ENV ! = ='production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}
Copy the code

Then we jump back to this._init(), which is ue.prototype._init, with a series of init* methods inside the _init() method in SRC \core\instance\init.js

Vue.prototype._init = function(options? : Object) { const vm: Component = this // ... Ignore, from line 45if(process.env.NODE_ENV ! = ='production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created') / /... ignoreif (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}
Copy the code

1.1 Here we summarize:

  1. initProxy, a scoping agent that intercepts data within a component that accesses other components.
  2. initLifecycle, and add some properties and lifecycle identifications to the current instance. Such as:$children,$refs,_isMountedAnd so on.
  3. initEventsWhich is used to store the division@hook: Lifecycle hook name =" Bound function"Event object. Such as:$on,$emitAnd so on.
  4. initRenderFor initialization$slots,$attrs,$listeners
  5. initInjectionsInitialization,inject, which is generally used for deeper component communication and is equivalent to an enhanced versionprops. Used for component library development.

As long as the provide is declared at the upper level, the next level no matter how deep the inject can visit the provide data. This also has obvious drawbacks: it can be accessed at any level, making it difficult to track the data, not knowing which level declares it or which level or levels are used.

  • initStateIs a summary of many option initializations, including:Props, methods, Data, computed, and WatchAnd so on.
  • initProvideInitialization,provide.
  • vm.$mountTo mount the instance.

2. “At what stage can I access the DOM?”

This answer can be started from the timing of beforeCreate and created. Let’s simplify the code according to the above overview:

callHook(vm, 'beforeCreate'// initialize props, methods, data, computed, and watch // provide callHook(VM,'created') // Mount the instance VM.$mount(vm.$options.el)
Copy the code

So when an interviewer asks you,

  • beforeCreateAs well ascreatedWhat data is available or not when called?
  • At what stage can I access the DOM?
  • whycreatedThen mount the instance?

You know how to answer that.

3. “Talk about your understanding of Vue’s life cycle”

I’m going to skip the usual answer here and go a little deeper:

  1. created/mounted/updated/destroyed, and the correspondingbeforeHook. If create => Mount => Update => Destroy.
  2. VueOne is defined in the source codemergeHookFunction to iterate over a constant arrayLIFECYCLE_HOOKS, which is actually an array of strings with the same name as the lifecycle hook.
Var LIFECYCLE_HOOKS = ['beforeCreate'.'created'.'beforeMount'.'mounted'.'beforeUpdate'.'updated'.'beforeDestroy'.'destroyed'.'activated'.'deactivated'.'errorCaptured', / / v2.6 +'serverPrefetch'
];
Copy the code

So you can say that Activated and deactivated (keep-alive enabled/disabled) and errorCaptured (a hook that’s available later in V2.5 for handling errors).

3.1 New Lifecycle hooks:serverPrefetchWhat is?

As you can see, serverPrefetch was formerly ssrPrefetch. As the name suggests, this is for SSR. Allows us to “wait” for asynchronous data during rendering. Can be used in any component, not just the routing component.

<! -- Item.vue --> <template> <div v-if="item">{{ item.title }}</div> <div v-else>... </div> </template> <script>export default {
  computed: {
    item () {
      return this.$store.state.items[this.$route.params.id]
    }
  },
  serverPrefetch () {
    return this.fetchItem()
  },
  mounted () {
    if(! this.item) { this.fetchItem() } }, methods: {fetchItem () {
      // return the Promise from the action
      return this.$store.dispatch('fetchItem', this.$route.params.id)
    }
  }
}
</script>
Copy the code
  • Most interviewers don’t pay much attention to code records and changes since V2.6 +. Here if you say thisv2.6.10Change, tut… The interviewer will appreciate you more.

3.2 Merge policy for lifecycle hooks

Take callHook(VM, ‘created’) as an example, first determine whether there is a lifecycle hook with the corresponding name in the component option, and then determine whether there is a parentVal(VM). If parentVal(VM) exists and both have lifecycle hooks, they are concat into an array (parentval.concat (childVal)). So, lifecycle hooks can actually be written as arrays. Such as:

created: [
function () {
  console.log('first')},function () {
  console.log('second')},function () {
  console.log('third')}]Copy the code

The hook functions are executed in sequence.

4. “How many vue-router routing modes are there?

Three “hash” | | “history”, “the abstract” the average person only know two “hash” | “history”.

Here’s the source code:

switch (mode) {
  case 'history':
    this.history = new HTML5History(this, options.base)
    break
  case 'hash':
    this.history = new HashHistory(this, options.base, this.fallback)
    break
  case 'abstract':
    this.history = new AbstractHistory(this, options.base)
    break
  default:
    if(process.env.NODE_ENV ! = ='production') {
      assert(false, `invalid mode: ${mode}`)}}Copy the code

# mode

Type: string

Default value: “hash” (the browser environment) | “the abstract” (Node. Js environment)

Optional value: “hash” | | “history” “the abstract” configuring the routing mode:

  • hashUse:URL hashValue for routing. Support for all browsers, including unsupportedHTML5 History ApiThe browser.
  • history: rely onHTML5 HistoryAPI and server configuration. To viewHTML5 HistoryMode.
  • abstract: Supports allJavaScriptRunning environment, such asNode.jsServer side. If you find no browserAPI, the route is automatically forced into this mode.

5. “Talk about your rightkeep-aliveOf?”

Here’s a general answer:

Keep-alive is a component built into Vue that allows included components to retain state or avoid rerendering. Since vue 2.1.0, keep-alive has added two new properties: include(the included component is cached) and exclude(the excluded component is not cached and has a higher priority than include).

Then you can start flirting:

  1. <keep-alive>isVueSource code in the implementation of a global abstract component, through the customizationrenderFunction and takes advantage of slots for data caching and updating. It’s defined insrc/core/components/keep-alive.jsIn:
export default {
  name: 'keep-alive',
  abstract: true. }Copy the code
  1. All abstract components are by definitionabstractOption. Abstract components do not render realityDOMAnd does not appear on the path of the parent-child relationship (initLifecycleWill ignore the abstract component), relevant code snippets:
if(parent && ! Options. Abstract) {// mask. Abstract '//whileLoop through the first non-abstract parent componentwhile (parent.$options.abstract && parent.$parent) {
    parent = parent.$parent
  }
  parent.$children.push(vm)
}
Copy the code

6. “understandingVue2.6 +The new globalAPI:Vue.observable()?”

The new global API for Vue2.6+ is vue.Observable (), which works like this:

import vue from vue;
const state = Vue.observable ({
   counter: 0,
});
export default {
   render () {
     return( <div> {state.counter} <button v-on:click={() => {state.counter ++; }}> Increment counter </ button> </ div> ); }};Copy the code

It is defined in line 48 of/SRC /core/global-api/index.js:

import { observe } from 'core/observer/index'/ /... // 2.6 Explicit Observable API Vue.Observable = <T>(obj: T): T => {observe(obj)return obj
}
Copy the code

Look at the observe import. The last commit was on 12/1/2018. HMM…

The core is to exposeobserve(obj)The code didn’t change anything after the observation. Got it?

Ask for a push in Shenzhen

At present, I am preparing for job-hopping. I hope that you and HR sister can promote a reliable front-end position in Shenzhen!

A collection of the author’s nuggets

  • Why do you never understand JavaScript scope chains?
  • “Vue Practice” project to upgrade vue-CLI3 correct posture
  • “Learn from source code” thoroughly understand the Vue option Props
  • “Learn from the source code” Vue source code in JS SAO operation
  • “Learn from source code” answers to Vue questions that interviewers don’t know

The public no. :