Vue的data的BUG

Object. DefineProperty problem

  • Object.defineProperty(obj,'n',{... })

  • There must be an ‘n’ in order to listen & proxy obj.n

  • But if the developer is careless and doesn’t give n, or if they give n and they don’t assign to n

    import Vue from "vue/dist/vue.js";
    
    Vue.config.productionTip = false;
    
    new Vue({
      data: {
        obj: {
          a: 0 // obj. A will be listened by Vue & proxy, a is 'n'}},template: ` 
            
    {{obj.b}}
    `
    .methods: { setB() { this.obj.b = 1; } } }).$mount("#app"); Copy the code

    If I write this, Vue will not give a warning. If I click setB, will the page show 1?

    The answer is no, because Vue doesn’t listen to OBJ.B, which doesn’t exist in the first place

    The solution

    1. It would have been better to have declared at the beginning (this is true nonsense, once declared at the beginning, there would not have been this problem)
    2. useVue.setorthis.$set
    new Vue({
      data: {
        obj: {
          a: 0}},template: ` 
            
    {{obj.b}}
    `
    .methods: { setB() { Vue.set(this.obj,'b'.1) / / or enclosing $set (enclosing obj, 'b', 1) } } }).$mount("#app"); Copy the code

    Click the button and the page will display a 1

Vue. Set and this.$set

  • The new key
  • Automatically create agents and listeners (if not already created)
  • Trigger UI update (but not immediately)

Array variation

new Vue({
  data: {
    array: ["a"."b"."c"]},template: ` 
      
{{array}}
`
.methods: { setD() { this.$set(this.array,3.'d'); } } }).$mount("#app"); Copy the code

When you click the button like this, there’s no way to add ‘D’, because there’s no way to declare index 3 in the array

So Yuxi had an idea

methods: {
    setD() {
      this.array.push('d')}}Copy the code

Perfect solution ~

But if we print out the new array, we’ll find that the prototype of the new array has been modified

In other words, this array object, once passed to Vue, Vue will tamper with the array, it will add a layer of prototypes in the middle

How?

It’s basically adding a chain of prototypes,

Take push as an example, the general idea is as follows:

class VueArray extends Array{
    push(. args){
        const oldLength = this.length// This is the current array
        super.push(... arg)//super.push calls push on my parent class
        console.log('Vue knows you pushed ')
        for(let i = oldLength; i<this.length; i++){ vue.set(this,i,this[i])
        }
    }
}
Copy the code

Vue tampers with push, and then notifies Vue of push changes via vue.set, which tells Vue that the array has changed

conclusion

The new key in the object

  • Vue has no way to listen and proxy in advance
  • You use set to add keys, create listeners and proxies, and update the UI
  • But it’s a good idea to write all the properties out ahead of time

The new key in the array

  • Yuxi tampered with seven apis to make it easier to add and delete arrays
  • These seven apis automatically handle listeners and proxies and update them