• Interviewer: Have you read the source code for Vue?
  • Candidate: Yes.
  • Interviewer: Would you say that if you change a property randomly in Vue Data, the view will be updated?
  • Candidate: No.
  • Interviewer: Why?
  • Candidate: If the property is not used in the template, there is no need to update the view frequently, which is not good performance.
  • Interviewer: How is the solution implemented in Vue?
  • Candidate: During instance initialization, theObject.definePropertyData listens for attributes in data. If the attributes are used in the template, they are collected by the Dep class and called when the attributes are changednotifyUpdate the view.
  • Interviewer: So how do you know which attributes are used in template?
  • Candidate: WTF… That’s not very clear. Could you explain it to me?
  • Interviewer: OK, let me explain briefly:

Let’s start with a simple demo where data has four attributes A, B, C, and D, and only a and B are used in the template. What if only A and B call Dep to collect it?

new Vue({
  el: '#app'.data() {
    return {
      a: 1.b: 2.c: 3.d: 4}; },created() {
    console.log(this.b);
    this.b = 'aaa';
  },
  template: '<div>Hello World{{a}}{{b}}</div>'});Copy the code
  1. The Vueinstance/state.jsInside, will useproxyProxy each property
const keys = Object.keys(data)
  const props = vm.$options.props
  const methods = vm.$options.methods
  let i = keys.length
  while (i--) {
    const key = keys[i]
    if(props && hasOwn(props, key)) { process.env.NODE_ENV ! = ='production' && warn(
        `The data property "${key}" is already declared as a prop. ` +
        `Use prop default value instead.`,
        vm
      )
    } else if(! isReserved(key)) {// Properties of the proxy object
      proxy(vm, `_data`, key)
    }
  }
  // observe data
  observe(data, true /* asRootData */)
Copy the code
  1. usingdefineReactiveHijacks each property in data
observe(data, true /* asRootData */);

// observe
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
  defineReactive(obj, keys[i]);
}

// defineReactive
Object.defineProperty(obj, key, {
  enumerable: true.configurable: true.get: function reactiveGetter() {
    const value = getter ? getter.call(obj) : val;
    // The important point here is that all subsequent properties used in the template will be implemented with the reactiveGetter function
    // is collected by the Dep class
    if (Dep.target) {
      console.log(`${key}Property is collected by the Dep class)
      dep.depend();
      if (childOb) {
        childOb.dep.depend();
        if (Array.isArray(value)) { dependArray(value); }}}return value;
  },
  set: function reactiveSetter(newVal) {
    const value = getter ? getter.call(obj) : val;
    /* eslint-disable no-self-compare */
    if(newVal === value || (newVal ! == newVal && value ! == value)) {return;
    }
    if (setter) {
      // Here is handling a computed SET function
      setter.call(obj, newVal);
    } else{ val = newVal; } childOb = ! shallow && observe(newVal);// If we change properties, we call notify asynchronously to update the viewdep.notify(); }});Copy the code
  1. perform$mountThe view is mounted
if (vm.$options.el) {
  vm.$mount(vm.$options.el);
}
Copy the code
  1. $mountIs to call the method on the Vue prototype, focusing on the last sentence mount.call(this, el, hydrating)
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
) :Component {
  el = el && query(el);

  const options = this.$options;
  // resolve template/el and convert to render function
  /** * check whether the render function exists. Render */ template */ template */ Vue */ template */
  if(! options.render) {let template = options.template;
    if (template) {
      if (typeof template === 'string') {
        if (template.charAt(0) = = =The '#') {
          template = idToTemplate(template);
          /* istanbul ignore if */
          if(process.env.NODE_ENV ! = ='production' && !template) {
            warn(
              `Template element not found or is empty: ${options.template}`.this); }}}else if (template.nodeType) {
        template = template.innerHTML;
      } else {
        if(process.env.NODE_ENV ! = ='production') {
          warn('invalid template option:' + template, this);
        }
        return this; }}else if (el) {
      // Create a default HTML template if the template does not existtemplate = getOuterHTML(el); }}Prototype.$mount (); // Vue. Prototype.$mount ()
  return mount.call(this, el, hydrating);
};
Copy the code
  1. heremountCall themountComponent(this, el, hydrating)Method, andmountComponentIs to perform the_renderDelta function, and finally_renderIs to callrenderTo generate avnode.
const { render, _parentVnode } = vm.$options;
vnode = render.call(vm._renderProxy, vm.$createElement);
Copy the code

The last one you can see isrenderThe function is in rendering our demotemplateTemplates, ultimately onlya, bIt takes two properties to beDepClass collected.

If there are mistakes in the article, please point out that I will continue to improve. Thank you, need to debug the source code, here click here, according to the readme operation. Hope under star. thank you