Capture method missing in Javascript and do some logic?
Asked Answered
T

4

4

In Ruby, you can capture a call to a method which is missing and define it on the fly.

What I wanna accomplish in JavaScript is to have an object with no methods. I want a missing method to be translated into a call to emit():

app.isReady() -> app.emit("isReady")
soldier.kills() -> soldier.emit("kills")

I think it's better to capture the missing method error and run emit(methodName) rather than defining all methods (from a fixed list) at runtime. That way we don't have performance overhead if there are hundreds or thousands of events for an object.

What is the best way to do this?

UPDATE: This is an API design so I rather stay out of:

try {
  app.isReady()
} catch(e) {
  ...
}

I want to know how I can accomplish this behind the scenes so the users can use methods as usual.

Tenacious answered 27/11, 2011 at 3:10 Comment(0)
I
6

In that way we don't have a performance overhead if there are hundreds/thousands of events for an object.

I think it's a massive misconception to think the performance overhead of adding methods to an object is smaller then the performance overhead of converting method invocations into emit calls.

However you cannot implement this feature in ES5

One could however implement this using Harmony proxies.

I recommend looking at simulating __noSuchMethod__.

I believe ES6 proxies are experimental and can be turned on in V8 so you could use them with node.js today.

Inequity answered 27/11, 2011 at 3:53 Comment(1)
I believe that Harmony:proxies has now been superseded by the newer direct proxies APIGaily
P
2

It's not possible to do that consistently at this stage, unless you can guarantee your app will only run on Mozilla, in which case noSuchMethod is what you're after.

As far as I know, none of the other browsers implement this yet.

Polak answered 27/11, 2011 at 3:52 Comment(2)
__noSuchMethod__ in mozilla will probably be deprecated / removed.Inequity
ah, tks for that. So yeah, no luck for our friend up there anyway ;)Polak
S
0

Use a RegExp test on the function pointer by using the following process:

  • pass the object literal as an argument
  • pass the name of the default method as a string
  • pass the name of the fallback method as a string
  • using subscript notation to dereference the function pointer
  • use a regexp to check the type against the name function
  • if it succeeds, call the default using subscript notation
  • if it fails, call the fallback using subscript notation

For example:

/* Define mapping */
var app = {"emit": emit};

/* Define interface */
function emit(){}

function \u1000missing(object, method, fallback)
  {
  /* Existence check */
  if (/function/.test(object[method]) ) 
    {
    object[method]();
    }
  /* reify */
  else
    {
    object[fallback](method)
    }    
  }

\u1000missing(app,"isReady","emit")

You might ask why you'd ever want to use subscript notation. Subscript notation allows for dynamic creation of properties and methods. So if you ever do any sort of metaprogramming, you'll most likely be using the subscript notation.

References

Sumner answered 4/4, 2014 at 19:31 Comment(0)
S
0

I've create a Node.js package to deal with your situation. It's called auto-object.

Here's a glance:

const myObject = autoObject.createObject(function(name) {
    if(name.startsWith("say")) {
        return function() {
            return name.substr(3);
        }
    }

    return name;
});

myObject.foo;       ///< "foo" 
myObject.sayFoo();  ///< "Foo" 
myObject.sayBar();  ///< "Bar" 

What's more, this works with class too.

Smallwood answered 17/6, 2017 at 12:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.