zoukankan      html  css  js  c++  java
  • vue2.x源码解析(第四部分)

    渲染函数的作用域添加代理

    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }

    上面这段代码可以看到在非生产环境下执行了initProxy函数,参数是实例;在生产环境下设置了实例的_renderProxy属性为实例自身,那么先来看看 initProxy函数,这个函数在core/instance/proxy.js文件下。

    initProxy = function initProxy (vm) {
        //判断是否支持ES6的Proxy或存在Proxy函数
        const hasProxy =typeof Proxy !== 'undefined' && isNative(Proxy)
        ...
        //支持Proxy
        if (hasProxy) {
          // determine which proxy handler to use
          //缓存合并选项后的vm.$options
          const options = vm.$options
          //_withStripped这个属性只在测试代码中出现过所以一般为false,也就是赋值为hasHandler
          const handlers = options.render && options.render._withStripped
            ? getHandler
            : hasHandler
          //为vm实例添加代理,对以下情况时进行拦截
          /*
            1、属性查询: foo in proxy
            2、继承属性查询: foo in Object.create(proxy)
            3、with 检查: with(proxy) { (foo); }
            4、Reflect.has()
          */    
          vm._renderProxy = new Proxy(vm, handlers)
        } else {
          vm._renderProxy = vm
        }
    }

    可以看到开头就是一个判断变量hasProxy,其作用是确定该环境是否支持Proxy,当支持情况下继续执行下面的代码: 读取实例的$options属性, 最后为实例添加_renderProxy属性,这样就和生产环境一致了。只不过对当读取_renderProxy的属性时进行了拦截操作,当该属性存在render函数和 render._withStripped属性时,执行的是getHandler拦截函数;否则就是执行hasHandler拦截函数,那么现在来看看这两个拦截函数都干了什么?

    hasHandler

    // 判断传入的参数是否存在于下面这段字符中
    const allowedGlobals = makeMap(
        'Infinity,undefined,NaN,isFinite,isNaN,' +
        'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
        'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
        'require' // for Webpack/Browserify
      )
    //比如: in运算符的拦截,但对for...in循环不生效
      const hasHandler = {
        //拦截key in target的操作,返回一个布尔值
        has (target, key) {
          const has = key in target //是否存在与目标中
          //判断key名是否存在于allowedGlobals函数中生成的对象中 || (key名是string类型 && 首字母是_)
          const isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_')
          //访问了一个没有定义在实例对象上(或原型链上)的属性 && isAllowed为false提示警告
          if (!has && !isAllowed) {
            warnNonPresent(target, key)
          }
          //返回一个布尔值
          return has || !isAllowed
        }
      }

    该函数的作用就是判断对象是否具有某个属性。可以看到首先用in操作符判断这个属性是否存在于_renderProxy中,当不存在 && (属性名不为字符串 || 属性名首字母为_) && allowedGlobals(key)false时,提示警告信息'属性或方法没有在实例上定义'

    getHandler

    //添加读取属性拦截
      const getHandler = {
        get (target, key) {
          //key名是字符串类型 && key不存在于目标中提示警告
          if (typeof key === 'string' && !(key in target)) {
            warnNonPresent(target, key)
          }
          return target[key]
        }
      }

    这个比较好理解,就是读取_renderProxy中的属性的时候,当属性名为字符串 && 不存在_renderProxy中时提示警告信息'属性或方法没有在实例上定义'。

    一个实例的生成后的一些隐藏所有属性

    vm = {
        _renderProxy: vm,
        _self: vm,
        $options: {
            _parentListeners: {},//所有父组件作用于该组件的监听函数集合
        },//用户可配置的属性和一些不可配置的属性
        $parent,//实例的父组件
        $children: [],//子组件集合
        $root,//根组件一般为App
        $refs:{},//存放该组件中所有存在`ref`属性的节点
        _watcher,//该实例渲染函数的数据的订阅者
        _inactive,//表示该组件是否激活, `false`代表激活  `true`或`null`代表未激活 
        _directInactive,//表示`keep-alive`中组件状态的属性,表示是否要激活 比如父组件未激活 那么其也不会激活
        _isMounted,//用于表示该组件是否已挂载
        _isDestroyed,//表示该组件是否已销毁
        _isBeingDestroyed,//表示该组件是否正在销毁中
        _events,//组件的所有监听函数集合
        _hasHookEvent,//父组件是否有监听子组件的生命周期钩子
    }

    这一章节到这就没了,下一章我们来看下‘初始化数据’做了什么

    详细信息可访问https://github.com/maomao93/vue-2.x/tree/master/personal

  • 相关阅读:
    django大全
    centos 下安装python3.6.2
    爬虫基础知识与简单爬虫实现
    HDU5950 Recursive sequence (矩阵快速幂加速递推) (2016ACM/ICPC亚洲赛区沈阳站 Problem C)
    ZOJ5833 Tournament(递归打表)
    ZOJ4067 Books(贪心)
    ZOJ4062 Plants vs. Zombies(二分+贪心)
    ZOJ4060 Flippy Sequence(思维题)
    洛谷P2568 GCD(线性筛法)
    2018.11.6刷题记录
  • 原文地址:https://www.cnblogs.com/maomao93/p/14166613.html
Copyright © 2011-2022 走看看