Have you ever been asked to build a rocket in a job interview?

I don’t want to complain because I’m the kind of interviewer who makes interviewees build rockets 🙂

This paper will analyze the causes of this situation from the underlying logic and put forward sincere suggestions.

Video tutorial

The village head specially recorded a supporting video and led everyone to pull out their mini Vue hand in hand:

From handwriting Vue to interview strategy analysis

Welcome to three small partners + attention, your encouragement is the biggest power I insist on ❤️

Why do interviews build rockets

Because the supply and demand of the market has changed, it used to be Spears, now it’s Mrs. Cow. It’s not like looking for a job 6 or 7 years ago. With more competitors, employers are more selective and choose more competent and motivated employees for the same amount of money. At the same time, interviewers found that everyone’s CV was the same: proficient in vUE framework and bucket, proficient in usingelement-ui,iViewSuch as component library, skilled useaxiosGet server-side data and so on. If the difficulty of the interview is not increased, it is difficult to distinguish between the competence of the interviewer and that of the interviewer.

How to deal with the problem of building rockets

For example, when the interviewer asks,

  • Why do WE need data responsiveness?vueHow is it implemented?
  • Why virtualdom?diffWhat’s the process like?

Friends choose to find the answer, recite down, you can not solve the problem, because the answer is dead, can not stand scrutiny, a little questioning a few times will reveal.

I think we should take this opportunity to learn the source code, not only to find the answer to the question, deepen the UNDERSTANDING of THE API, but also to learn a lot of algorithms, design patterns and engineering knowledge, to improve the programming level is very helpful.

What if source code is difficult to learn

Many partners also want to read the source code to learn, but the source code is usually very large and complex, it is easy to discourage. I suggest you start with a mini implementation. Lay a good foundation first, after master to look at the source will be much simpler.

Try building a rocket

I’ll take Vue as an example, write a mini version, and then we’ll worry about building rockets.

Vue’s design philosophy

Before we start, let’s take a look at the design philosophy of Vue so that it will be easier to understand later:

Easy to understand, friendly, high-performance, easy to maintain, testable

Feel it in the code

Vue not used, 01-no-vue.html:

<div id="app"></div>

<script>
  / / requirements:
  // 1. There is a title title that you want to display in the H3 tag
  // The title will change after 2.2 seconds
  const title = 'I'm a headline.'
  const h3 = document.createElement('h3')
  h3.textContent = title
  app.appendChild(h3)
  setTimeout(() = > {
    h3.textContent = 'I still have the same title, but I've changed.'
  }, 2000);
</script>
Copy the code

Features are:

  • The user wants direct access to the DOM
  • Dom manipulation is also part of the business
  • The user’s mental burden is heavier, and the development efficiency is lower

Use Vue, 02-with-vue.html:

<div id="app">
  <h3>{{title}}</h3>
</div>

<script src="http://unpkg.com/vue"></script>
<script>
  / / requirements:
  // 1. There is a title title that you want to display in the H3 tag
  // The title will change after 2.2 seconds
  new Vue({
    data() {
      return {
        title: 'I'm a headline.'}},mounted() {
      setTimeout(() = > {
        this.title = 'I still have the same title, but I've changed.'
      }, 2000);
    },
  }).$mount('#app')
</script>
Copy the code

The important change is that our app is data-driven and avoids DOM manipulation, so our goal is clear:

  • Be able to tell when the data has changed
  • View updates can be performed after changes

Try building a wheel

Basic structure: Vue constructor and $mount method

<div id="app"></div>

<script>
  function Vue(options) {}
  Vue.prototype.$mount = function() {}
</script>
Copy the code

DefineProperty is used to realize data responsiveness and monitor data changes in data

function Vue(options) {
  / / response type
  this.$options = options
  this.$data = options.data()
  observe(this.$data)
}
Vue.prototype.$mount = function () {}
// select * from obj
function observe(obj) {
  Object.keys(obj).forEach(key= > {
    defineReactive(obj, key, obj[key])
  })
}
// Reactive intercepts object property access
function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get() { return val },
    set(newVal) { val = newVal }
    }
  })
}
Copy the code

Mount: Prepares an update function for view initialization and subsequent updates

<script>
  Vue.prototype.$mount = function (sel) {
    // Create the update function
    this.update = function () {
      const child = this.$options.render.call(this)
      const parent = document.querySelector(sel)
        
      if (!this.isMounted) {
        // init
        parent.appendChild(child)

        this.isMounted = true
        if (this.$options.mounted) {
          this.$options.mounted.call(this)}}else {
        // update
        parent.innerHTML = ' '
        parent.appendChild(child)
      }
    }

    this.update()
  }
  function observe(obj) {}
  function defineReactive(obj, key, val) {
    Object.defineProperty(obj, key, {
      get() {},
      set(newVal) {
        if(newVal ! == val) {// Trigger the updateapp.update(); }}})}</script>
Copy the code
<script>
  const app = new Vue({
		// Add the render function to render the DOM
    render() {
      const h3 = document.createElement('h3')
      h3.textContent = this.$data.title
      return h3
    }
  })
</script>
Copy the code

Problem: Each update is a full update to the view

Vnode based implementation to avoid full updates

<script>
  Vue.prototype.$mount = function (sel) {
    this.update = function () {
      // Execute render to get the vnode
      const vnode = this.$options.render.call(this.this.createElement)
      
      if (!this.isMounted) {
        // init patch: pass parent to dom
        const parent = document.querySelector(sel)
        this.patch(parent, vnode)
      } else {
        // Update patch: Pass two VNodes to diff
        this.patch(this._vnode, vnode)
      }

      this._vnode = vnode
    }

    this.update()
  }

  // Add a vnode generator
  Vue.prototype.createElement = function (tag, props, children) {
    return { tag, props, children }
  }

  // Patch is used to convert vNode to DOM during initialization or update
  Vue.prototype.patch = function (n1, n2) {
    if (n1.nodeType) {
      // init
      const child = this.createElm(n2)
      n1.appendChild(child)
      n2.$el = child
    } else {
      // update}}// Create elements recursively
  Vue.prototype.createElm = function (vnode) {
    const {tag, props, children} = vnode
    const el = document.createElement(tag)
    / / create the children
    if (Array.isArray(children)) {
      // element
      children.forEach(child= > el.appendChild(createElm(children)))
    } else {
      // text
      el.textContent = children
    }
    vnode.$el = el
    return el
  }
</script>
Copy the code
<script>
  const app = new Vue({
    // render returns vnode
    render(h) {
      return h('h3'.null.this.$data.title)
    }
  })
  app.$mount('#app')
</script>
Copy the code

Update logic: Mainly depending on the children type of both parties, dom operation is performed specifically. Only the text in the test case is solved here

Vue.prototype.patch = function (n1, n2) {  if (n1.nodeType) {} else {    Dom const el = n2.$el = n1.$el // children update if (n1.tag === n2.tag) { If (typeof n1.children === 'string') {if (typeof n2.children === 'string') {// text update if (n1.children! == n2.children) { el.textContent = n2.children } } else { // replace text with elements } } else { if (typeof n2.children === 'string') { // replace elements with text } else { // update children } } } else { // replace } }
Copy the code

Now think about the answer strategy

Use four paragraphs: introduce the concept, explain the necessity, how to implement the source code, and how to use it in practice. Such as:

  • Why do WE need data responsiveness? How does it work?

    Introduction to the concept: Data responsiveness is a mechanism for detecting changes in data in frameworks like MVVM, and varies among the three frameworks.

    Necessity: The most important task of MVVM is to realize data-driven. To realize data-driven, it is necessary to know when data changes and respond to them, which requires a data-responsive mechanism.

    Source code implementation: Vue 2.x mainly use defineProperty, vue 3.x mainly use Proxy (do not know not to mention). Take Vue 2.x as an example by traversing object attributes, defining GET /set, and doing attribute interception. In the future, data changes can be sensed and update functions can be called to update the view.

    In practice: In practice, we pass in component props, methods, and data, all of which are handled responsively during Vue initialization, so that when they change, the view is re-rendered and updated. There are also special cases where new attributes are added or deleted and apis like vue. set/delete are required.

Of course, you still have to learn a lot of details, such as:

  • How to notify views of updates
  • How views are updated (virtual DOM and patch)
  • What’s wrong with responsiveness in Vue 2.x (efficiency, extra API, array handling, etc.)
  • Why do we need an API like vue. set/delete

You can see that all of them are derived from the point of responsiveness, and if you answer them properly, there’s basically no problem.

Example source code

Pay attention to the public number “village head learning front”

Video tutorial

The village head specially recorded a supporting video and led everyone to pull out their mini Vue hand in hand:

From handwriting Vue to interview strategy analysis

Welcome to three small partners + attention, your encouragement is the biggest power I insist on ❤️