Reflect.hasOwn() ?
On Sat, Jul 26, 2014 at 5:43 AM, Axel Rauschmayer <axel at rauschma.de> wrote:
The only exception that comes to my mind is
{}.hasOwnProperty.call(obj, key)
(which is the only safe way to invoke this method). Would it make sense to provide that as a tool function, e.g. asReflect.hasOwn()
?
That would make it unsafe again. Not so much from random people polluting the global Object, but certainly unsafe from a security perspective.
With “safe”, I only meant w.r.t. overriding (e.g., obj.hasOwnProperty('foo')
fails if obj
has an own property whose name is 'hasOwnProperty'
).
Security-wise, how is {}.hasOwnProperty.call()
safer than a hypothetical Reflect.hasOwn()
?
obj.hasOwnProperty('foo')
fails with objects that do not inherit from
Object.prototype
I'd personally +1 Reflect.hasOwnProperty(genericObject, propertyName)
without going fancy with shortcuts if the meaning and the result should be
exactly the same as Object.prototype.hasOwnProperty.call(genericObject, propertyName)
My $0.02
2014-07-26 5:43 GMT+02:00 Axel Rauschmayer <axel at rauschma.de>:
ECMAScript 6 mostly eliminates the need to call methods generically (no need to use the array-like
arguments
,Array.from()
, spread operator, etc.).The only exception that comes to my mind is
{}.hasOwnProperty.call(obj, key)
(which is the only safe way to invoke this method). Would it make sense to provide that as a tool function, e.g. asReflect.hasOwn()
?
Reflect.hasOwn was actually included in the Reflect API initially, as the dual to the Proxy "hasOwn" trap. When we decided to remove the trap, we also threw out Reflect.hasOwn (in keeping with the symmetry between these Reflect.* utilities and the Proxy traps).
The rationale to remove Reflect.hasOwn was that it could easily be simulated via (Reflect.getOwnPropertyDescriptor(obj,name) !== undefined). While this conses a throw-away property descriptor object, the overhead was deemed insignificant.
Overall, I'm leaning towards keeping the built-in Reflect API minimal. There's room for many more utility methods (Reflect.getPropertyDescriptors comes to mind) which can all be expressed as a library.
The rationale to remove Reflect.hasOwn was that it could easily be simulated via (Reflect.getOwnPropertyDescriptor(obj,name) !== undefined). While this conses a throw-away property descriptor object, the overhead was deemed insignificant.
Sounds good.
Still, hanging "hasOwnProperty" off of Object.prototype was a mistake and a is constant source of irritation. Perhaps the mistake could be rectified by hanging the same functionality directly off of Object?
if (Object.hasOwn(obj, "foo")) doSomething();
On Fri, Jul 25, 2014 at 9:02 PM, Peter van der Zee <ecma at qfox.nl> wrote:
That would make it unsafe again. Not so much from random people polluting the global Object, but certainly unsafe from a security perspective.
Hi Peter, what is the security issue you are concerned about?
why would you drop the specificity of the name?
would a Symbol be a valid second argument ?
and what if one day we'd like to introduce a hasOwnValue instead, as similar to Array#contains but for generic objects ?
Overall, I'm leaning towards keeping the built-in Reflect API minimal. There's room for many more utility methods (Reflect.getPropertyDescriptors comes to mind) which can all be expressed as a library.
After thinking about it some more, I agree w.r.t. these two examples:
- As far as I can tell,
hasOwnProperty
is mainly used to implement maps via objects.Map
will eliminate this use case. getPropertyDescriptors
is useful for cloning objects viaObject.create()
, whereObject.assign
can often be used in ES6.
- As far as I can tell,
hasOwnProperty
is mainly used to implement maps via objects.Map
will eliminate this use case.
To a certain extent yes, but not completely. Objects-as-maps will still be used quite frequently as object literals passed into functions (as an options object, for example).
I think that there is still a need here. Since we are really interested in keys, what about this:
Object.hasKey(obj, someKey);
which would be a more ergonomic and efficient way of saying:
Object.keys(obj).some(key => key === someKey)
?
On Jul 26, 2014, at 20:36 , Kevin Smith <zenparsing at gmail.com> wrote:
- As far as I can tell,
hasOwnProperty
is mainly used to implement maps via objects.Map
will eliminate this use case.To a certain extent yes, but not completely. Objects-as-maps will still be used quite frequently as object literals passed into functions (as an options object, for example).
I think that there is still a need here.
Yes, but it’s much less urgent.
Since we are really interested in keys, what about this:
Object.hasKey(obj, someKey);
Ah, good point! I hadn’t thought of symbols as property keys.
which would be a more ergonomic and efficient way of saying:
Object.keys(obj).some(key => key === someKey)
Did you mean Reflect.ownKeys()
? How about:
Reflect.ownKeys(obj).indexOf(someKey) >= 0
Or, maybe in ES7:
Reflect.ownKeys(obj).contains(someKey)
Did you mean
Reflect.ownKeys()
?
I meant Object.keys. That will eliminate the inconsistency between Object.keys usage and hasOwnProperty usage that crops up sometimes:
When dealing with objects-as-maps, it's usually just the key-ness that you're interested in, not whether the property is inherited or not.
I meant Object.keys. That will eliminate the inconsistency between Object.keys usage and hasOwnProperty usage that crops up sometimes:
Nevermind. Brain-stall. Sorry about the noise.
On 7/26/14, 5:33 AM, Tom Van Cutsem wrote:
The rationale to remove Reflect.hasOwn was that it could easily be simulated via (Reflect.getOwnPropertyDescriptor(obj,name) !== undefined). While this conses a throw-away property descriptor object, the overhead was deemed insignificant.
That depends on how much work an implementation has to perform to produce the value of a value property, doesn't it.
In the case of some DOM objects that work can be fairly significant (e.g. O(N) in size of the document).
On the other hand, maybe performance of Reflect.* is just not that critical.
On Sat, Jul 26, 2014 at 11:36 AM, Kevin Smith <zenparsing at gmail.com> wrote:
- As far as I can tell,
hasOwnProperty
is mainly used to implement maps via objects.Map
will eliminate this use case.To a certain extent yes, but not completely. Objects-as-maps will still be used quite frequently as object literals passed into functions (as an options object, for example).
In that case, though, you don't want to use hasOwnProperty
; you want
to allow property bags to express properties on the proto (for
example, as getters). So this particular use-case of objects-as-maps
is irrelevant for the question at hand.
I think that there is still a need here. Since we are really interested in keys, what about this:
Object.hasKey(obj, someKey);
which would be a more ergonomic and efficient way of saying:
Object.keys(obj).some(key => key === someKey)
This is identical to obj.key !== undefined
, unless you're allowing
undefined to be passed explicitly as a valid argument for some reason.
On Sat, Jul 26, 2014 at 5:14 PM, Mark S. Miller <erights at google.com> wrote:
Hi Peter, what is the security issue you are concerned about?
Unless Reflect
is completely sealed out of the box, you can never
know whether properties on it are the actual built-ins. That's all.
Le 27/07/2014 13:35, Peter van der Zee a écrit :
On Sat, Jul 26, 2014 at 5:14 PM, Mark S. Miller <erights at google.com> wrote:
Hi Peter, what is the security issue you are concerned about? Unless
Reflect
is completely sealed out of the box, you can never know whether properties on it are the actual built-ins. That's all.
You can deeply freeze it yourself before any other script accesses it.
Even without doing so, let's say Reflect is not sealed. If you change it yourself (by code you wrote or imported), you know what to expect (or you didn't audit code you import, but them, you also know you can only expect the worst). If you don't change Reflect yourself, then it's third-party code which is. But then, why did you let this third-party code access to the capability of modifying the built-ins? You could set up a proxy in your own domain, fetch thrid-party scripts from there and serve them to your own domain confined (with Caja or else).
My point being that there are ways to prevent any non-trusted scripts from modifying Reflect (assuming you stay away from script at src which doesn't allow any form of confinment on the imported script)
For ES6, I'm not clear yet on how the module loader will work with to cross-domain scripts. I believe part of the web platform security model relies on a page not being able to read the content of thrid-party scripts it imports via script at src (IIRC because some websites send private data based on cookies in such scripts, so being able to read the content of such scripts would lead to terrible data leakage). Does the module loader preserves such a guarantee?
On Sun, Jul 27, 2014 at 1:57 PM, David Bruant <bruant.d at gmail.com> wrote:
You can deeply freeze it yourself before any other script accesses it.
That's already assuming you are first. You may not be without your knowledge (ISP injection, virus hijack, garden gnomes, etc). At this point you'll be too late.
My point being that there are ways to prevent any non-trusted scripts from modifying Reflect
And I guess I'm saying, "no, there isn't".
It'd be nice if there was some kind of mechanic of detecting/ensuring that some built-in is indeed a built-in. That would take away all of this pain. Maybe including a system module could fix this issue. I doubt I'm the first here to mention that though.
Although there is some interesting work in trying to obtain security relevant guarantees from a script that isn't first, where a malicious script may instead have been first (link please if anyone has it), this work did not seem practical to me.
My POV: A realm starts out pervasively malleable. It can only provide practical protection to some scripts within the realm from other scripts in that realm if the first script loaded into that realm is not harmful to this cause, and if a script supportive of that cause (like initSES.js) is loaded before any scripts that may be harmful to that cause.
On Sun, Jul 27, 2014 at 6:14 PM, Mark S. Miller <erights at google.com> wrote:
Although there is some interesting work in trying to obtain security relevant guarantees from a script that isn't first, where a malicious script may instead have been first (link please if anyone has it), this work did not seem practical to me.
I'm not familiar with actual deep research in this area for JS.
Seems to me like a syntactic way of including a module that's guaranteed to be a system module (completely sealed of the shelf) would circumvent a lot of these problems. For example, a module that gives you a fresh default global object with all the built-ins guaranteed unchanged. Since the syntax can't really be affected by an earlier script and the language could define a hardcoded system module, this kind of approach seems viable to me. But we're digressing from the topic.
On Sunday, July 27, 2014, Tab Atkins Jr. <jackalmage at gmail.com> wrote:
On Sat, Jul 26, 2014 at 11:36 AM, Kevin Smith <zenparsing at gmail.com <javascript:;>> wrote:
- As far as I can tell,
hasOwnProperty
is mainly used to implement mapsvia objects.
Map
will eliminate this use case.To a certain extent yes, but not completely. Objects-as-maps will still be used quite frequently as object literals passed into functions (as an options object, for example).
In that case, though, you don't want to use
hasOwnProperty
; you want to allow property bags to express properties on the proto (for example, as getters). So this particular use-case of objects-as-maps is irrelevant for the question at hand.I think that there is still a need here. Since we are really interested in keys, what about this:
Object.hasKey(obj, someKey);
which would be a more ergonomic and efficient way of saying:
Object.keys(obj).some(key => key === someKey)
This is identical to
obj.key !== undefined
,
As long as "key" is enumerable.
2014-07-27 18:14 GMT+02:00 Mark S. Miller <erights at google.com>:
Although there is some interesting work in trying to obtain security relevant guarantees from a script that isn't first, where a malicious script may instead have been first (link please if anyone has it), this work did not seem practical to me.
Not sure if this is what you had in mind, but Sergio Maffeis has been working on something along these lines:
DefensiveJS (DJS) www.defensivejs.com
"DJS is a defensive subset of JavaScript: code in this subset runs independently of the rest of the JavaScript environment. When propertly wrapped, DJS code can run safely on untrusted pages and keep secrets such as decryption keys."
Previous thread (2 years ago) here: esdiscuss.org/topic/reflect-hasown
It is still incredibly common to check if an object contains a key using:
if (Object.prototype.hasOwnProperty.call(myObject, key))
This syntax is quite verbose, and doesn't really make sense in the first place. As someone said in the previous thread, hasOwnProperty should have never been added to the Object prototype.
According to the discussion, Reflect.hasOwn has been thrown away in order to keep the Reflect API simple, arguing that such a method could easily be replaced by Reflect.getOwnPropertyDescriptor anyway. While this is certainly true, the situation isn't without parallel with Array.prototype.includes, which has been added as least in part in order to help conveying a semantic meaning in the source code.
Since the usage hasn't decreased, what would you think about reconsidering Reflect.hasOwn for adoption?
Reflect is a namespace that contains the proxy traps (it’s a bit of an unfortunate name), so we shouldn’t be adding things to it that are not part of the meta-object protocol.
A new namespace, or using Object, might be OK. I think that it will still be controversial, since this proposal is in support of an objects-as-maps programming style which has caused many problems in the past and should not be encouraged. See e.g. www.2ality.com/2012/11/proto-breaks-webapps.html.
If you are using objects-as-maps safely, you’d use Object.create(null), in which case the in
operator works fine and there's no need for hasOwnProperty incantations.
JSON.parse() and object literals are big sources of objects-as-maps. In
both of these cases, using the in
operator won't give the right answer.
Le mar. 6 sept. 2016 à 22:11, Domenic Denicola <d at domenic.me> a écrit :
I'll admit I use them partially out of laziness and partially because
engines already optimize for this much better than with actual maps (only
string keys). I frequently alias const hasOwn = Object.prototype.hasOwnProperty
, so this wouldn't do much for me other
than saving a declaration in each file I use it. Honestly, though, I feel
it was a design flaw from the start to be on the prototype, but we can't
just time travel and fix it.
Removing hasOwnProperty from Object.prototype would break a lot of code, so it's not even an option, but we could at least add Object.hasOwn, since Reflect apparently isn't the right place for this (it's a shame, it would mirror nicely with Reflect.ownKeys).
Doing this would improve a bit the clarity of new codes, and could prevent silly mistakes, the kind we all hate to debug (I've been unable to find a reliable tool that could search for exact matches in a large number of source codes, but I feel like forgetting the .call probably happens every once in a while).
Le mer. 7 sept. 2016 à 06:08, Isiah Meadows <isiahmeadows at gmail.com> a écrit :
Just my 2 cents.
The tiniest JS utility I know [1] solves verbosity and freeze the method so it's also safe.
// meet callerOf
function callerOf(c) {return c.call.bind(c)}
// how to use it
const hasOwn = callerOf({}.hasOwnProperty);
hasOwn({key: 'value'}, 'key'); // true
hasOwn({value: 'key'}, 'key'); // false
However, since functions also inherit from Object.prototype
, I usually
write this shortcut to semantically reach the
Object.prototype.hasOwnProperty
method, avoiding the need of the
callerOf
utility:
// assign it once per module/scope
var hOP = Object.hasOwnProperty;
// whenever is needed
hOP.call({key: 'value'}, 'key'); // true
hOP.call({value: 'key'}, 'key'); // false
Beside the top level copy&paste operation to define hOP
, writing
hOP.call(o,k)
is less verbose than Reflect.hasOwn(o,k)
and strawberry
on top, there's nothing else to explain for something that has been
misunderstood for a very long time ( hasOwnProperty
through
Object.prototype
vs in
)
Best
On Sep 6, 2016, at 4:10 PM, Domenic Denicola <d at domenic.me> wrote:
Reflect is a namespace that contains the proxy traps (it’s a bit of an unfortunate name), so we shouldn’t be adding things to it that are not part of the meta-object protocol.
I generally disagree with the idea that this doesn’t belong in “Reflect” because it’s not an MOP operation. There are three reasons for this.
-
only spec editors care about whether an operation is MOP or not. JS authors are concerned with operations and algorithms that are helpful to their work, not whether it’s written as [Op] vs Op(). To a JS author, HasOwnProperty() is just as valid of a reflection mechanism as [HasProperty].
-
Given what was said above about hasOwn() being a valid and useful reflection mechanism, and as you’ve mentioned, the “Reflect” namespace indicates that it performs reflection tasks, not that it lets you perform spec internal MOP operations.
-
Even if Reflect were exclusively for MOP operations, it tends to add extra steps which are not part of the MOP operation. These can make the methods more useful for JS consumers, or they can be convenience mechanisms, but either way, it’s not a 1:1 mapping to MOP operations.
I think it belongs in Reflect, as it’s a reflection capability, the MOP status is a moot point (and it’s just a thin wrapper around [[GetOwnProperty]] anyways), and changing Reflect is less likely to break content than changing Object.
In the meantime, var hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty)
will continue to be a useful workaround for people.
Reflect is a namespace that contains the proxy traps (it’s a bit of an unfortunate name), so we shouldn’t be adding things to it that are not part of the meta-object protocol.
A new namespace, or using Object, might be OK. I think that it will still be controversial, since this proposal is in support of an objects-as-maps programming style which has caused many problems in the past and should not be encouraged. See e.g. www.2ality.com/2012/11/proto-breaks-webapps.html.
If you are using objects-as-maps safely, you’d use Object.create(null), in which case the in
operator works fine and there's no need for hasOwnProperty incantations.
Previous thread (2 years ago) here: esdiscuss.org/topic/reflect-hasown
It is still incredibly common to check if an object contains a key using:
if (Object.prototype.hasOwnProperty.call(myObject, key))
This syntax is quite verbose, and doesn't really make sense in the first place. As someone said in the previous thread, hasOwnProperty should have never been added to the Object prototype.
According to the discussion, Reflect.hasOwn has been thrown away in order to keep the Reflect API simple, arguing that such a method could easily be replaced by Reflect.getOwnPropertyDescriptor anyway. While this is certainly true, the situation isn't without parallel with Array.prototype.includes, which has been added as least in part in order to help conveying a semantic meaning in the source code.
Since the usage hasn't decreased, what would you think about reconsidering Reflect.hasOwn for adoption?
I'll admit I use them partially out of laziness and partially because
engines already optimize for this much better than with actual maps (only
string keys). I frequently alias const hasOwn = Object.prototype.hasOwnProperty
, so this wouldn't do much for me other
than saving a declaration in each file I use it. Honestly, though, I feel
it was a design flaw from the start to be on the prototype, but we can't
just time travel and fix it.
Removing hasOwnProperty from Object.prototype would break a lot of code, so it's not even an option, but we could at least add Object.hasOwn, since Reflect apparently isn't the right place for this (it's a shame, it would mirror nicely with Reflect.ownKeys).
Doing this would improve a bit the clarity of new codes, and could prevent silly mistakes, the kind we all hate to debug (I've been unable to find a reliable tool that could search for exact matches in a large number of source codes, but I feel like forgetting the .call probably happens every once in a while).
Le mer. 7 sept. 2016 à 06:08, Isiah Meadows <isiahmeadows at gmail.com> a écrit :
JSON.parse() and object literals are big sources of objects-as-maps. In
both of these cases, using the in
operator won't give the right answer.
Le mar. 6 sept. 2016 à 22:11, Domenic Denicola <d at domenic.me> a écrit :
Just my 2 cents.
The tiniest JS utility I know [1] solves verbosity and freeze the method so it's also safe.
// meet callerOf
function callerOf(c) {return c.call.bind(c)}
// how to use it
const hasOwn = callerOf({}.hasOwnProperty);
hasOwn({key: 'value'}, 'key'); // true
hasOwn({value: 'key'}, 'key'); // false
However, since functions also inherit from Object.prototype
, I usually
write this shortcut to semantically reach the
Object.prototype.hasOwnProperty
method, avoiding the need of the
callerOf
utility:
// assign it once per module/scope
var hOP = Object.hasOwnProperty;
// whenever is needed
hOP.call({key: 'value'}, 'key'); // true
hOP.call({value: 'key'}, 'key'); // false
Beside the top level copy&paste operation to define hOP
, writing
hOP.call(o,k)
is less verbose than Reflect.hasOwn(o,k)
and strawberry
on top, there's nothing else to explain for something that has been
misunderstood for a very long time ( hasOwnProperty
through
Object.prototype
vs in
)
Best
On Sep 6, 2016, at 4:10 PM, Domenic Denicola <d at domenic.me> wrote:
Reflect is a namespace that contains the proxy traps (it’s a bit of an unfortunate name), so we shouldn’t be adding things to it that are not part of the meta-object protocol.
I generally disagree with the idea that this doesn’t belong in “Reflect” because it’s not an MOP operation. There are three reasons for this.
-
only spec editors care about whether an operation is MOP or not. JS authors are concerned with operations and algorithms that are helpful to their work, not whether it’s written as [Op] vs Op(). To a JS author, HasOwnProperty() is just as valid of a reflection mechanism as [HasProperty].
-
Given what was said above about hasOwn() being a valid and useful reflection mechanism, and as you’ve mentioned, the “Reflect” namespace indicates that it performs reflection tasks, not that it lets you perform spec internal MOP operations.
-
Even if Reflect were exclusively for MOP operations, it tends to add extra steps which are not part of the MOP operation. These can make the methods more useful for JS consumers, or they can be convenience mechanisms, but either way, it’s not a 1:1 mapping to MOP operations.
I think it belongs in Reflect, as it’s a reflection capability, the MOP status is a moot point (and it’s just a thin wrapper around [[GetOwnProperty]] anyways), and changing Reflect is less likely to break content than changing Object.
In the meantime, var hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty)
will continue to be a useful workaround for people.
ECMAScript 6 mostly eliminates the need to call methods generically (no need to use the array-like
arguments
,Array.from()
, spread operator, etc.).The only exception that comes to my mind is
{}.hasOwnProperty.call(obj, key)
(which is the only safe way to invoke this method). Would it make sense to provide that as a tool function, e.g. asReflect.hasOwn()
?