1

Is there any way to create an object that respond to any message? Suppose you have the following object:

function Dog();
Dog.prototype.speak(){
   alert("woof woof");
}
var myDog = new Dog();

Then when you do myDog.speak() you will get an alert with "Woof woof". But what I want is when you call myDog.jump() (which is not defined in the class) you will get a default action like show the user an alert with "you are trying to excecute an inexistent method".

Do you know how can I do it?

gal007
  • 6,911
  • 8
  • 47
  • 70

3 Answers3

3

Short answer: you can't.

Long answer: you could use __noSuchMethod__ but it's not standard and there are some plans to remove it, because Proxy can do the same, and more. Plus, it's a standard. Therefore, you could use a Proxy to do that, but I would discourage to have all objects as proxies, because performance reasons.

Personally, I would just leave the language thrown it's own exception, that the developer can check in the error console.

ZER0
  • 24,846
  • 5
  • 51
  • 54
1

There is no standards-based way to do this. The closest thing is this.

The closest you could get to this would be:

function execute(obj, message, args) {
    if (obj[message] && typeof(message) === function) {
        obj[message].call(obj, args);
    } else {
       obj[message] = function() {
           //missing method functionality a la Ruby here
       };
    }
}
Mike Thomsen
  • 36,828
  • 10
  • 60
  • 83
  • 1
    ComFreek just said that...in his comment ^^^ – abc123 Oct 23 '13 at 14:40
  • It should be `typeof obj[message] === 'function'`, shouldn't it? (Also add the quotes in case someone defines the variable `function`.) – ComFreek Oct 23 '13 at 14:44
  • I don't think you can redefine `function` like you can with `undefined` but other than that you're correct; typeof always returns a string. – Marcus Stade Oct 23 '13 at 15:00
0

Others have already mentioned __noSuchMethod__ and Proxy so I'll refrain from going into further detail on those.

Instead, I wanted to highlight another technique that may be able to do what you want. Please be aware that this is a ugly hack, I can't encourage it's usage and it may not even work in all of your targets. With those caveats in mind, I present you with window.onerror:

window.onerror = function(err) {
  if (/has no method/.test(err)) {
    console.log('oh my: ' + err) // This is where you'd call your callback
    return true
  }

  return false
}


;(function() {
  this.foo() // will be caught by window.onerror
})()

This – at least in my very limited testing – catches TypeErrors (in Chrome at least, mileage may vary) that signified that the method could not be found. Here are some of the reasons why you should not do this:

  • window.onerror can only have one handler; if your handler is overwritten this won't work
  • It catches TypeErrors globally, not just for a specific object; i.e. lot's of false positives
  • It'll make it fun to debug for anyone coming in not knowing where to find this handler
  • It tightly couples any bit of code you have that relies on this behavior (bad, bad, bad!)

I don't think I can stress enough how much you really shouldn't be thinking of hacking this in. Use Proxy if you can, admit defeat if you can't.

Marcus Stade
  • 4,724
  • 3
  • 33
  • 54