资讯专栏INFORMATION COLUMN

从vue源码来看Proxy的用途

刘永祥 / 1252人阅读

摘要:从源码来看的用途表述该对象构造器是用于对某对象定义用户自定义行为的。那么,这到底是什么意思呢我们下面直接来分析一下源码中应用到对象的地方,来理解该对象构造器的作用。源码讲解该处定义了所允许的全局对象类型。

从vue源码来看Proxy的用途

The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).MDN Proxy

MDN表述该对象构造器是用于对某对象定义用户自定义行为的。那么,这到底是什么意思呢?我们下面直接来分析一下Vue源码中应用到Proxy对象的地方,来理解该对象构造器的作用。

Proxy在Vue中的应用

首先我们来看一看Vue源码的 1430行

/* not type checking this file because flow doesn"t play well with Proxy */

  var initProxy;

  {
    var 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
    );

    var warnNonPresent = function(target, key) {
      warn(
        "Property or method "" + key + "" is not defined on the instance but " +
        "referenced during render. Make sure to declare reactive data " +
        "properties in the data option.",
        target
      );
    };

    var hasProxy = typeof Proxy !== "undefined" &&
    Proxy.toString().match(/native code/);

    if (hasProxy) {
      var isBuiltInModifier = makeMap("stop,prevent,self,ctrl,shift,alt,meta");
      config.keyCodes = new Proxy(config.keyCodes, {
        set: function set(target, key, value) {
          if (isBuiltInModifier(key)) {
            warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key));
            return false
          } else {
            target[key] = value;
            return true
          }
        }
      });
    }

    var hasHandler = {
      has: function has(target, key) {
        var has = key in target;
        var isAllowed = allowedGlobals(key) || key.charAt(0) === "_";
        if (!has && !isAllowed) {
          warnNonPresent(target, key);
        }
        return has || !isAllowed
      }
    };

    var getHandler = {
      get: function get(target, key) {
        if (typeof key === "string" && !(key in target)) {
          warnNonPresent(target, key);
        }
        return target[key]
      }
    };

    initProxy = function initProxy(vm) {
      if (hasProxy) {
        // determine which proxy handler to use
        var options = vm.$options;
        var handlers = options.render && options.render._withStripped
          ? getHandler
          : hasHandler;
        vm._renderProxy = new Proxy(vm, handlers);
      } else {
        vm._renderProxy = vm;
      }
    };
  }

首先,我们要明白一件事情,vue放弃了对ie9以下的支持。即使这样,由于Proxy作为一个es6的新特性,支持度依然不高,作者也只是尝试着使用了一下。下面我们来一步一步讲解。

源码讲解
 var 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
    );

该处定义了所允许的全局对象类型。

var warnNonPresent = function(target, key) {
      warn(
        "Property or method "" + key + "" is not defined on the instance but " +
        "referenced during render. Make sure to declare reactive data " +
        "properties in the data option.",
        target
      );
 };

该处定义了一个报警方法,传入键名或方法名,log显示一条警告

 var hasProxy = typeof Proxy !== "undefined" &&
    Proxy.toString().match(/native code/);

该处是对es6特性Proxy的检测, 其检测手段是确认Proxy是原生实现并未被用户代码所覆盖。

    var isBuiltInModifier = makeMap("stop,prevent,self,ctrl,shift,alt,meta");
    config.keyCodes = new Proxy(config.keyCodes, {
        set: function set(target, key, value) {
          if (isBuiltInModifier(key)) {
            warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key));
            return false
          } else {
            target[key] = value;
            return true
          }
        }
      });

该段代码对config.keyCodes对象进行了代理,其意义在于禁止用户修改Vue内建的一些按键值,这些按键值和按键名是对应的。如果用过Vue的用户应该知道,Vue在事件对象上对一些常用按键和常用操作进行了内建(这个内建过程被用eval函数压缩了,由一堆代码段构成的,没什么看头),作者肯定不希望也不允许用户修改配置的时候覆盖了内建内容。于是,当我们做config.keyCodes["stop"] = xxx这样的操作的时候,Vue就会告诉你说“你这个人,不老实,为什么想着改我东西”,直接打出禁止改写内建配置的警告。如果非内建内容,那么可以直接设置上。

    initProxy = function initProxy(vm) {
      if (hasProxy) {
        // determine which proxy handler to use
        var options = vm.$options;
        var handlers = options.render && options.render._withStripped
          ? getHandler
          : hasHandler;
        vm._renderProxy = new Proxy(vm, handlers);
      } else {
        vm._renderProxy = vm;
      }
    };

这句话就不再解释了,类似上面。不过读者可能会问has是什么? 那么下面我们来讲解一下Proxy的各个参数

Proxy所需参数

两个, var b = new Proxy(a, { has: fn xxx, get: fn xxx, set: fn xxx .... })

target 被代理的对象

handler 处理器对象

用来定义我们对该对象的各种操作

完整的handler处理器对象内容:

{
    get: "咋获取",
    set: "咋设置",
    deleteProperty: "咋删除",
    enumerate: "咋枚举",
    ownKeys: "咋获取所有该对象的属性键 ",
    has: "问你有没有, 比如 "xxx" in target",
    defineProperty: "如何defineProperty, 这个我们也是可以代理的",
    getOwnPropertyDescriptor: "获取属性描述的代理",
    getPrototypeOf: "找原型时候的代理",
    setPrototypeOf: "设置对象原型的时候的代理",
    isExtensible: "判断对象是否可扩展的时候的代理",
    preventExtensions: "设置阻止对象扩展的时候的代理",
    apply: "执行调用操作的时候的代理",
    construct: "执行实例化的时候的代理"
}

以上皆是函数~~

所以Proxy的作用是?

拦截,预警,上报,扩展功能,统计,强化对象...能想得到的都能沾到点边,这里Vue的代码主要将代理运用于拦截。并且由于规范依然在发展,所以大家慎用。。。

资料

MDN js Proxy Object

MDN Proxy Handler

sec-proxy-object-internal-methods-and-internal-slots

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81452.html

相关文章

  • 人人都能懂Vue源码系列—07—initProxy

    摘要:不同的代码运行环境赋值的结果不同。当访问的属性不是类型或者属性值在被代理的对象上不存在,则抛出错误提示,否则就返回该属性值。该方法可以在开发者错误的调用属性时,提供提示作用。只不过目前规范还没有很完善,使用的时候要稍加注意。 前几篇文章中,我们主要讲了merge options的一些操作。今天我们回到init方法往下讲。 if (process.env.NODE_ENV !== pro...

    vspiders 评论0 收藏0
  • 10分钟看懂动态代理设计模式

    摘要:动态代理是语言中非常经典的一种设计模式,也是所有设计模式中最难理解的一种。本文将通过一个简单的例子模拟动态代理实现,让你彻底明白动态代理设计模式的本质,文章中可能会涉及到一些你没有学习过的知识点或概念。 动态代理是Java语言中非常经典的一种设计模式,也是所有设计模式中最难理解的一种。本文将通过一个简单的例子模拟JDK动态代理实现,让你彻底明白动态代理设计模式的本质,文章中可能会涉及到...

    atinosun 评论0 收藏0
  • vue-cli3.0源码分析@vue/cli-----create

    摘要:本文主要学习的源码的记录。这里有一个的示例的数据会被插件生成器用来生成相应的项目文件。另一个远程版本另外而是通过包获取的版本。 本文主要学习vue-cli3.0的源码的记录。源码地址: https://github.com/vuejs/vue-cli 主要对packages里面的@vue进行学习。如下图 showImg(https://segmentfault.com/img/...

    JasonZhang 评论0 收藏0
  • proxy实现一个更优雅vue

    摘要:以上引用内容来自阮一峰的教程的章节原文地址请戳这里。最后本文最终实现代码已经放在上,想要直接看效果的同学,可以上去直接,运行。 前言 如果你有读过Vue的源码,或者有了解过Vue的响应原理,那么你一定知道Object.defineProperty(),那么你也应该知道,Vue 2.x里,是通过 递归 + 遍历 data对象来实现对数据的监控的,你可能还会知道,我们使用的时候,直接通过数...

    objc94 评论0 收藏0
  • Vue.js源码角度再看数据绑定

    摘要:在学习过程中,为加上了中文的注释,希望可以对其他想学习源码的小伙伴有所帮助。数据绑定原理前面已经讲过数据绑定的原理了,现在从源码来看一下数据绑定在中是如何实现的。 写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出。文章的原地址:https://github.com/answershuto/le...

    elina 评论0 收藏0

发表评论

0条评论

刘永祥

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<