Detailed explanation of the data responsiveness principle of Vue

Detailed explanation of the data responsiveness principle of Vue

This article is mainly for those who do not understand or have not been exposed to the Vue responsive source code. Its main purpose is to have a basic understanding of the responsive principle of Vue. If you are asked such questions in an interview, you will know what the interviewer wants you to answer? PS: If there is anything wrong in the article, you are welcome to correct it.

Responsive understanding

Responsiveness, as the name implies, means that data changes will cause the view to be updated. This article mainly analyzes the implementation of object and array responsiveness in Vue2.0. We will leave dependency collection and view update to the next article.

In Vue, the responsive data we refer to generally refers to array type and object type data. Vue internally hijacks the properties of an object through the Object.defineProperty method, and the array is implemented by overriding the array method. Let's simply implement it below.

First, we define the data that needs to be intercepted.

const vm = new Vue({
 data () {
  return {
   count: 0,
   person: { name: 'xxx' },
   arr: [1, 2, 3]
  }
 }
})
let arrayMethods
function Vue (options) { // Only consider the operation of data here let data = options.data
 if (data) {
  data = this._data = typeof data === 'function' ? data.call(this) : data
 }
 observer (data)
}
function observer(data) { 
 if (typeof data !== 'object' || data === null) {
  return data
 }
 if (data.__ob__) { // The existence of the __ob__ attribute indicates that it has been intercepted return data
 }
 new Observer(data)
}

Please continue reading below for the implementation and function of arrayMethods, Observer, and __ob__

Implementing the Observer Class

class Observer {
 constructor (data) {
  Object.defineProperty(data, '__ob__', { // Define the __ob__ property on data, which is needed in array hijacking enumerable: false, // Not enumerable configurable: false, // Not configurable value: this // The value is the Observer instance })
  if (Array.isArray(data)) { //Intercept the array data.__proto__ = arrayMethods //Prototype inheritance this.observerArray(data)
  } else { // Object interception this.walk(data)
  }
 }
 walk (data) {
  const keys = Object.keys(data)
  for(let i = 0; i < keys.length; i++) {
   const key = keys[i]
   defineReactive(data, key, data[key])
  }
 }
 observerArray (data) { // intercept each item in the array data.forEach(value => observer(value))
 }
}

Object interception

A few points to note about object hijacking:

  • Traverse the object. If the value is still an object type, you need to call the observer method again.
  • If the new value set is an object type, it also needs to be intercepted
//Intercept function of processing object defineReactive(data, key, value) {
 observer(value) // If value is still an object type, you need to recursively hijack Object.defineProperty(data, key, {
  get() {
   return value
  },
  set(newValue){
   if (newValue === value) return
   value = newValue
   observer(newValue) // If the newValue value is also an object type, it needs to be hijacked}
 })
}

Array hijacking

A few points to note about array hijacking:

  • Arrays use the idea of ​​function hijacking (slice programming) to intercept data
  • Newly added values ​​in the array, if they are object types, also need to be re-intercepted
const oldArrayPrototype = Array.prototype
arrayMethods = Object.create(oldArrayPrototype)
const methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'] // Methods that can change the original array methods.forEach(method => {
 arrayMethods[methods] = function (...args) {
  const result = oldArrayPrototype[methods].call(this, ...args)
  const ob = this.__ob__ // this is the array that calls the method let inserted; // The collection of newly added items in the array needs to be intercepted switch(methods) {
   case 'push': 
   case 'unshift':
    inserted = args
   case 'splice':
    inserted = args.slice(2) // Because the second parameter of splice is the one that is added}
  if (inserted) {
   ob.observerArray(inserted)
  }
  return result
 }
})

Principle Summary

In the interview, if we need to hand-write the responsiveness principle of Vue, the above code is enough. However, by learning the source code of Vue, if we can give the following summary answers in the interview, we will be more favored by the interviewer.

The responsive principle of Vue 2.0 source code:

  • Because objects are intercepted recursively, the deeper the data level, the worse the performance.
  • Arrays are not intercepted using Object.defineProperty because performance will be poor if there are too many array items.
  • Only the data defined in data will be intercepted. The attributes we add later on the instance through vm.newObj = 'xxx' will not be intercepted.
  • Changing the index and length of the array will not be intercepted, so it will not cause the view to update.
  • If you need to intercept the addition of new attributes to data and the change of array index and length, you can use the $set method
  • You can use the Object.freeze method to optimize data and improve performance. The data using this method will not be rewritten by the set and get methods.

Vue 3.0 source code responsive principle:

  • In version 3.0, proxy is used instead of Object.defineProperty. It has 13 interception methods. It does not need to process objects and arrays separately, nor does it need to intercept recursively. This is also the biggest performance improvement.
  • Simple implementation of the responsive principle of Vue 3.0 version
const handler = {
 get (target, key) {
  if (typeof target[key] === 'object' && target[key] !== null) {
   return new Proxy(target[key], handler)
  }
  return Reflect.get(target, key)
 },
 set (target, key, value) {
  if(key === 'length') return true
  console.log('update')
  return Reflect.set(target, key, value)
 }
}
const obj = {
 arr: [1, 2, 3],
 count: { num: 1 }
}
// obj is the target object of the proxy, handler is the configuration object const proxy = new Proxy(obj, handler)

This is the end of this article on the detailed explanation of the data responsiveness principle of Vue. For more relevant Vue data responsiveness content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of the array of Vue data responsiveness principle
  • In-depth understanding of Vue's data responsiveness
  • Vue data responsiveness summary
  • Summary of knowledge points about Vue data responsiveness principle
  • How is Vue data responsiveness implemented?
  • A brief discussion on the principle of Vue data responsiveness
  • Vue explains the principle of data responsiveness in depth

<<:  Docker learning method steps to build ActiveMQ message service

>>:  MySQL 5.7.16 installation and configuration method graphic tutorial (Ubuntu 16.04)

Recommend

JavaScript Canvas draws dynamic wireframe effect

This article shares the specific code of JavaScri...

WeChat applet implementation anchor positioning function example

Preface In the development of small programs, we ...

Basic usage of @Font-face and how to make it compatible with all browsers

@Font-face basic introduction: @font-face is a CSS...

A brief analysis of React Native startReactApplication method

In this article, we sorted out the startup proces...

Html tips to make your code semantic

Html semantics seems to be a commonplace issue. G...

A brief understanding of the differences between MySQL InnoDB and MyISAM

Preface MySQL supports many types of tables (i.e....

How to remove the blue box that appears when the image is used as a hyperlink

I recently used Dreamweaver to make a product pres...

5 Ways to Send Emails in Linux Command Line (Recommended)

When you need to create an email in a shell scrip...

MySQL query optimization: a table optimization solution for 1 million data

1. Query speed of two query engines (myIsam engin...

Example of implementing element table row and column dragging

The element ui table does not have a built-in dra...

js implements mouse in and out card switching content

This article shares the specific code of js to re...

Examples of preview functions for various types of files in vue3

Table of contents Preface 1. Preview of office do...

Summary of MySQL database and table sharding

During project development, our database data is ...

Detailed explanation of adding click event in echarts tooltip in Vue

Table of contents need Workaround 1. Set tooltip ...

Solutions to MySQL OOM (memory overflow)

OOM stands for "Out Of Memory", which m...