navigation

[Deep 01] Execution context [Deep 02] Prototype chain [Deep 03] Inheritance [Deep 04] Event loop [Deep 05] Curri Bias function [Deep 06] Function memory [Deep 07] Implicit conversions and operators [Deep 07] Browser caching mechanism (HTTP caching mechanism) [Deep 08] Front-end security [Deep 09] Deep copy [Deep 10] Debounce Throttle [Deep 10] Front-end routing [Deep 12] Front-end modularization [Deep 13] Observer mode Publish subscribe mode Bidirectional data binding [Deep 14] Canvas [Deep 15] webSocket Webpack HTTP and HTTPS CSS- Interview Handwriting Promise

[react] Hooks

[Deployment 01] Nginx [Deployment 02] Docker deployVue project [Deployment 03] gitlab-CI

[source code – Webpack01 – precompiler] AST abstract syntax tree [source code – Webpack02 – Precompiler] Tapable [source code – Webpack03] hand written webpack-compiler simple compilation process [source code] Redux React-redux01 [source] Axios [source] vuex [source -vue01] Data reactive and initialize render [source -vue02] Computed responsive – Initialize, access, Update procedure [source – vuE04] Watch Listen properties – Initialize and update [source -vue04] vue. set and VM.$SET

Front knowledge

Some words

My: primitiveCopy the code

Objects and arrays are not updated in a responsive manner

  • Objects are not updated responsively
    • The answer to a data Object is a getter/setter for an object.defineProperty
    • So: only respond to (modify) existing properties of the object, not (add) and (delete) properties of the object
    • The solution:
      • Add attributesVue.set() , vm.$set().Return a new Object with object.assign ({}, this.object, the Object to which new properties are added)
      • Delete the propertiesVue.delete().vm.$delete()
  • Arrays are not updated in response
    • Directly modify the values of array membersarr[0] = 1000
    • Change the length of the array directlyarr.length = 1000
    • The solution
      • 7 ways to use overwritten arrays: push pop unshift Shift splice sort reverse
      • 4. To add or modify:Vue.set() , vm.$set().splice
      • Delete:Vue.delete().vm.$delete().splice
    • Note:
      • When an array member is an object, the properties of the object that the array member is a member of are updated responsively
  • Website description: cn.vuejs.org/v2/guide/re…
  • case
<! DOCTYPE html> <html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
  <script src="./vue.js"></script>
</head>
<body>
  <div id="root">
    <div>{{this.obj}}</div>
    <div>{{this.arr}}</div>
    <button @click="change">change - will not respond </button> < button@click ="change2"< div> <script> new Vue({el:'#root',
      data: {
        obj: {
          number1: 1,
          number2: 2,
          number3: {
            number4: 4
          }
        },
        arr: [1, 2, {
          number5: 5
        }]
      },
      methods: {
        change() { this.obj.count = 1; Reflect.deleteproperty (this.obj, this.number2); This.arr [0] = 0; this.arr[0] = 0; This.arr. length = 100; // Change the length of the array, not rerender},change2() {// object vue.delete (this.obj,'number2'Vue.set(this.obj, this.obj)'count', 1) // Add attributes to object // array this.arr[2]. Number5 = 555; Var (this.arr, 3, 300); var (this.arr, 3, 300); // Add array member vue.set (this.arr, 0, 0) // Modify array member this.$set(this.arr, 0, 0) // Modify the value vm for a member of the array.$setMethod, the vm.$setThe instance method is an alias of the global method vue.set this.arr.splice(0, 1, }},}) </script> </body> </ HTML >Copy the code

(Observer class new Dep) and (defineReactive() new Dep) and (let childOb =! shallow && observe(val) )

  • New Dep in the Observer class
    • Dep = new dep () in the Observer class, which represents the deP corresponding to the observed object
  • New Dep in defineReactive()
    • DefineReactive () is executed for each attribute in the object, and dep = new dep () in defineReactive() is the deP for each attribute in the object
  • childOb = ! shallow && observe(val)
    • If the property of the object is an object, then childOb is an observer instance of the child object

(1) the Vue. The set () the source code

  • set – src/core/global-api/index.js
export function set(target: Array < any > | Object, key: any, val: any) : any {/ / / / parameter Array target or Object / / the key attributes of the Object or Array subscript, any type / / val any typeif(process.env.NODE_ENV ! = ='production' &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}') // If it is a development environment and the target is undefined, NULL, or the original data type, Throw a warning / / that is the target only object or array} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- handle arraysif(array.isArray (target) && isValidArrayIndex(key)) {// If target is an Array type, Target. Length = math.max (target.length, key) // Take a larger value // For example: // target => [1,2,3] // vue.set (target, 3, 4) // 1.target. Length = 3 // 2.key = 3 // 12 Max = 3 // end: [1,2,3].splice(3, 1, 4) => [1,2,3,4] target. Splice (key, 1, val) => [1,2,3,4] targetreturnVal / / Vue. Set the return value of a ()} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- processing objectif (key intarget && ! (keyinObject.prototype)) {// return target[key] = valreturn val
  }

  const ob = (target: any).__ob__

  if(target. _isVue | | (ob && ob. VmCount)) {/ / if the target is the vue instance or rootData process. The env. NODE_ENV! = ='production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }

  if(! // if ob does not exist, target.__ob__ does not exist. // If ob does not exist, target.__ob__ does not existreturn// defineReactive(ob.value, key, val) // defineReactive(ob.value, key, val) // 1. The function is to add responses to the key attribute of the value object, access get dependency collection, and modifyset// ob.value = value // There are three parameters, so val is directly passed in // 3. Important points in defineReactive(ob.value, key, val) // collection of child object attribute dependencies:letchildOb = ! Shallow && Observe (val) If the value is still an object, the dependency collection will continue to observe and become reactive // The dependency collection will continue on the child object itself: ChildOb exists, childob.dep.depend (), DefineReactive (ob.value, key, val) update is not updated until the value has been modified. // target.__ob__ = new Observer(target) // ob.dep.notify() = target.__ob__.dep.notify( Note that the dep of the target object updates the target value from the new render // ob.dep.notify() is the focusreturn val
}
Copy the code
  • Observer – src/core/global-api/index.js
export class Observer {
  value: any;
  dep: Dep;
  vmCount: number; // number of vms that have this object as root $dataconstructor (value: Any) {// value = data this.value = value this.dep = new dep () // dep => The dep in the Observer class is mainly for passing Value.__ob__.dep.depend method to do dependency collection // mainly used for // childOb =! shallow && observe(val) => childOb = new Observer(value) // childOb.dep.depend() this.vmCount = 0 def(value,'__ob__', this)
    // def(value, '__ob__'__ob__ = this // the difference is: the __ob__ of the def() method is not enumerable and will not befor.forEach traverses the propertyif(array.isarray (value)) {// Arrayif(hasProto) {// Inherit protoAugment(value, __proto__ = arrayMethods) // value.__proto__ = data.__proto__ = arrayMethods // arrayMethods bind 7 custom methods, when accessing these 7 methods, Trigger mutator method // mutator // 1. First the native 7 methods will be called as normal and return the value // 2. // (2-1) push unshift splice assigns the added elements to an array // (2-2) if inserted, Execute ob.observeArray(inserted) // (2-3) ob.dep.notify() to manually distribute an update, updating the page}else{// augment (value, arrayMethods, arrayKeys) // def(target, key, src[key] // value.key = arrayMethods[key] } this.observeArray(value) }else{// object this.walk(value)}}Copy the code
  • defineReactive – src/core/observer/index.js
export functiondefineReactive ( // defineReactive(obj, keys[i]) obj: Object, key: string, val: any, customSetter? :? Function, shallow? : boolean ) { const dep = new Dep() const property = Object.getOwnPropertyDescriptor(obj, key)if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  const getter = property && property.get
  const setter = property && property.set
  if((! Getter | | setter) && the arguments. Length = = = 2) {/ / if (getter or setter exists) is not present and (number of arguments is 2) / / 1. The defineReactive(obj, keys[I]) full tree argument is initialized with length 2 // 2. The getter and the setter are both initializedfalseVal = obj[key] val = obj[key]} val = obj[key]}letchildOb = ! shallow && observe(val) // 1. ! Shallow => Initialize data; shallow = undefined; // 2.observe (val) => Continue to observe the data properties // If the data properties are not objects or arrays, Terminating execution // If the data attribute is still an object or array, Ob = new Observer(value) => return ob // New Observer(value) object.defineProperty (obj, key, {enumerable:true,
    configurable: true,
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if(childOb) {// if the data attribute is still an object, childOb exists childob.dep.depend () // childob.dep.depend () // collect dependencies for each attribute of all nested objects, Updates can also be dispatched when properties corresponding to nested objects are accessedif(array.isarray (value)) {// If the data attribute is an Array dependArray(value) //function dependArray (value: Array<any>) {
            //   for (lete, i = 0, l = value.length; i < l; I++) {/ / e = value [I] / / e & e. __ob__ && e. __ob__. Dep. Depend () / / / / (value [I] __ob__) is (calls Value [I] __ob__. Dep. Depend ()) / / / / note: / / / / __ob__ attributes only observed (object or array) with / /if(Array. IsArray (e)) {/ / dependArray (e) / / / / or Array, recursive / /} / / / /}}}}}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
      }
      /* eslint-enable no-self-compare */
      if(process.env.NODE_ENV ! = ='production' && customSetter) {
        customSetter()
      }
      // #7981: for accessor properties without setter
      if(getter && ! setter)return
      if (setter) {
        setter.call(obj, newVal)
      } else{ val = newVal } childOb = ! shallow && observe(newVal) dep.notify() } }) }Copy the code

(1-1) Vue.set() Case process analysis

  • case
<! DOCTYPE html> <html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
  <script src="./vue.js"></script>
</head>
<body>
  <div id="root">
    <div>{{this.obj}}</div>
    <button @click="change">change</button>
  </div>
  <script>
    new Vue({
      el: '#root',
      data: {
        obj: {
          a: 1
        }
      },
      methods: {
        change() {
          debugger
          Vue.set(this.obj, 'b', 2)
        }
      },
    })
  </script>
</body>
</html>
Copy the code
  • Process analysis
  1. The data to initialize
    • The first initialization of data, because there are nested objects, will passlet childOb = ! shallow && observe(val)Continue to observe the child objects until all properties are responsive
  2. Initialize mount and render
    • Accessed in the templatethis.objSo it accesses data,obj, and all the properties in OBj, and renders them
    • Note:
      • When accessing rootData, let childOb =! Shallow && Observe (val) returns obJ’s observer
      • So: childob.dep.depend () can collect dependencies on the DEp of an obj object
      • Update: when vue.set () is set, the response to OBj. B = 2 is established
  3. Vue.set(this.obj, ‘b’, 2)
    • Warning when obj is undefined,null, and a primitive data type
    • Processing arrays:
      • The changes, adds, and deletes are all done by rewriting target.splice(key, 1, val), the target values to be processed are constructed into an array, observed through ob.observeArray(val), and then ob.dep.notify() manually assigns updates, However, the changed value is reflected on the DOM
    • Reactive processing objects – (that is, value.ob= Observer exists)
      • DefineReactive (ob.value, key, val) creates a new response to the added object attributes
      • Then ob.dep.notify() notifies manually, because the child object obj of data has been let childOb =! Shallow && Observe (val) => childob.dep.depend (
    • A normal nonresponsive object
      • Direct assignment

(2) vm.$set – is the alias of the global vue.set.

(3) Vue.delete

  • Vue.delete = del
  • The source code
export function del (target: Array<any> | Object, key: any) {
  if(process.env.NODE_ENV ! = ='production'&& (isUndef (target) | | isPrimitive (target))) {/ / if it is a development environment And (target is undefined, or primitive data types is warning) warn (` always delete reactive property on undefined, null, or primitive value:${(target: any)}')} // the -------------- arrayif(array.isarray (target) && isValidArrayIndex(key)) { Target. Splice (key, 1); // Delete the member corresponding to the index from the array using the overwritten splicereturn} // -------------- const ob = (target: __ob__ // Each observed object has a __ob__ attribute // in the constructor of the Observer class, which passes the target.__ob__ = this, Point to the Observer instance // The OBSERVER instance has the DEP propertyif(target. _isVue | | (ob && ob. VmCount)) {/ / if the target is the vue instance or rootData process. The env. NODE_ENV! = ='production' && warn(
      'Avoid deleting properties on a Vue instance or its root $data ' +
      '- just set it to null.'
    )
    return
  }

  if(! HasOwn (target, key)) {// not its own attributereturn} delete target[key] // Delete the properties of the objectif(! ob) {return} ob.dep.notify() // Manual notification}Copy the code