[翻译&摘抄]ES6 中的元编程:Reflect

原文地址:Metaprogramming in ES6: Part 2 - Reflect
原文作者:Keith Cirkel
译文出自:掘金翻译计划
转自:https://juejin.im/post/5a0e66386fb9a04523417418
作者:吴晓军
译者:yoyoyohamapi
校对者:IridescentMia ParadeTo

Reflect 是通过自省(introspection)实现反射(Reflection through introspection) ,反射是元编程的一个方面。
—— 通常用来探索非常底层的代码信息。

元编程又是个啥:元编程(笼统地说)是所有关于一门语言的底层机制,而不是数据建模或者业务逻辑那些高级抽象。如果程序可以被描述为 “制作程序”,元编程就能被描述为 “让程序来制作程序”。

Reflect 是一个新的全局对象(类似 JSON 或者 Math),该对象提供了大量有用的内省(introspection)方法(内省是 “看看那个东西” 的一个非常华丽的表述)。内省工具已经存在于 JavaScript 了,例如 Object.keys,Object.getOwnPropertyNames 等等。

“内置方法”

内置方法能够有效地让 JavaScript 引擎在对象上执行一些基础操作。如果你通读了规范,你会发现这些方法散落各处,例如 [[Get]]、[[Set]]、[[HasOwnProperty]] 等等。

其中一些 “内置方法” 对 JavaScript 代码是隐藏的,另一些则应用在了其他方法中,即使这些方法可用,它们仍被隐藏于难于窥见的缝隙之中。例如,Object.prototype.hasOwnProperty 是 [[HasOwnProperty]] 的一个实现。

另一个例子,[[OwnPropertyKeys]] 这一内置方法能获得对象上所有的字符串 key 和 Symbol key,并作为一个数组返回。在不使用 Reflect 的情况下,能一次性获得这些 key 的方式只有连接 Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols 的结果。

var s = Symbol('foo');
var k = 'bar';
var o = { [s]: 1, [k]: 1 };
// 模拟 [[OwnPropertyKeys]]
var keys = Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o));
assert.deepEqual(keys, [k, s]);

所以,为什么我们仍然新建 API ,而不是直接在 Object 上做扩展呢?且看下节。

反射方法

反射是一个非常有用的集合,它囊括了所有 JavaScript 引擎内部专有的 “内部方法”,现在被暴露为了一个单一、方便的对象 —— Reflect。你可能会问:“这听起来不错,但是为什么不直接将内置方法绑定到 Object 上呢?就像 Object.keys、Object.getOwnPropertyNames 这样”。

原因:

1、反射拥有的方法不仅针对于 Object,还可能针对于函数,例如 Reflect.apply,毕竟调用 Object.apply(myFunction) 看起来太怪了。
2、用一个单一对象贮存内置方法能保持 JavaScript 其余部分的纯净性,这要优于将反射方法通过点操作符挂载到构造函数或者原型上,更要优于直接使用全局变量。
3、typeof、instanceof 以及 delete 已经作为反射运算符存在了 —— 为此添加同样功能的新关键字将会加重开发者的负担,同时,对于向后兼容性也是一个梦魇,并且会让 JavaScript 中的保留字数量急速膨胀。

常见的 Reflect 方法

更详细的说明可以参见原文。

Reflect.apply ( target, thisArgument [, argumentList] )

// ---------------------------------------------------------------------------//

Reflect.construct ( target, argumentsList [, constructorToCreateThis] )
// ES5 风格的工厂函数:
function greetingFactory(name) {
    var instance = Object.create(Greeting.prototype);
    Greeting.call(instance, name);
    return instance;
}
// ES6 风格的工厂函数:
function greetingFactory(name) {
    return Reflect.construct(Greeting, [name], Greeting);
}

// ---------------------------------------------------------------------------//

Reflect.defineProperty ( target, propertyKey, attributes )

// ---------------------------------------------------------------------------//

Reflect.getOwnPropertyDescriptor ( target, propertyKey )

// ---------------------------------------------------------------------------//

Reflect.deleteProperty ( target, propertyKey )

var myObj = { foo: 'bar' };
delete myObj.foo;
assert(myObj.hasOwnProperty('foo') === false);

myObj = { foo: 'bar' };
Reflect.deleteProperty(myObj, 'foo');
assert(myObj.hasOwnProperty('foo') === false);

// ---------------------------------------------------------------------------//

Reflect.getPrototypeOf ( target )

// ---------------------------------------------------------------------------//

Reflect.setPrototypeOf ( target, proto )

// ---------------------------------------------------------------------------//

Reflect.isExtensible (target)

// ---------------------------------------------------------------------------//

Reflect.preventExtensions ( target )

// ---------------------------------------------------------------------------//

Reflect.get ( target, propertyKey [ , receiver ])

// ---------------------------------------------------------------------------//

Reflect.set ( target, propertyKey, V [ , receiver ] )

// ---------------------------------------------------------------------------//

Reflect.has ( target, propertyKey )

// 不使用 Reflect.has:
assert(('foo' in myObject) === true);
assert(('bing' in myObject) === false);

// 使用 Reflect.has:
assert(Reflect.has(myObject, 'foo') === true);
assert(Reflect.has(myObject, 'bing') === false);


// ---------------------------------------------------------------------------//

Reflect.ownKeys ( target )

var myObject = {
  foo: 1,
  bar: 2,
  [Symbol.for('baz')]: 3,
  [Symbol.for('bing')]: 4,
};

// 不使用 Reflect.ownKeys:
var keys = Object.getOwnPropertyNames(myObject).concat(Object.getOwnPropertySymbols(myObject));
assert.deepEqual(keys, ['foo', 'bar', Symbol.for('baz'), Symbol.for('bing')]);

// 使用 Reflect.ownKeys:
assert.deepEqual(Reflect.ownKeys(myObject), ['foo', 'bar', Symbol.for('baz'), Symbol.for('bing')]);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值