15

How can I specify a default getter for a prototype? With default getter I mean a function that is called if obj.undefinedProperty123 is called.

I tried Object.prototype.get = function(property) {..} but this is not called in this case.

Shog9
  • 152,046
  • 34
  • 225
  • 232
Manuel
  • 731
  • 2
  • 7
  • 19
  • 1
    I don't think there is a way to do that even with any non-standard implementation, and certainly not with ECMAScript 5. There is a non-standard implementation called `__noSuchMethod__` for methods in Firefox, and may come on Chrome, but nothing similar for non-function properties. The only route seems to use a wrapper function such as `get` through which all properties are accessed. – Anurag Jun 24 '10 at 19:19
  • Related: [JavaScript getter for all properties](http://stackoverflow.com/q/994143/1048572) – Bergi Sep 29 '14 at 17:08

8 Answers8

12

In ECMAScript 5, you can only intercept get/set operations on specific named properties (not universally all properties) via Object.defineProperty:

Object.defineProperty(someObj, "someProp", {
    get: function() {
        console.log("you tried to get someObj.someProp");
        return "foo";
    }
});

Here, the get function will run any time code tries to read someObj.someProp.

In the upcoming ECMAScript 6 draft, this will be possible via proxies. A proxy has an underlying target object and set/get functions. Any time a set or get operation happens on any of a proxy's properties, the appropriate function runs, taking as arguments the proxy's target object, property name used, and the value used in a set attempt.

var proxyHandler = {
    get: function(obj, name){
        console.log("you're getting property " + name);
        return target[name];
    },
    set: function(obj, name, value) {
        console.log("you're setting property " + name);
        target[name] = value;
    }
}

var underlyingObj = {};

// use prox instead of underlyingObj to use get/set interceptor functions
var prox = new Proxy(underlyingObj, proxyHandler);

Here, setting to getting property values on prox will cause the set/get functions to run.

Matt Way
  • 30,739
  • 10
  • 76
  • 83
apsillers
  • 107,868
  • 16
  • 221
  • 236
4

You need to wait for the implementation of the ECMA6 "Proxy" system, designed to do exactly this. See http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies.

4

What Gareth said, except it's __noSuchMethod__.

Or maybe you were thinking of PHP?

Here's a very good article on the recently standardized property getters/setters, highlighting some previous non-standard incarnations.

http://whereswalden.com/2010/04/16/more-spidermonkey-changes-ancient-esoteric-very-rarely-used-syntax-for-creating-getters-and-setters-is-being-removed/

summary: there's no standard 'catch-all' getter / setter (yet), but Object.defineProperty is the future.

Dagg Nabbit
  • 72,560
  • 18
  • 107
  • 141
2

You want to create a Proxy:

const data = {};

const proxy = new Proxy(data, {
  get: (target, prop) => {
    console.log({ target, prop });
    return "My Value";
  },
  set: (target, prop, value) => {
    console.log({ target, prop, value });
    return true;
  },
});

proxy["foo"] = "bar";
const bar = proxy["foo"];
STEJ
  • 123
  • 3
1

Firefox it's possible with non-standard noSuchMethod:-

({__noSuchMethod__:function(){alert(1);}}).a();
Curtis
  • 98,395
  • 62
  • 265
  • 345
0

I am not sure about what you are asking. But If you want a method to be called when the user attempts to Access object.nonExistingProperty . I dont think there is any way to do that.

Neel Basu
  • 12,338
  • 10
  • 76
  • 142
  • That's just what I want to do. I think it is possible and I think I remember that I did this before - if I'd just know how... – Manuel Jun 24 '10 at 18:47
0

maybe late to ther party, let just add simple ES5 friendly "class creation": both string props and getters - i needed it for some ancient rewrite, to temporarily support IE (yes, that hurts, still found someone relying on ActiveX)

var MyObj = function () {
  var obj = {
    url: 'aabbcc',
    a: function(){ return this.url;}
  }  
  Object.defineProperty(obj, "urltoo", { get: function () { return this.url; } })
  return obj;
}

var X = new MyObj();
x.url // aabbcc
x.urltoo // aabbcc
x.urltoo() // error - not a function
x.a() // aabbcc
x.a // ƒ (){ return this.url;}
Peminator
  • 735
  • 1
  • 8
  • 21
0

I ran into this question because I wanted this behavior: if object property is undefined, return some default value instead.

const options = {
  foo: 'foo',
  bar: 'bar',
  baz: 'baz'
};

function useOptionValue(optionName) {
  // I want `options` to return a default value if `optionName` does not exist
  const value = options[optionName];
  // etc...
}

The simple way to do this (without Proxy or Object.defineProperty overkill for this use case) is like so:

function useOptionValue(optionName) {
  const value = options[optionName] || defaultValue;
}

Or, if you want to get fancy, you could use a Symbol:

const default = Symbol.for('default');

const options = {
  foo: 'foo',
  bar: 'bar',
  baz: 'baz',
  [default]: 'foobarbaz'
};

function useOptionValue(optionName) {
  const value = options[optionName] || options[default];
}
Monkpit
  • 2,500
  • 1
  • 27
  • 35