2015 年更新:
正如7th's answer 所指出的,现在 ES6 (ECMAScript 2015) 已经完成,现在可以获得更合适的文档:
原始答案(用于(历史)理解和额外示例):
Reflection proposal 似乎已经升级为Draft ECMAScript 6 Specification。本文档目前概述了Reflect-object 的方法,仅说明了Reflect-object 本身的以下内容:
Reflect 对象是一个普通的对象。
Reflect对象的[[Prototype]]内部槽的值是标准的内置Object原型对象(19.1.3)。
Reflect 对象不是函数对象。它没有 [[Construct]] 内部方法;不能将 Reflect 对象用作带有 new 运算符的构造函数。 Reflect 对象也没有 [[Call]] 内部方法;不能将 Reflect 对象作为函数调用。
不过,在ES Harmony 中有一个关于其用途的简短说明:
“@reflect”模块有多种用途:
- 现在我们有了模块,“@reflect”模块对于之前定义在 Object 上的许多反射方法来说是一个更自然的地方。
出于向后兼容的目的,Object 上的静态方法不太可能消失。但是,应该将新方法添加到“@reflect”模块而不是 Object 构造函数中。
- 代理的自然归宿,无需全局代理绑定。
- 此模块中的大多数方法都将一对一映射到代理陷阱。代理处理程序需要这些方法来方便地转发操作,如下所示。
因此,Reflect 对象提供了许多实用功能,其中许多似乎与全局对象上定义的 ES5 方法重叠。
但是,这并不能真正解释它打算解决哪些现有问题或添加了哪些功能。我怀疑这可能会被填充,实际上,上面的和谐规范链接到'non-normative, approximate implementation of these methods'。
检查该代码可以(进一步)了解它的用途,但幸运的是还有一个 wiki 概述了 a number of reasons why the Reflect object is useful:
(我已经复制(并格式化( /sub>
更多有用的返回值
Reflect 中的许多操作类似于 Object 上定义的 ES5 操作,例如 Reflect.getOwnPropertyDescriptor 和 Reflect.defineProperty。然而,Object.defineProperty(obj, name, desc) 将在成功定义属性时返回obj,否则抛出TypeError,而Reflect.defineProperty(obj, name, desc) 指定简单地返回一个指示属性是否成功定义的布尔值。这允许您重构此代码:
try {
Object.defineProperty(obj, name, desc);
// property defined successfully
} catch (e) {
// possible failure (and might accidentally catch the wrong exception)
}
到这里:
if (Reflect.defineProperty(obj, name, desc)) {
// success
} else {
// failure
}
返回这种布尔成功状态的其他方法有Reflect.set(更新属性)、Reflect.deleteProperty(删除属性)、Reflect.preventExtensions(使对象不可扩展)和Reflect.setPrototypeOf(更新对象的原型链接)。
一流的运营
在ES5中,检测对象obj是否定义或继承了某个属性名的方法是写(name in obj)。同样,要删除一个属性,可以使用delete obj[name]。虽然专用语法既好又短,但这也意味着当您想要将操作作为一等值传递时,您必须将这些操作显式包装在函数中。
使用Reflect,这些操作很容易定义为一等函数:
Reflect.has(obj, name) 是(name in obj) 的功能等价物,Reflect.deleteProperty(obj, name) 是与delete obj[name]. 执行相同功能的函数
更可靠的功能应用
在 ES5 中,当想要调用函数 f 并将可变数量的参数打包为数组 args 并将 this 值绑定到 obj 时,可以这样写:
f.apply(obj, args)
但是,f 可能是有意或无意定义其自己的 apply 方法的对象。当你真的想确保调用了内置的apply 函数时,通常会这样写:
Function.prototype.apply.call(f, obj, args)
这不仅冗长,而且很快变得难以理解。使用Reflect,您现在可以以更短且更易于理解的方式进行可靠的函数调用:
Reflect.apply(f, obj, args)
变量参数构造函数
假设你想调用一个带有可变数量参数的构造函数。在 ES6 中,由于新的扩展语法,可以编写如下代码:
var obj = new F(...args)
在 ES5 中,这更难写,因为只能使用 F.apply 或 F.call 调用具有可变数量参数的函数,但没有 F.construct 函数到 new 函数可变数量的参数。有了Reflect,现在可以在 ES5 中编写代码了:
var obj = Reflect.construct(F, args)
代理陷阱的默认转发行为
当使用Proxy对象包装现有对象时,很常见的是拦截一个操作,做一些事情,然后“做默认的事情”,这通常是将拦截的操作应用到被包装的对象上。例如,假设我想简单地记录对对象 obj 的所有属性访问:
var loggedObj = new Proxy(obj, {
get: function(target, name) {
console.log("get", target, name);
// now do the default thing
}
});
Reflect 和Proxy API 是串联设计的,因此对于每个Proxy 陷阱,在Reflect 上存在一个“执行默认操作”的相应方法。因此,每当您发现自己想要在 Proxy 处理程序中“执行默认”操作时,正确的做法是始终调用 Reflect 对象中的相应方法:
var loggedObj = new Proxy(obj, {
get: function(target, name) {
console.log("get", target, name);
return Reflect.get(target, name);
}
});
Reflect 方法的返回类型保证与Proxy 陷阱的返回类型兼容。
控制访问器的 this 绑定
在 ES5 中,进行通用属性访问或属性更新相当容易。例如:
var name = ... // get property name as a string
obj[name] // generic property lookup
obj[name] = value // generic property update
Reflect.get 和 Reflect.set 方法允许您做同样的事情,但另外接受一个 receiver 参数作为最后一个可选参数,该参数允许您在属性时显式设置 this-binding get/set 是一个访问器:
var name = ... // get property name as a string
Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper`
Reflect.set(obj, name, value, wrapper)
当您包装 obj 并且您希望访问器中的任何自发送被重新路由到您的包装器时,这有时很有用,例如如果obj 定义为:
var obj = {
get foo() { return this.bar(); },
bar: function() { ... }
}
调用Reflect.get(obj, "foo", wrapper) 将导致this.bar() 调用重新路由到wrapper。
避免遗留__proto__
在某些浏览器上,__proto__ 被定义为一个特殊属性,可以访问对象的原型。 ES5 标准化了一种新方法Object.getPrototypeOf(obj) 来查询原型。 Reflect.getPrototypeOf(obj) 的作用完全一样,只是Reflect 还定义了一个对应的Reflect.setPrototypeOf(obj, newProto) 来设置对象的原型。这是更新对象原型的符合 ES6 的新方法。
请注意:setPrototypeOf also exists on Object(正如Knu 的comment 正确指出的那样)!
编辑:
旁注(将 cmets 指向 Q):有一个简短的 answer on 'Q: ES6 Modules vs. HTML Imports' 解释了 Realms 和 Loader 对象。
this link提供了另一种解释:
领域对象抽象了一个独特的全局环境的概念,
拥有自己的全局对象、标准库的副本,以及
“内在”(未绑定到全局变量的标准对象,
像 Object.prototype 的初始值)。
可扩展网络:这是同源的动态等价物
<iframe> 没有 DOM。
值得一提的是:这一切都还在草稿中,这不是一成不变的规范! 它是 ES6,所以请牢记浏览器兼容性!
希望这会有所帮助!