最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue源码分析(七)

    正文概述 掘金(cherish553)   2020-11-30   435

    一、响应式对象

    vue是通过bject.defineProperty进行数据劫持,把数据变成响应式的,这也是vue的一个核心思想

    在执行_init的时候会执行initState函数,initState中,会通过initPropsinitData来初始化props和data

    export function initState (vm: Component) {
      // src/core/instance/state.js
      ...
      if (opts.props) initProps(vm, opts.props)
      if (opts.data) {
        initData(vm)
      }
      ...
    }
    

    initData函数会调用observe(data, true /* asRootData */)函数,observe函数首先会判断他是否是一个对象,如果不是一个对象,或者它是一个vnode,那么就不会接着执行。之后会判断传入的data是否有通过Observer类构造出的__ob__属性,如果有的话,则说明他已经是一个响应式的对象,则ob直接使用之前的data.__ob__,如果不满足,那么会判断shouldObserveshouldObserve定义在当前文件,默认为true,通过toggleObserving方法可以进行值的修改,在initProps的时候,会判断props是否是一个根部的props,如果是(则不需要变为响应式),会通过toggleObserving先变为false,执行到最后再变为true。接着会判断他是否是一个数组,或对象,并且会通过Object.isExtensible判断他是否是一个可扩展的对象,所以如果想阻止data中的一些恒量变为响应式的,通过Object.freeze即可。最后会调用new Observer(value)

    // src/core/observer/index.js
    /**
     * Attempt to create an observer instance for a value,
     * returns the new observer if successfully observed,
     * or the existing observer if the value already has one.
     */
    export function observe (value: any, asRootData: ?boolean): Observer | void {
      if (!isObject(value) || value instanceof VNode) {
        return
      }
      let ob: Observer | void
      if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
        ob = value.__ob__
      } else if (
        shouldObserve &&
        !isServerRendering() &&
        (Array.isArray(value) || isPlainObject(value)) &&
        Object.isExtensible(value) &&
        !value._isVue
      ) {
        ob = new Observer(value)
      }
      if (asRootData && ob) {
        ob.vmCount++
      }
      return ob
    }
    

    在执行new Observer的时候,会调用def(value, '__ob__', this)def定义在 src/core/util/lang.js下,他通过Object.defineProperty来控制这个对象属性的enumerable是true,还是false(是否可枚举)。当前的__ob__是不可被枚举的。然后会判断他是否是一个数组,如果不是一个数组,会调用walk方法,如果是数组,会遍历数组去调用observe方法,会再次new Observer这样会让数组中的对象最终都会调用walk函数。walk函数会遍历对象,然后调用defineReactive函数,这样就可以解释为什么会对__ob__做不可枚举的处理,因为__ob__使用者并不会手动去修改,也就不需要是一个响应式的属性。

    // src/core/observer/index.js
    /**
     * Observer class that is attached to each observed
     * object. Once attached, the observer converts the target
     * object's property keys into getter/setters that
     * collect dependencies and dispatch updates.
     */
    export class Observer {
      value: any;
      dep: Dep;
      vmCount: number; // number of vms that have this object as root $data
    
      constructor (value: any) {
        this.value = value
        this.dep = new Dep()
        this.vmCount = 0
        def(value, '__ob__', this)
        if (Array.isArray(value)) {
          if (hasProto) {
            protoAugment(value, arrayMethods)
          } else {
            copyAugment(value, arrayMethods, arrayKeys)
          }
          this.observeArray(value)
        } else {
          this.walk(value)
        }
      }
    
      /**
       * Walk through all properties and convert them into
       * getter/setters. This method should only be called when
       * value type is Object.
       */
      walk (obj: Object) {
        const keys = Object.keys(obj)
        for (let i = 0; i < keys.length; i++) {
          defineReactive(obj, keys[i])
        }
      }
    
      /**
       * Observe a list of Array items.
       */
      observeArray (items: Array<any>) {
        for (let i = 0, l = items.length; i < l; i++) {
          observe(items[i])
        }
      }
    }
    

    defineReactive函数首先他会尝试拿到他原始的configurable,enumerable,value,writable,然后会去获取他的getset,如果没有getter或者有setter(该属性是一个对象)并且该函数传入了两个参数,那么会去执行observe这样就保证了对象中的属性值是一个对象,也会变成响应式的。最后通过Object.defineProperty给该属性绑定getter(依赖收集)和setter(派发更新),而initProps最终也会调用defineReactive把props变为响应式的

    
    /**
     * Define a reactive property on an Object.
     */
    export function defineReactive (
      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) && arguments.length === 2) {
        val = obj[key]
      }
    
      let childOb = !shallow && observe(val)
      Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter () {
          ...
        },
        set: function reactiveSetter (newVal) {
          ...
        }
      })
    }
    
    

    起源地下载网 » vue源码分析(七)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元