7

I'm sure this has definitively been answered before, and I've tried to search for it.. maybe my search terms are wrong...

Basically I have an object myObject, and I have a set of defined properties and methods for it. What I want to do is be able to handle calls/references to properties and methods that I have not defined.

For example, let's say I have this:

var myObject = {
  someProperty : 'foobar',
  someFunction : function () { /* Do stuff */ }
}

Currently, if someone tries to make a call to myObject.someOtherFunction(), JavaScript yells and screams about it. What I want to do is setup a way to automatically handle that. So for example, instead of JavaScript throwing an error, my object just returns false. Is this possible?

Another way to look at it is this:

var myObject = {
  someFunction : function () { /* Do stuff */ }
  magicBucket : function () { /* Do stuff */ }
}

If I call myObject.someFunction(), well that is defined and does something. What I want to happen is if I were to for instance call myObject.someOtherFunction(), instead of JavaScript throwing an error, it would call myObject.magicBucket().

The reason is that I have a client that uses a third-party library on their site. They want to discontinue using it, but completely removing it is going to take a lot of time and effort. So as a short-term solution, they wanted to know if I could make a dummy file that basically does nothing. Well, this library uses several objects that has lots of methods. I could go through everything and make dummy objects, but I thought maybe there might be some easy "catch-all" method to do this.

Some have mentioned checking if the method exists first, wrapping it in a condition or try..catch, etc. Well, the point of this is that at this time I can't touch the actual calls to the methods. And since the overall goal is to eventually remove the coding altogether, it's not even applicable.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
slinkhi
  • 947
  • 4
  • 16
  • 32
  • This is quite irregular, may I ask why you want this functionality? – azz Aug 28 '13 at 14:37
  • 1
    If you think `someOtherFunction` will either be `undefined` or a function, you could do `myObject.someOtherFunction?myObject.someOtherFunction():false`, so you only invoke `myObject.someOtherFunction` if it is not a "falsy" value (`false` `undefined`, `null`, `0`), or yield `false` as a fallback value. – apsillers Aug 28 '13 at 14:39
  • 1
    http://stackoverflow.com/questions/2527474/is-there-a-way-to-handle-undefined-functions-being-called-in-javascript – Matthew Mcveigh Aug 28 '13 at 14:39
  • 1
    This is more or less a reason for `try`/`catch` blocks or for checking if the desired function/property exists on the object. If someone other than you is using your code, then you cannot be entirely responsible for them trying to use a potentially nonexistent property. Are you encountering a situation where your object may or may not have `someOtherFunction` on it, and you want to handle the situation if it does or does not have it? – ajp15243 Aug 28 '13 at 14:41
  • possible duplicate of [Set undefined javascript property before read](http://stackoverflow.com/questions/11503666/set-undefined-javascript-property-before-read) – Bergi Aug 28 '13 at 14:52
  • Yeah I understand these concepts, but they aren't applicable, see edits – slinkhi Aug 28 '13 at 14:53
  • Given your edits, your best option seems to be to create your dummy object(s) with no-op-esque properties on them. At best, if you can guarantee beyond a shadow of a doubt that your client's code will only be run on Firefox, then the accepted answer in the linked question by @MatthewMcveigh might be applicable. – ajp15243 Aug 28 '13 at 14:55
  • @ajp15243 yes, the accepted answer in MatthewMcveigh's link is exactly what I'm looking for..unfortunately, it is not good enough, since visitors to the website will definitely be using other browsers :( I guess it looks like no magic wand for this – slinkhi Aug 28 '13 at 15:04
  • 1
    I think you're going to have to make an object with all the methods defined but empty function bodies. What might speed up that process is using `for (var mthd in myObject) { if (typeof mthd == 'function') {` to programmatically generate a list of methods to be dummies. (I program quick'ndirty scripts to generate scripts all the time, scriptception basically) – asontu Aug 28 '13 at 15:21
  • @funkwurm yep, that's exactly what i'm doing ;) – slinkhi Aug 28 '13 at 16:22
  • @DerFlatulator I am looking for something like this right now to make a dictionary-like object to feed into some existing code that takes a dictionary as an argument. I cannot provide a dictionary as it would be ridiculously huge (~1TB) but I can calculate entries on the fly. By the way, a[x] and f(x) are conceptually the same in some languages such as k. There is nothing intrinsically special about the code that does an array lookup as opposed to the code that executes some other function, except that JS makes such a distinction, arguably for purely historic reasons. I hope that helps :-) – Max Murphy Aug 08 '16 at 19:59

5 Answers5

4

There's a special property called __noSuchMethod__ which does precisely what you just described. However it's a non-standard property. It only works in Firefox. Here's how you use it:

var o = {
    __noSuchMethod__: function (name, args) {
        alert(name); // prints the name of the method
        alert(args); // prints the array of arguments
    }
};

o.abc(1, 2, 3); // OUTPUT: abc 1,2,3

The future however are proxy objects. The following is a short tutorial on proxies: Proxy Tutorial

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • yep, this is exactly what I need, except that it needs to work in all browsers :/ +1 for being on the right track though – slinkhi Aug 28 '13 at 15:15
  • Thank you for putting me on the right track. The Proxy syntax has changed since that blog post, so the example there doesn't work. MDN has an up-to date example: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy – Max Murphy Aug 08 '16 at 20:06
2

No, you can't have arbitrary getters in JavaScript. You can test if a function exists before calling it to prevent the error though:

if (myObject.someOtherFunction)
    myObject.someOtherFunction();

Or, better, if you don't know that it's necessarily a function:

if (typeof myObject.someOtherFunction == 'function')
    myObject.someOtherFunction();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul
  • 139,544
  • 27
  • 275
  • 264
2

An update on Proxies, here is an infinite array:

$ var squares = new Proxy([], {get:(target,key) => key*key});
$ squares[2]
4
$ Array.isArray(squares)
true
Unfortunately:
$ squares.length
NaN // Want Infinity.

And a dummy object:

$ x = new Proxy({}, {get:(target,key) => console.error("The computer says no", key)})
$ x.laugh
The computer says no laugh

This latter would help the OP make a dummy object, although it would take a bit of black magic to divine what sort of dummy to return.

An up-to date reference: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Max Murphy
  • 1,701
  • 1
  • 19
  • 29
0

You could create a wrapper function like so:

function callFunction(fn, args) {
   var funct = this[fn];
   return (typeof funct == "function") 
      ? funct.apply(this, args)
      : false;
}

And call with:

callFunction("blah", [1, 2, 3]);
>>> false

An example:

this.foo = function(a, b) { 
  console.log(a); 
  return b;
}
callFunction("foo", [1, 2, 3]);
>>> 1 
>>> 2 # return value
azz
  • 5,852
  • 3
  • 30
  • 58
0

With Proxy the following works:

function createPseudoObject() {
  return new Proxy(new Function(), { get() { return createPseudoObject() } })
}

Eg. createPseudoObject().foo.bar.toString() does not throw error and returns undefined. By using new Function() as a base for the dummy object I can reference not just any property, but call any function on the dummy object.

Maybe there are some edge cases that are not covered by this, but something like this should work.

Ádám Bozzay
  • 529
  • 7
  • 19