3

I am fumbling for a way to avoid creating a new Proxy for each new object instance. I have 1 prototype, and I want to use just 1 Proxy. That's the goal. If I use a Proxy per instance, I could have thousands and thousands of Proxy objects which hurts performance a lot.

Ultimately what I am doing is setting properties on a prototype method, like this:

const v = {
  foo: function () {
    assert.notEqual(this, v);
  }
};

v.foo.bar = function(){
   // I need `this` to be a certain value here
};

v.foo.zam = function(){
   // I need `this` to be a certain value here
};

but I need those properties to still have the same context (this value), as the prototype method itself would.

const assert = require('assert');

const v = {
  foo: function () {
    assert.notEqual(this, v);
  }
};

new Proxy(v.foo, {
  get: function(target, prop){
     console.log(this); // I am looking to get access to `x` here
  }
});


const x = Object.create(v);

x.foo();
const z = x.foo.bar; // I would have guessed this would have fired the Proxy `get` method.

I am trying to do some black magic, where I can access the this value of the v prototype methods from the Proxy. In this case, that would mean accessing the value of x from the Proxy. Is this possible somehow? Also, I can't figure out why the get method of the Proxy is not called when I read the bar property from x.foo, as in x.foo.bar.

this Github gist I just created is a little bit closer: https://gist.github.com/ORESoftware/757dd6285d554f4f52ae415fd39141a5

however, I still don't think it's possible to do what I want to do. The rationale is so that I can reuse the same Proxy object in the prototype, without having to create a new Proxy for each instance.

6
  • you've created a proxy for v.foo - why would it even know about x Commented Dec 13, 2017 at 5:28
  • it wouldn't know about x, but even if it was a proxy for v instead of v.foo - it wouldn't know about x either, unless it could somehow access the this value of the prototype method somehow Commented Dec 13, 2017 at 5:30
  • I am fumbling for a possible way to do this, but it might not be possible Commented Dec 13, 2017 at 5:31
  • You've created a proxy but then you're not using p anywhere? Commented Dec 13, 2017 at 5:57
  • yeah, I don't need to use p itself, I just need to use the hooks get/set Commented Dec 13, 2017 at 5:58

3 Answers 3

2

You're not looking for a proxy, all you need is a simple getter:

const v = {
  get foo() {
    console.log(this); // will log x
    return Object.assign(() => "hi", {bar: 42});
  }
};

const x = Object.create(v);

console.log(x.foo());
console.log(x.foo.bar);

The rationale is so that I can reuse the same Proxy object in the prototype, without having to create a new Proxy for each instance.

For that you would need to use the proxy as the prototype. Your current code is just creating a proxy object and then throwing it away, which will not affect the original code in any way. You'd rather need to do something like

const p = new Proxy({}, {
  get(target, prop) {
    console.log(target); // will log x
    if (prop == "foo")
      return Object.assign(() => "hi", {bar: 42});
  }
});

const x = Object.create(p);
//                      ^ use the proxy here!

console.log(x.foo());
console.log(x.foo.bar);
Sign up to request clarification or add additional context in comments.

8 Comments

I was thinking about that, let me try it
I have pretty stupid/clever idea that will just take advantage of JS single-threaded nature - I can just set a context value when a property is accessed, that should work, will add an answer later. This is all synchronous code, nothing async, so I can some more black magic.
@AlexanderMills What problem are you trying to solve?
I am simply trying to avoid creating a new Proxy for each instance. I have 1 prototype, and I want to use just 1 Proxy. That's the goal. If I use a Proxy per instance, I could have thousands and thousands of Proxy objects which hurts performance a lot.
OK, but that's rather standard usage not black magic :-) Still, why are you using proxies at all?
|
2

You can also add the proxy to the object prototype.

SomeObject.prototype = new Proxy(
    SomeObject.prototype,
    SomeObjectHandlerProxy
);

instance = new SomeObject();

something like should work

1 Comment

Note that for built-in objects prototype is not writable: stackoverflow.com/a/76366833/10406353
0

Some black magic here, but it works, you can use an Object.defineProperty getter to set the context for the proxied prototype method, (note this methodology will only work for synchronous parts of your code).

const proto = {};  // the prototype object 

const ctx = {
   val: null
};

const foo = function () {
    // the prototype method
    // do something with ctx.val which gets set dynamically
};

foo.bar = function(){
  // doing important stuff here
  // do something with ctx.val which gets set dynamically
};

const p = new Proxy(foo, {
  get: function (target, prop) {

    if (typeof prop === 'symbol') {
      return Reflect.get.apply(Reflect, arguments);
    }

    // do something with ctx.val
    // => ctx.val

  }
});


Object.defineProperty(proto, 'foo', {
  get: function() {
    ctx.val = this;  // set the context here!!
    return p;
  }
});

now we can use it like so:

proto.foo.bar()

when foo is accessed, it then dynamically sets the ctx for bar()

I end up using it like so:

const o = Object.create(proto);
o.foo.bar();

And we can also call o.foo() if we want to.

3 Comments

this answer is correct, but it's not simple, so read it carefully
This could fail in some cases then a = proto.foo;somecode();a.bar();
yes, it will fail if a.bar() and proto.foo was set to the wrong context.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.