Ответ 1
ОБНОВЛЕНИЕ 2015: Как отметил 7th ответ, теперь, когда ES6 (ECMAScript 2015) завершена, более уместно теперь доступна документация:
Оригинальный ответ (для (исторического) понимания и дополнительных примеров):
Кажется, что Reflection proposal
перешел к проекту спецификации ECMAScript 6. В этом документе в настоящее время описываются методы Reflect
-объектов и только указано следующее о Reflect
-объекте:
Объект Reflect является единственным обычным объектом.
Значение внутреннего слота [[Prototype]] объекта Reflect является стандартным встроенным объектом прототипа объекта (19.1.3).
Объект Reflect не является объектом функции. У него нет внутреннего метода [[Construct]]; невозможно использовать объект Reflect в качестве конструктора с оператором new. Объект Reflect также не имеет внутреннего метода [[Call]]; невозможно вызвать объект Reflect как функцию.
Однако есть короткое объяснение этой цели в ES Harmony:
Модуль "@reflect" выполняет множество задач:
- Теперь, когда у нас есть модули, модуль "@reflect" является более естественным местом для многих методов отражения, ранее определенных для Object. Для целей обратной совместимости маловероятно, что статические методы на объекте исчезнут. Однако новые методы, вероятно, должны быть добавлены к модулю "@reflect" , а не к конструктору Object.
- Естественный дом для прокси, избегая необходимости глобального связывания прокси.
- Большинство методов в этом модуле сопоставляются взаимно однозначно с прокси-ловушками. Прокси-обработчики нуждаются в этих методах для удобной пересылки операций, как показано ниже.
Таким образом, объект Reflect
предоставляет ряд функций утилиты, многие из которых, похоже, перекрываются с методами 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)
}
Для этого:
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
}
});
API-интерфейсы Reflect
и Proxy
были созданы в тандеме, так что для каждой ловушки 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 = ... // get property name as a string
obj[name] // generic property lookup
obj[name] = value // generic property update
Методы Reflect.get
и Reflect.set
позволяют вам делать то же самое, но дополнительно принимают в качестве последнего необязательного аргумента параметр receiver
, который позволяет явно установить привязку this
, когда свойство, которое вы get/set - это accessor:
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
также существует на Object
(как правильно указано Knu comment)!
EDIT:
Боковая заметка (адресация комментариев к Q): есть короткий и простой ответ на тему "Q: ES6 Modules vs. HTML Imports" , в котором объясняются Realms
и Loader
объектов.
Другое объяснение предлагается эта ссылка:
Объект области абстрагирует понятие отдельной глобальной среды, с его собственным глобальным объектом, копией стандартной библиотеки и "intrinsics" (стандартные объекты, не привязанные к глобальным переменным, как начальное значение Object.prototype).
Расширяемая сеть: это динамический эквивалент одного и того же происхождения
<iframe>
без DOM.
Стоит упомянуть: все это все еще в черновике, это не спецификация, выгравированная в камне! Это ES6, поэтому учитывайте совместимость с браузером!
Надеюсь, это поможет!