Do we really need the [[HasOwnProperty]] internal method and hasOwn trap

Tom Van Cutsem at
Mon Nov 12 01:52:09 PST 2012

2012/11/12 Allen Wirfs-Brock <allen at>

> It isn't clear to me why the [[HasOwnProperty]] internal method and the
> hasOwn Proxy trap need to exist as object behavior extension points.
> [...]
> let p = new Proxy({}, {
>    hasOwn(target,key) {return key === 'foo' ? false:
> Reflect.hasOwn(target,key)}
>    has(target,key) {return key === 'foo' ? true: Reflect.has(target,key)}
> });
> console.log(Reflect.hasOwn(p,"foo"));  //will display: false
> console.log(Reflect.has(p,"foo"));          //will display: true

I think you intended to swap the outcomes: the above is perfectly
consistent with a normal object that inherits a "foo" property. The more
awkward behavior would be an object that says it does have a "foo" own
property, but no "foo" own or inherited property.

> Given,that [[HasOwnProperty]] is not really essential, has good
> alternatives,  and exposes the potential for such inconsistency I think we
> should just eliminate it.  Does anyone want to argue that we need to keep
> it?

I would argue to keep it, on the general principle that all "derived" traps
(like "hasOwn") enable a more "efficient" virtualization (concretely: they
avoid unnecessary object allocations). In this particular case, the
alternative solution would allocate a property descriptor only to test
whether it's not undefined.

We could of course revisit this principle, but that would argue in favor of
abandoning all the derived traps, as they can be dealt with similarly (see <>).

Or we could make ad hoc exceptions on the general principle. For instance
you could argue that "hasOwn" is a much less common operation than "has"
(i.e. the in-operator), such that we don't need a "hasOwn" trap but we do
still need a "has" trap. I'm not a fan of this option though.

(of course, this isn't the only situation where a proxy can be defined that
> exhibits inconsistent responses for the internal methods.  I'm thinking
> about some others too, but this one seems fairly straightforward to
> eliminate).

This is a general issue with all derived traps. Derived traps avoid
allocations, but always open the way to inconsistencies with the
fundamental traps from which they are normally derived.

Note that the "invariant enforcement" technique still doesn't allow a proxy
with non-config/non-extensibility invariants to lie about its own
properties. There are post-condition assertions on both
"getOwnPropertyDescriptor" and "hasOwn" that ensure this. More generally:
as long as a proxy p doesn't answer "true" to Object.isFrozen(p), its
behavior can be arbitrary. Only when some sensible invariants are
established on the proxy's target is the proxy's behavior restrained.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list