理解元编程
Symbol、Reflect 和 Proxy 是属于 ES6 元编程范畴的,能“介入”的对象底层操作进行的过程中,并加以影响。元编程中的 元 的概念可以理解为 程序 本身。
“元编程就是改变程序原本的运行方式”
Javascript 中,eval、new Function()便是两个可以用来进行元编程的特性。
ES6 下的元编程:Symbol
Symbols 是 ES6 一个全新的 API,它是实现了的反射(Reflection within implementation)—— 你将 Symbols 应用到你已有的类和对象上去改变它们的行为。
Symbols 是新的原始类型(primitive)。就像是 Number、String、和 Boolean 一样。Symbols 具有一个 Symbol 函数用于创建 Symbol。与别的原始类型不同,Symbols 没有字面量语法(例如,String 有 ”)—— 创建 Symbol 的唯一方式是使用类似构造函数而又非构造函数的 Symbol 函数:
1 | Symbol(); // symbol |
Symbols 能被用作对象的 key
Symbols 能用作对象的 key (类似字符串 key),这意味着你可以分配无限多的具有唯一性的 Symbols 到一个对象上,这些 key 保证不会和现有的字符串 key 冲突,或者和其他 Symbol key 冲突。
并且,继续划重点,Symbols key 无法通过 for in、for of 或者 Object.getOwnPropertyNames 获得 —— 获得它们的唯一方式是 Object.getOwnPropertySymbols。
这意味着 Symbols 能够给对象提供一个隐藏层,帮助对象实现了一种全新的目的 —— 属性不可迭代,也不能够通过现有的反射工具获得,并且能被保证不会和对象任何已有属性冲突。
但是,这里也有个例外:Symbol.for()
JavaScript 也有另一个创建 Symbol 的方式来轻易地实现 Symbol 的获得和重用:Symbol.for()。该方法在 “全局 Symbol 注册中心” 创建了一个 Symbol。额外注意的一点:这个注册中心也是跨域的,意味着 iframe 或者 service worker 中的 Symbol 会与当前 frame Symbol 相等
- Symbols 无法通过现有的反射工具读取。
你需要一个新的方法 Object.getOwnPropertySymbols() 来访问对象上的 Symbols,这让 Symbol 适合存储那些你不想让别人直接获得的信息。
- Symbols 不是私有的。
作为双刃剑的另一面 —— 对象上所有的 Symbols 都可以直接通过 Object.getOwnPropertySymbols() 获得 —— 这不利于我们使用 Symbol 存储一些真正需要私有化的值。
- Symbols 不总是唯一的。
Symbol.for() 将为你返回一个不唯一的 Symbol。不要总认为 Symbol 具有唯一性,除非你自己能够保证它的唯一性。
Symbol的作用
作为一个可替换字符串或者整型使用的唯一值
作为一个对象中放置元信息(metadata)的场所(记住,Symbols 不是私有的)
给予开发者在 API 中为对象添加钩子(hook)的能力
1 | // 从 API 的 Symbols 常量中获得这个充满魔力的 Inspect Symbol |
钩子实现大致如下:
1 | console.log = function (…items) { |
- PS:钩子是什么?
提供一个可以影响默认的(或原有的)流程(机制)的时机
通常就是:一个库、一个框架、一个系统或一种语言,提供一个对外公开的接口,通过这个接口,用户能够影响库、框架、系统或程序的行为。
1 | const arr = [4, 5, 6, 7, 8, 9]; |
Proxy
Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。
1 | let person = { |
Reflect
为操作对象而提供的新API
将Object对象的属于语言内部的方法放到Reflect对象上,即从Reflect对象上拿Object对象内部方法。
将用 老Object方法 报错的情况,改为返回false
1 | function Tree() { |


