Jim*_*nes 77 javascript ecmascript-6
我刚才在MDN上看到了一个空白的存根,用于Reflectjavascript中的对象,但是我无法在Google的生活中找到任何东西.今天我发现了这个http://people.mozilla.org/~jorendorff/es6-draft.html#sec-reflect-object,除了领域和加载器功能外,它听起来与Proxy对象类似.
基本上,我不知道我找到的这个页面是否只解释了如何实现Reflect,或者我是否只是无法理解其措辞.有人可以请大家向我解释一下Reflect做什么方法?
例如,在我发现的页面上,调用Reflect.apply ( target, thisArgument, argumentsList )
将"返回使用参数thisArgument和args调用目标的[[Call]]内部方法的结果." 但是这与调用target.apply(thisArgument, argumentsList)有何不同?
更新:
感谢@Blue,我在维基上找到了这个页面
http://wiki.ecmascript.org/doku.php?id=harmony:reflect_api&s=reflect据
我所知,反射对象提供了所有的方法版本代理可以捕获的操作使转发更容易.但这对我来说似乎有点奇怪,因为我看不出它是如何完全必要的.但它似乎做了一点点,特别是那个标准double-lifting但但是指向旧的代理规范/
Git*_*LAB 111
更新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"模块有多种用途:
- 现在我们有了模块,"@ reflect"模块对于之前在Object上定义的许多反射方法来说是一个更自然的地方.出于向后兼容的目的,Object上的静态方法不太可能消失.但是,新方法可能会添加到"@reflect"模块而不是Object构造函数中.
- 代理的自然之家,无需全局代理绑定.
- 此模块中的大多数方法都是一对一地映射到代理陷阱.代理处理程序需要这些方法来方便地转发操作,如下所示.
因此,该Reflect对象提供了许多实用程序函数,其中许多函数似乎与全局Object上定义的ES5方法重叠.
但是,这并没有真正解释这个打算解决的现有问题或者添加了哪些功能.我怀疑这可能会变得松软,事实上,上面的和谐规范与"这些方法的非规范,近似实施"有关.
检查代码可以给出(进一步)关于它的使用的想法,但幸运的是还有一个维基,它概述了为什么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);
// property defined successfully
} catch (e) {
// possible failure (and might accidentally catch the wrong exception)
}
Run Code Online (Sandbox Code Playgroud)
对此:
if (Reflect.defineProperty(obj, name, desc)) {
// success
} else {
// failure
}
Run Code Online (Sandbox Code Playgroud)
返回这种布尔成功状态的其他方法是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)
Run Code Online (Sandbox Code Playgroud)
但是,f可能是有意或无意定义其自身apply方法的对象.当你真的想确保apply调用内置函数时,通常会写:
Function.prototype.apply.call(f, obj, args)
Run Code Online (Sandbox Code Playgroud)
这不仅很冗长,而且很快变得难以理解.有了Reflect,您现在可以用更简单,更容易理解的方式进行可靠的函数调用:
Reflect.apply(f, obj, args)
Run Code Online (Sandbox Code Playgroud)
变量参数构造函数
想象一下,您想要使用可变数量的参数调用构造函数.在ES6中,由于新的扩展语法,可以编写如下代码:
var obj = new F(...args)
Run Code Online (Sandbox Code Playgroud)
在ES5中,这更难编写,因为只能使用F.apply或F.call调用具有可变数量参数的函数,但是F.construct函数没有new函数且具有可变数量的参数.有了Reflect,现在可以在ES5中编写:
var obj = Reflect.construct(F, args)
Run Code Online (Sandbox Code Playgroud)
代理陷阱的默认转发行为
当使用Proxy对象来包装现有对象时,通常拦截操作,执行某些操作,然后"执行默认操作",这通常是将截取的操作应用于包装对象.例如,假设我想简单地记录对象的所有属性访问obj:
var loggedObj = new Proxy(obj, {
get: function(target, name) {
console.log("get", target, name);
// now do the default thing
}
});
Run Code Online (Sandbox Code Playgroud)
在Reflect和ProxyAPI的设计串联,使得对于每个Proxy陷阱,存在相应的方法上Reflect说,"确实默认的事情".因此,每当您发现自己想要在Proxy处理程序中"执行默认"操作时,正确的做法是始终在Reflect对象中调用相应的方法:
var loggedObj = new Proxy(obj, {
get: function(target, name) {
console.log("get", target, name);
return Reflect.get(target, name);
}
});
Run Code Online (Sandbox Code Playgroud)
的返回类型Reflect的方法是保证用的返回类型兼容的Proxy陷阱.
控制访问者的这种绑定
在ES5中,进行通用属性访问或属性更新相当容易.例如:
var name = ... // get property name as a string
obj[name] // generic property lookup
obj[name] = value // generic property update
Run Code Online (Sandbox Code Playgroud)
该Reflect.get和Reflect.set方法允许你做同样的事情,而且还接受作为最后的可选参数一个receiver参数,使您可以明确设置this-结合时,你的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)
Run Code Online (Sandbox Code Playgroud)
这在包装时偶尔会有用,obj并且您希望访问器中的任何自发送重新路由到您的包装器,例如,如果obj定义为:
var obj = {
get foo() { return this.bar(); },
bar: function() { ... }
}
Run Code Online (Sandbox Code Playgroud)
呼叫Reflect.get(obj, "foo", wrapper)将导致this.bar()呼叫被重新路由到wrapper.
避免传统 __proto__
在某些浏览器中,__proto__被定义为一个特殊属性,可以访问对象的原型.ES5标准化了一种Object.getPrototypeOf(obj)查询原型的新方法.Reflect.getPrototypeOf(obj)完全相同,除了Reflect还定义了对应Reflect.setPrototypeOf(obj, newProto)的set对象的原型.这是更新对象原型的符合ES6标准的新方法.
请注意:setPrototypeOf 也存在Object(正如Knu的评论正确指出的那样)!
编辑:
侧面注释(对Q的评论):对Q:ES6模块与HTML Imports的解释Realms和Loader对象有一个简短而简单的答案.
此链接提供了另一种解释:
领域对象使用自己的全局对象,标准库的副本和"内在函数"(未绑定到全局变量的标准对象,如Object.prototype的初始值)抽象出不同全局环境的概念.
可扩展的Web:这是
<iframe>没有DOM 的同源的动态等价物 .
值得一提的是:所有这些仍然在草案中,这不是刻在石头上的规格!它是ES6,因此请记住浏览器兼容性!
希望这可以帮助!
按照维基上的草案文件,
http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts
我们在草案中阐明了"单一普通对象"的界限.它还具有功能定义.
维基应该是可靠的,因为你可以从emcascript网站找到它的链接
http://www.ecmascript.org/dev.php
我发现谷歌的第一个链接,并没有任何运气通过直接搜索维基找到它.