ES6 中的Proxy 和 Reflect 到底是什么鬼?

一、Proxy
1、概述
Proxy取其英文意思即“代理”
所谓代理,是你要取得某样东西或对其进行某些操作的中间媒介,而不是直接作用在这个对象上。这就类似我们网购东西,需要在网店平台上购买,而不是直接向厂家购买。
Proxy 对象就是这样的媒介,要操作这个对象的话,需要经过这个媒介的同意。
使用方式: let p = new Proxy(target, habdler);
target:用 Proxy 包装的目标对象(可以是数组对象,函数,或者另一个代理);
handler:一个对象,拦截过滤代理操作的函数。

let obj = {
  name: "猿跑跑",
  age:28
}
  
let p = new Proxy(obj, {
  get: function (target, key) {
    if (key in target) {
      return target[key]
    } else {
      console.log("对象没有此属性");
    }
  },
  set: function (target, key, value) {
    if (key == "age" & value < 1) {
      console.log("参数有误");
    } else {
      target[key] = value;
    }
  }
});
p.age = -1;
p.age = 22;
console.log(p.age);
console.log(p.name);
// 参数有误
// 22
// 猿跑跑

2、实例方法
除了上面代码中set 和 get 两个实例方法外,Proxy 对象实例方法如下表显示:

方法 描述
handler.apply() 拦截 Proxy 实例作为函数调用的操作
handler.construct() 拦截 Proxy 实例作为函数调用的操作
handler.defineProperty() 拦截 Object.defineProperty() 的操作
handler.deleteProperty() 拦截 Proxy 实例删除属性操作
handler.get() 拦截 读取属性的操作
handler.set() 拦截 属性赋值的操作
handler.getOwnPropertyDescriptor() 拦截 Object.getOwnPropertyDescriptor() 的操作
handler.getPrototypeOf() 拦截 获取原型对象的操作
handler.has() 拦截 属性检索操作
handler.isExtensible() 拦截 Object.isExtensible()操作
handler.ownKeys() 拦截 Object.getOwnPropertyDescriptor() 的操作
handler.preventExtension() 拦截 Object().preventExtension() 操作
handler.setPrototypeOf() 拦截Object.setPrototypeOf()操作
Proxy.revocable() 创建一个可取消的 Proxy 实例

二、Reflect
1、概述
与Proxy相同,也是ES6新增。
它新增了一些方法,这些方法可以使一些操作更加规范化,更加便利。对象有如下特点:
(1).只要Proxy对象具有的代理方法,Reflect对象全部具有,以静态方法的形式存在。这些方法能够执行默认行为,无论Proxy怎么修改默认行为,总是可以通过Reflect对应的方法获取默认行为。
(2).新增的方法与现有一些方法功能重复,新增的方法会取代现有的方法
,比如Reflect.getPrototypeOf(),Object对象具有同样的方法,功能也相同,但是将getPrototypeOf()方法移植到Reflect更加合理。还有一些新增方法用来取代现有的命令式操作,比如判断属性是否存在的in命令,用Reflect.has()方法替代。
2、实例方法

方法 描述
handler.apply() 通过指定的参数列表发起对目标函数的调用
handler.construct() 此方法行为有点像 new 操作符构造函数,相当于运行 new target(...args)
handler.defineProperty() 方法功能类似于Object.defineProperty()方法
handler.deleteProperty() 功能类似于delete运算符
handler.get() 从对象获取指定属性值
handler.set() 设置指定对象的属性,比如为对象添加新属性或者修改原有属性的值
handler.getOwnPropertyDescriptor() 功能类似于Object.getOwnPropertyDescriptor()
handler.getPrototypeOf() 获取对象的原型对象
handler.has() 获取对象的原型对象
handler.isExtensible() 判断一个对象是否是可扩展的
handler.ownKeys() 返回一个数组,此数组中包含有参数对象自有属性名称
handler.preventExtension() 将对象设置为不可扩展
handler.setPrototypeOf() 设置指定对象的原型对象

三、应用实例
1、操作节点(切换两个不同的元素的属性或类名)

let view = new Proxy({
  selected: null
},
{
  set: function(obj, prop, newval) {
    let oldval = obj[prop];

    if (prop === 'selected') {
      if (oldval) {
        oldval.setAttribute('aria-selected', 'false');
      }
      if (newval) {
        newval.setAttribute('aria-selected', 'true');
      }
    }

    // The default behavior to store the value
    obj[prop] = newval;
  }
});

let i1 = view.selected = document.getElementById('item-1');
console.log(i1.getAttribute('aria-selected')); // 'true'

let i2 = view.selected = document.getElementById('item-2');
console.log(i1.getAttribute('aria-selected')); // 'false'
console.log(i2.getAttribute('aria-selected')); // 'true'

2、对象多重继承

var obj1 = {
    name: "obj-1",
    foo() {
        console.log( "obj1.foo:", this.name );
    }
},
obj2 = {
    name: "obj-2",
    foo() {
        console.log( "obj2.foo:", this.name );
    },
    bar() {
        console.log( "obj2.bar:", this.name );
    }
},
handlers = {
    get(target,key,context) {
        if (Reflect.has( target, key )) {
            return Reflect.get(target, key, context);
        }
        else {
            for (var P of target[Symbol.for( "[[Prototype]]" )]) {
                if (Reflect.has( P, key )) {
                    return Reflect.get(P, key, context);
                }
            }
        }
    }
},
obj3 = new Proxy({
    name: "obj-3",
    baz() {
        this.foo();
        this.bar();
    }
},handlers);

obj3[Symbol.for("[[Prototype]]")] = [obj1, obj2];
obj3.baz();
//obj1.foo:obj-3
//obj2.bar:obj-3

如果我们要实现对象间的单继承,比如obj3继承在obj1,可以使用Object.setPrototypeOf方法,但是没法实现多继承。所以上面的代码中用了一个自定义的属性Symbol.for("[[Prototype]]")来表示要继承的多个父对象。
然后用Proxy来拦截所有obj3中的get请求,先检查obj3中是否有相应的属性或者方法,使用的就是Reflect.has方法,如果有,就直接转发;如果没有,就遍历父对象列表,在父对象中逐个检查是否有相应的属性或者方法,有就调用。如果都没有,那get就相当于返回undefined了。逻辑还是非常好理解的,代码也比较清楚,应该不需要太多的解释。

戳我博客

章节目录

1、ES6中啥是块级作用域?运用在哪些地方?
2、ES6中使用解构赋值能带给我们什么?
3、ES6字符串扩展增加了哪些?
4、ES6对正则做了哪些扩展?
5、ES6数值多了哪些扩展?
6、ES6函数扩展(箭头函数)
7、ES6 数组给我们带来哪些操作便利?
8、ES6 对象扩展
9、Symbol 数据类型在 ES6 中起什么作用?
10、Map 和 Set 两数据结构在ES6的作用
11、ES6 中的Proxy 和 Reflect 到底是什么鬼?
12、从 Promise 开始踏入异步操作之旅
13、ES6 迭代器(Iterator)和 for...of循环使用方法
14、ES6 异步进阶第二步:Generator 函数
15、JavaScript 异步操作进阶第三步:async 函数
16、ES6 构造函数语法糖:class 类

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,934评论 6 13
  • defineProperty() 学习书籍《ECMAScript 6 入门 》 Proxy Proxy 用于修改某...
    Bui_vlee阅读 649评论 0 1
  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 6,543评论 3 22
  • 又是到了晚11点抢时间更文。 昨天首更便是如此。 狼狈不堪。 伏案7个小时不停歇地赶出公众号里一份几千字的超长攻略...
    Miss李ls阅读 170评论 5 2