0

I'm sure I've seen this before somewhere. I'm just beginning looking at prototypes so I don't know much.

What's the correct prototype declaration so it catches all requests for varibles? With myObject being an object with the altered prototype.

"myObject.x" would get caught by the function, where I'd then log that there's been a call attempting to access 'x' and return x depending on what was called (not overly important).

(x could be any valid variable name) Edit: So 'myObject.foo' would give a console output of 'foo' and 'myObject.bar' would return 'bar'

I've seen this used in a script where variables were changed before they were returned, but I can't remember enough about it to find it again.

monkeymad2
  • 153
  • 1
  • 11
  • Are you confusing variables with properties? – Bergi Mar 27 '13 at 01:29
  • possible duplicate of [Set undefined javascript property before read](http://stackoverflow.com/questions/11503666/set-undefined-javascript-property-before-read) – Bergi Mar 27 '13 at 01:38
  • I don't think it's a duplicate very near it though,what I want is a way to intercept calls to the variables within an Object (e.g. if(entity.position_X) would give a console output of 'position_X' before returning whatever that value is) – monkeymad2 Mar 27 '13 at 01:52
  • Then the prototype won't help you at all. If there already is a property "position_X" at `entity`, the prototype object won't even notice the access. – Bergi Mar 27 '13 at 01:58

3 Answers3

1

You could make x a method (instead of a property), override it in the subclass (adding your logging call) and then use prototype.x.call to call the super method.

var Foo = function () {
    this.x = function () {
        console.log('ancestor x');
    }
}

var Bar = function () {
    this.x = function () {
        console.log('inherited x');
        Bar.prototype.x.call(this);
    }
}

Bar.prototype = new Foo;

new Bar().x();

Otherwise, there are some vendor extensions and ES5/6 getter methods, but you'll have to contend with erratic browser support for either of those options.

Fiddle

pdoherty926
  • 9,895
  • 4
  • 37
  • 68
0

You are looking for getters/setters:

foo = {};
var x;
Object.defineProperty(foo, 'x', {
    get: function () {
        console.log("Getting:",x);
        return x; // or not..
    },
    set: function (val) {
        console.log("Setting to:", val);
        x = val;
        return x;
    }
});

Of course, these don't work on legacy browser.

Edit: I've created the Waject for this sort of thing: https://github.com/s-p-n/Waject

Spencer Lockhart
  • 1,164
  • 7
  • 7
  • This seems pretty close to what I'm looking for, I'm guessing there isn't a way to set it up as a 'catch all' though? – monkeymad2 Mar 27 '13 at 01:55
0

What's the correct prototype declaration so it catches all requests for varibles? With myObject being an object with the altered prototype.

That's not really related to JavaScript's prototypical inheritance. Creating objects with prototypes can either be done by using the new keyword on constructor functions with their prototype property, or via Object.create. What you're interested in is how to construct an object where every property access…

would get caught by the function

This unfortunately not possible with current JavaScript. You can only set up properties (with values, or with getters/setters) with specific names, a catch-all behaviour is currently not implemented - though some few engines support the Proxy draft. For that, see Is there an equivalent of the __noSuchMethod__ feature for properties, or a way to implement it in JS?, Javascript array with default values (equivalent of Python's defaultdict)? or Set undefined javascript property before read.


I think this comes closest to what you want - using an explicit getter function instead of properties:

function Entity() {
   this.data = {position_X:5, foo:"bar", …};
}
Entity.prototype.get = function (name) {
    console.log("access on "+name);
    return this.data[name];
};

var entity = new Entity;
entity.get("x"); // undefined, but logs "access on x"
entity.get("position_X"); // 5, and logs "access on position_X"
entity.get("foo"); // "bar", and logs "access on foo"
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375