2015年更新:
正如第7条回答所指出的那样,既然ES6(ECMAScript 2015)已经完成,现在可以找到更多合适的文档:
原始答案(用于(历史性)理解和更多示例):
在Reflection proposal
似乎已经进展到草案的ECMAScript 6规范。本文档当前概述了Reflect
-object的方法,并且仅说明了Reflect
-object本身的以下内容:
Reflect对象是单个普通对象。
Reflect对象的[[Prototype]]内部插槽的值是标准的内置Object原型对象(19.1.3)。
Reflect对象不是函数对象。它没有[[Construct]]内部方法。不能将Reflect对象与new运算符一起用作构造函数。Reflect对象也没有[[Call]]内部方法。不能将Reflect对象作为函数调用。
但是,在ES Harmony中有一个简短的解释:
“ @reflect”模块有多种用途:
- 现在我们有了模块,对于以前在Object上定义的许多反射方法,“ @ reflect”模块更为自然。出于向后兼容的目的,Object上的静态方法不太可能消失。但是,应该将新方法添加到“ @reflect”模块,而不是对象构造函数。
- 代理的天然家园,无需全局代理绑定。
- 此模块中的大多数方法都将一对一映射到代理陷阱。代理处理程序需要这些方法来方便地转发操作,如下所示。
因此,该Reflect
对象提供了许多实用程序功能,其中许多功能似乎与在全局对象上定义的ES5方法重叠。
但是,这并不能真正解释它打算解决哪些现有问题或添加了什么功能。我怀疑这可能是不正确的,并且实际上,上述和谐规范链接到“这些方法的非规范,近似实现”。
检查该代码可以使人们对它的使用有更进一步的了解,但值得庆幸的是,还有一个Wiki概述了Reflect对象有用的许多原因:(
我已经复制(并格式化)了以下文本,以供以后参考资料来源,因为它们是我唯一能找到的例子。除此之外,它们很有意义,已经有了很好的解释,并可以回答问题的apply
例子。)
更有用的返回值
许多操作在Reflect
类似于定义ES5操作Object
,比如Reflect.getOwnPropertyDescriptor
和Reflect.defineProperty
。但是,虽然Object.defineProperty(obj, name, desc)
将obj
在成功定义属性时返回,否则将抛出TypeError
否则,但Reflect.defineProperty(obj, name, desc)
仅返回一个布尔值即可,该布尔值指示属性是否已成功定义。这使您可以重构以下代码:
try {
Object.defineProperty(obj, name, desc);
} catch (e) {
}
对此:
if (Reflect.defineProperty(obj, name, desc)) {
} else {
}
返回此类布尔成功状态的其他方法是Reflect.set
(更新属性),Reflect.deleteProperty
(删除属性),Reflect.preventExtensions
(使对象不可扩展)和Reflect.setPrototypeOf
(更新对象的原型链接)。
一流的运营
在ES5中,检测对象是否obj
定义或继承某个属性名称的方法是write (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);
}
});
在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
陷阱。
控制访问者的此绑定
在ES5中,进行常规属性访问或属性更新相当容易。例如:
var name = ...
obj[name]
obj[name] = value
该Reflect.get
和Reflect.set
方法允许你做同样的事情,而且还接受作为最后的可选参数一个receiver
参数,使您可以明确设置this
属性时,你得到结合位/集是访问:
var name = ...
Reflect.get(obj, name, 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
也存在Object
(如Knu的注释正确指出的)!
编辑:
旁注(解决对Q的评论):关于“ Q:ES6模块与HTML导入”的解释Realms
和Loader
对象有一个简短的答案。
该链接提供了另一种解释:
领域对象通过其自己的全局对象,标准库的副本和“ intrinsics”(未绑定至全局变量的标准对象,如Object.prototype的初始值)抽象出独特的全局环境的概念。
可扩展的网络:这是<iframe>
没有DOM的动态同源
。
值得一提的是:这一切仍在草案中,这不是刻板的规范!它是ES6,因此请牢记浏览器的兼容性!
希望这可以帮助!
Reflect
它只是Realm
和Loader
对象的容器,但我也不知道后者做什么。