An update on Object.observe

Coroutines coroutines at gmail.com
Wed Nov 4 05:51:39 UTC 2015


Okay, so I've been making a lot of noise on this list in the last few
days about Proxy and Object.observe().  I thought I would try to put
up some example code to show why both should stay, but
Object.observe() usage should be restricted so it's not web-accessible
(debug use only).

  var target = {} // this is the object we want to "observe", either
with Object.observe() or through a Proxy object.
  var p = new Proxy(target, {}); // this is the proxy where we can add
indirection, validation, or simply watch for events as we attempt to
operate on target

With Object.observe() we would be dealing with the same reference,
`target`.  If we used a Proxy we would replace the `target` reference
with that of the proxy to ensure that every operation on `target` is
going through the handling code of the Proxy:

  target = p; // and now only the Proxy holds an internal reference to
the original object (side question: is this accessible through
p.valueOf()?)

Anyway, my issue with Object.observe() is that you can observe
operations on an object from within closures, from references to
`target` that were made before you began observing.

My example is that you have global access to `String`, but a module
usually wraps all its implementation details and private functions in
a (function (){})() and returns either a constructor or an object with
public-facing functions.

(function () {
  var s = String;
  var private = function () { return new s("cat"); }
  var public = function () { return private(); }
  return public;
})()

Please accept this poor example with awful identifiers as code you
might see in the wild.

Now:

Should you be able to Object.observe() String and see that it is being
used to construct "cat" within the private function, within this
closure?

String is accessible and referenced from many places, so observing
that particular object that is very public seems reasonable.  I am on
the fence about if this should be allowed because while String is
quite 'visible', what is happening within that closure should not be.
Closures are used for organization and to hide implementation details
(of course).

The reason I think Proxy does it "right" is because you would need to
replace the reference to String with a Proxy that wraps String before
the closure makes a localized reference to it and exports its public
function.  I think this still respects the "black box" way closures
are used to hide what they do.  Proxy requires setup before references
are made, Object.observe() can begin watching for changes at any time.
This is because a Proxy is a separate object, and therefore has a
separate identity - while Object.observe() works with the original
object.  I want to say that because the closure seals away the
reference to String, that String should not be observable within the
closure - even if you have access to String outside the closure.  If
you wrap String before executing the closure, then you would of course
have the ability - but only if you proxy it before the closure.  To
*me* that would feel correct.

Anyway, I'm going to try to talk less I've been sending too many
messages.  I come from Lua and I love that this functionality exists
in Javascript exists in its own form.  I did a lot of fun things in
Lua so this is pretty personal to me if I want to continue having fun
in JS.

I want Object.observe() to stay for tricky debug situations, but I
think it would break information hiding/encapsulation on the web by
allowing you to observe changes made through existing private
references.  Proxy is what people should use, O.o() can be a private
sexy debug tool?

FIN.


More information about the es-discuss mailing list