Skip to content Skip to sidebar Skip to footer

Can I Decide What Happens On A Call To A Nonexistent Object Method?

I have code that looks like this: obj.foo(); // obj might, or might not have a `foo` method. I want to know if I can override what happens when obj.foo is called in my code, for e

Solution 1:

Two years ago Benjamin, you didn't understand the notion of behavioral typing very well did you?

Lucky for you, you'll soon realize that an interface is not structural in JavaScript since writing that question, and even wrote a library that solves the exact question you speak of here, only to never use it.

So, to answer your question:

  • Yes, it's perfectly possible to do this.
  • You probably shouldn't for the case you have given.

How to do it

It is perfectly doable if you only have to support really really (really really) new browsers via the Proxy API.

var realObject = { foo: function(){ alert("Bar"); }); // our fooable apivar api = newProxy({}, {
    get: function(target, name){
        if(name in target){ // normal API callreturn target[name]; 
        }
        // return whatever you want instead of the method:returnfunction(){ alert("Baz"); });
    }
});
api.foo(); //alerts Bar
api.bar(); //alerts Baz
api.IWillNotBuyThisRecordItIsScratched(); // alerts Baz

So, while browser support is very shakey, it

Why you shouldn't

Interfaces convey behavior, above cases like typos that can (and should) be normally caught by static analysis tools like jshint or ternjs.

Tools checking for typos are simply not powerful enough to convey behavior in JavaScript, type checking is considered an anti pattern, generally - in languages like JavaScript, Ruby and Python you know the types you'll get.

Solution 2:

Unfortunately that's not possible in any widely supported way. The closest you can get is using a proxy function for all calls, i.e. instead of foo.bar() you would use something like foo.invoke('bar'). However, that's pretty ugly and most likely close to what you meant in the first "not interested in" part.

In loosely-typed languages is is pretty common to expect the developer to pass compatible objects though - i.e. getting an error when passing something unexpected is usually fine.


However, if you are lucky enough to use a JS engine which supports ECMAScript-harmony features (obviously IE doesn't), you can use Proxy objects to achieve this. Basically you wrap your object in a Proxy which lets you trap most operations on the object such as iterating it, retrieving a property, or even creating properties. Besides the two links having a look at this answer to this question might be worth a shot.

Solution 3:

If you're working with strictly defined objects, you should be using custom objects instead of object literals:

functionFoo(bar, baz) {
  this.bar = bar;
  this.baz = baz;
}
Foo.prototype = {
  fizz: function () {
     alert(this.bar + ' ' + this.baz + '!');
  }
};

//elsewhere
f = newFoo('Hello', 'World');
f.fizz();

And then you can tell if the object is a Foo instance by using the instanceof operator:

functionBuzz(foo) {
  if (foo instanceofFoo) {
    foo.fizz();
  }
}
f = newFoo('Hello', 'World');
Buzz(f);

If you're simply looking to check whether an object contains a function at a particular parameter, you can use something like:

functionhasFunction(obj, param) {
    return (typeof obj[param] === 'function');
}
o = {
    foo: function () {}
}
hasFunction(o, 'foo'); //truehasFunction(o, 'bar'); //false

Solution 4:

This is not really useful today (due to spotty browser support), but the Proxy API will allow you to write code that intercepts property access on objects. In other words, when you write:

obj.foo();

The proxy's trap can then return whatever it wants (to be invoked), regardless of whether the property actually exists on the original object.

Post a Comment for "Can I Decide What Happens On A Call To A Nonexistent Object Method?"