1.概述

Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。Reflect对象的设计目的有这样几个。

(1) 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在ObjectReflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。

(2) 修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false

// 老写法
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
} // 新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}

(3) 让Object操作都变成函数行为。某些Object操作是命令式,比如name in objdelete obj[name],而Reflect.has(obj, name)Reflect.deleteProperty(obj, name)让它们变成了函数行为。

// 老写法
'assign' in Object // true // 新写法
Reflect.has(Object, 'assign') // true

(4)Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。

Proxy(target, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target,name, value, receiver);
if (success) {
log('property ' + name + ' on ' + target + ' set to ' + value);
}
return success;
}
});

上面代码中,Proxy方法拦截target对象的属性赋值行为。它采用Reflect.set方法将值赋值给对象的属性,确保完成原有的行为,然后再部署额外的功能。

2.静态方法

Reflect对象一共有13个静态方法。

  • Reflect.apply(target,thisArg,args)
  • Reflect.construct(target,args)
  • Reflect.get(target,name,receiver)
  • Reflect.set(target,name,value,receiver)
  • Reflect.defineProperty(target,name,desc)
  • Reflect.deleteProperty(target,name)
  • Reflect.has(target,name)
  • Reflect.ownKeys(target)
  • Reflect.isExtensible(target)
  • Reflect.preventExtensions(target)
  • Reflect.getOwnPropertyDescriptor(target, name)
  • Reflect.getPrototypeOf(target)
  • Reflect.setPrototypeOf(target, prototype)

上面这些方法的作用,大部分与Object对象的同名方法的作用都是相同的,而且它与Proxy对象的方法是一一对应的。

3.实例:使用Proxy实现观察者模式

观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行

const person = observable({
name: '张三',
age: 20
}); function print() {
console.log(`${person.name}, ${person.age}`)
} observe(print);
person.name = '李四';
// 输出
// 李四, 20

上面代码中,数据对象person是观察目标,函数print是观察者。一旦数据对象发生变化,print就会自动执行。

下面,使用 Proxy 写一个观察者模式的最简单实现,即实现observableobserve这两个函数。思路是observable函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数。

const queuedObservers = new Set();

const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set}); function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}

上面代码中,先定义了一个Set集合,所有观察者函数都放进这个集合。然后,observable函数返回原始对象的代理,拦截赋值操作。拦截函数set之中,会自动执行所有观察者。

13.Reflect的更多相关文章

  1. ES6 之 Reflect 的方法总结

    1. 概述 将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty ),放到 Reflect 对象上. 修改某些 Object 方法的返回结果,让其变得更 ...

  2. [转载]ECMA-262 6th Edition / Draft August 24, 2014 Draft ECMAScript Language Specification

    http://people.mozilla.org/~jorendorff/es6-draft.html#sec-23.4 Draft Report Errors and Issues at: htt ...

  3. ES6读书笔记(二)

    前言 前段时间整理了ES6的读书笔记:<ES6读书笔记(一)>,现在为第二篇,本篇内容包括: 一.数组扩展 二.对象扩展 三.函数扩展 四.Set和Map数据结构 五.Reflect 本文 ...

  4. Golang字符串处理以及文件操作

    一.整数 1.int与uint的初值比较以及其大小. 1 /* 2 #!/usr/bin/env gorun 3 @author :xxxx 4 Blog:http://www.cnblogs.com ...

  5. 16.go语言基础学习(上)——2019年12月16日

    2019年12月13日10:35:20 1.介绍 2019年10月31日15:09:03 2.基本语法 2.1 定义变量 2019年10月31日16:12:34 1.函数外必须使用var定义变量 va ...

  6. ES6深入浅出-13 Proxy 与 Reflect-1.Reflect 反射

    阮一峰  http://es6.ruanyifeng.com/#docs/reflect MDN有一些简陋的介绍 https://developer.mozilla.org/zh-CN/docs/We ...

  7. 12,13 Proxy和Reflect

    Proxy和Reflect Proxy(代理) Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种"元编程"(meta programming),即对编程 ...

  8. 背水一战 Windows 10 (13) - 绘图: Stroke, Brush

    [源码下载] 背水一战 Windows 10 (13) - 绘图: Stroke, Brush 作者:webabcd 介绍背水一战 Windows 10 之 绘图 Stroke - 笔划 Brush ...

  9. android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error(Sqlite code 14): Could not open database,(OS error - 13:Permission denied)

    07-24 15:03:14.490 6291-6291/com.tongyan.nanjing.subway E/SQLiteDatabase: Failed to open database '/ ...

随机推荐

  1. shell 脚本 实现随机数

    现在我想要1~39之间的随机数该怎么做呢? date +%N   显示当前时间的纳秒   可以把这个数用来做随机数 但我只想要1~39的随机数,该怎么办呢 #! /bin/bash # echo $( ...

  2. 6.nuget安装C#Driver驱动ZooKeeperNet

    一: C# 的Drivers   1. nuget上下载 zookeeper.Net   IWatcher是什么?: client 连接到 server 后,会在server上面注册一个watcher ...

  3. python 中为什么不需要重载

    函数重载主要是为了解决两个问题. (1)可变参数类型. (2) 可变参数个数. 另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两 ...

  4. 用VC实现特定编辑框上对回车键响应

    一.引言 在通常的以CEditView为基类的单文档/多文档视图程序中,可以很好的响应键盘输入的回车键,只需比较最近两次的输入的字符,看看最新输入的字符是否内码是13(0x0d,回车键的内码)即可识别 ...

  5. centos 安装vmware 9.02 报 Failed to load module "pk-gtk-module" "canberra-gtk-module"

    http://www.linuxidc.com/Linux/2012-01/50944.htm 系统平台:RHEL6.1 X86 32bit 软件版本:VMware-Workstation-Full- ...

  6. C# 中 String 类型的详细讲解

    C# 字符串(String) 在 C# 中,您可以使用字符数组来表示字符串,但更常见的做法是使用 string 关键字来声明一个字符串变量.string 关键字是 System.String 类的别名 ...

  7. WPF 按名称查找控件

    1FrameworkElement类FindName方法 使用过程 1.容器控件.RegisterName("Name",要注册的控件)   //注册控件 2.容器控件.FindN ...

  8. 云捕Redis实战

    本文由作者余宝虹授权网易云社区发布. Redis是一个支持丰富数据结构的分布式key-value系统,Redis在云捕系统的地位相当重要,碰到的问题也比较多,最近才解决了一个遗留的老大难问题.由于15 ...

  9. Java50道经典习题-程序11 求不重复数字

    题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. public cla ...

  10. 微信小程序—相对路径和绝对路径

    一.绝对路径: 以“/”开头代表根目录, /ada/like/index 二.相对路径 ../../ada/like/index 或者: ada/like/index