16

I've been working on upgrading some code to use ES6 syntax. I had the following line of code:

delete this._foo;

and my linter raised a suggestion to use:

Reflect.deleteProperty(this, '_foo');

You can find the documentation for this method here.

The MDN docs state:

The Reflect.deleteProperty method allows you to delete a property on an object. It returns a Boolean indicating whether or not the property was successfully deleted. It is almost identical to the non-strict delete operator.

I understand that the delete keyword does not return a value indicating success, but it is much less verbose.

If I'm not dependent on the success/failure of delete is there any reason to favor Reflect.deleteProperty? What does it mean that delete is non-strict?

I feel like a lot of the use cases for the Reflect API are for resolving exceptional cases and/or providing better conditional flow, but at the cost of a much more verbose statement. I'm wondering if there's any benefit to use the Reflect API if I'm not experiencing any issues with my current usages.

Yukulélé
  • 15,644
  • 10
  • 70
  • 94
Sean Anderson
  • 27,963
  • 30
  • 126
  • 237
  • I'd say no, there doesn't seem to be any other benefits to using `deleteProperty()`. If you don't need to know wether or not the delete was successful, just using `delete` is fine. – adeneo Feb 08 '16 at 18:25
  • 3
    `delete` throws in strict mode if the property is an own non-configurable property, I'm guessing `deleteProperty()` does not throw an error in such cases – adeneo Feb 08 '16 at 18:26
  • 3
    What linter is suggesting that? – Bergi Feb 08 '16 at 18:55
  • @Bergi ESLint's prefer-reflect rule: http://eslint.org/docs/rules/prefer-reflect Of course it's opt-in and not smart enough to realize potential use cases. Just curious if I should honor it or quiet it down. – Sean Anderson Feb 08 '16 at 20:03
  • 1
    A lot of methods that have to do with construction of an object and properties have been added to the new `Reflect` API. Even though `Reflect.deleteProperty()` does not throw an error, it is not going to delete a non-configurable property. – Dmitry S. Feb 08 '16 at 21:26
  • If using `Reflect` is preferred, you could always do `const _delete = Reflect.deleteProperty` and use it like `_delete(this, '_foo')`. – sdgluck Feb 09 '16 at 16:06
  • Possible duplicate of [What is reflection and why is it useful?](http://stackoverflow.com/questions/37628/what-is-reflection-and-why-is-it-useful) – Paul Sweatte Feb 11 '16 at 22:22

1 Answers1

27

Reflect API exposes abstract operations staying behind common JavaScript idioms. It's main use to provide reasonable way to forward actions called on Proxy traps. All of Reflect methods match signature of proxy traps with the same name, so you can use new Proxy(target, Reflect) to create object with identical behaviour as target object - everything will be forwarded, including special JavaScript quirks.

It's especially important for getters and prototypes, as third argument of many methods is "receiver"

The value of this provided for the call to target if a getter is encountered.

Consider following code:

var target = {
    get foo() {
        return this.bar;
    },
    bar: 3
};
var handler = {
    get(target, propertyKey, receiver) {
        if (propertyKey === 'bar') return 2;

        console.log(Reflect.get(target, propertyKey, receiver)); // this in foo getter references Proxy instance; logs 2
        console.log(target[propertyKey]); // this in foo getter references "target" - logs 3
    }
};
var obj = new Proxy(target, handler);

When you write Proxy, you expect it to fully cover target object - and there is no idiomatic way to do this without Reflect.

Moreover, having operators as functions is convenient for functional style programming.

Ginden
  • 5,149
  • 34
  • 68
  • 1
    Reflect isn't needed in new Proxy(target, Reflect). to create a proxy that behaves like the target object you can pass an empty handler. as per docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler "All traps are optional. If a trap has not been defined, the default behavior is to forward the operation to the target." – idan hav Feb 24 '20 at 12:18
  • How is this any different than doing `receiver[propertyKey]` in the place of `Reflect.get(target, propertyKey, receiver)`? – Redu Sep 28 '22 at 15:31