zoukankan      html  css  js  c++  java
  • Vue源码之----为什么Vue中Array的pop,push等方法可以reactive,而Array[0]='a'这样的方法不会reactive?

     initData--->observe(data)做的事情是:

    data的__ob__指向一个observer,observer中有一个Dep

    一、如果data是一个普通对象(非数组),遍历其属性(比如a),重写a的get和set方法,get方法的闭包中有两个重要属性:

    1、一个Dep类型的属性(简称getDep)

    2、递归observe(data.a)的返回值:Observer类型的childOb属性,

    当get方法被调用的时候,getDep+ childOb的dep收集栈顶的watcher,当set方法被调用的时候,收集的watcher被调用update方法

    二、如果data是一个数组,因为data是根节点,会报错,为了讨论observe数组的情况,假定data.a的值是一个数组b,接着上面说的递归observe(b):

    一样的新建一个Observer,赋值给b的__ob__属性,接下来发现b是数组,把b的__proto__属性指向一个arrayMethods对象,arrayMethods的__proto__指向的是Array.prototype,重写b的push等方法,重写后的逻辑是先调用Array的push,再调用b的__ob__指向的

    observer中的dep.notify。

    data()方法的返回值以及watch,props,computed里面的属性,,在这之前都会被defineReactive方法重写get和set方法(get方法重写为调用的时候收集Dep这个静态变量指向的watcher,set方法调用的时候会notify收集的watchers,调用每个watcher的update--->run--->get方法)和methods里面的方法一起,被挂载到vm实例上(所以methods里面this.XXX才有用,因为调用method的是 vm,属性也在vm上)

    -----------------所以如果想要对象(比如a)的属性b的set方法能引起重新渲染,必须在b被get的时候,收集到可以引起重新渲染的watcher。那么是什么时候收集的呢?

    每一个vm有一个render Watcher,在mountComponent的时候生成,render Watcher的expOrFn方法是 vm._update(vm._render(), hydrating)--->vm.__patch__(prevVnode, vnode),(对比新旧虚拟节点,操作真实node),在这个过程中,vm._render()会按照Vue的<template>中的内容,为每一个子节点

    生成属性,查看render的代码会发现有个with(this),这里this就是vm,就是要调用vm的属性的get方法给虚拟节点的属性赋值。然后再进行对比等操作。在这个过程中,被调用get方法的属性就会收集renderWatcher。

    -----------------那为什么array[0]='a'这样的方法不会重新渲染?

    因为array的0这个属性?,没有重写get和set方法

    -----------------为什么pop push可以reactive?

    比如a.b=c,reactive的过程是: observe(a)---> defineReactive(b)--->重写b的get方法之前先observe(c)。observe c的时候,如果判断c是一个数组,protoAugment方法中,c的__proto__会指向arrayMethods这个对象,

    而arrayMethods的__proto__指向Array.prototype,但是其push等属性重写了,先调用Array原来的相应方法等等一系列操作,再调用收集的watcher的update方法,如果收集了renderWatcher,就会reactive

    -----------------对象的dep从哪里来?

    上面说过,observe(c),new一个Observer 实例childOb,c的_ob_属性指向childOb,childOb里面有一个dep属性,而在b的重写的get方法中,会有childOb.dep.depend()的执行

    -----------------灵魂第五问:既然是给b重写set和get的时候,给c的_ob_的dep收集Watcher,那么数组里面的元素比如array[0]=d,而d恰好是数组,为什么d.push也可以reactive?

    在childOb.dep.depend()方法下面还有个if,如果属性指向的是个数组,遍历数组中的元素,使其observer的dep属性收集renderWatcher。所以array[0]='a'是不能reactive的,但是array[0].push('a')是可以reactive的

  • 相关阅读:
    洛谷 P1236 算24点
    洛谷 P1483 序列变换
    洛谷 P2071 座位安排 seat.cpp/c/pas
    洛谷 P3079 [USACO13MAR]农场的画Farm Painting
    洛谷 P3912 素数个数
    洛谷 P1617 爱与愁的一千个伤心的理由
    洛谷 P1894 [USACO4.2]完美的牛栏The Perfect Stall
    hdu_5908_Abelian Period(暴力)
    hdu_4283_You Are the One(区间DP)
    hdu_5903_Square Distance(dp)
  • 原文地址:https://www.cnblogs.com/chuliang/p/10360541.html
Copyright © 2011-2022 走看看