tags:

views:

81

answers:

3

I'm looking for a way to handle calls to undefined methods and properties in JavaScript.

These would be similar to the PHP magic methods __call, __callStatic, __get.

An example of the code using this might be:

var myObject = {};
myObject.__call = function (called, args) {
    alert(called);
    alert(args);
    return(true);
}

myObject.meow("kitty", "miau");

This would result in the first alert dialog displaying "meow" and the second to display "kitty, miau".

A: 

There is a magic function in Javascript called __noSuchMethod__. Here's an example:

var foo = { __noSuchMethod__ : function(name,params) { alert('invalid function call'); } }
foo.bar();

EDIT: As @jldupont mentioned, this is actually only in Rhino and SpiderMonkey (Mozilla's JS engine); it is not supported in the ECMAScript standard. There are some requests that it be in ECMAScript 4.

Alex Beardsley
this isn't standard...
jldupont
not even on V8: http://code.google.com/p/v8/issues/detail?id=264
jldupont
OP never mentioned that as a requirement; for all i know he could be using Rhino. just saying, this is one way to do it.
Alex Beardsley
Ideally it would be a standard approach, yes. At the very least, webkit and mozilla browsers would be able to do it.
Omega
This is the best answer I will be getting for now. Thank you for at least drawing my attention to the method name.I encourage readers to comment on and vote for the following issue:http://code.google.com/p/v8/issues/detail?id=264It may be closed, but voicing support is the only way to raise awareness.
Omega
A: 

I should add for people still looking for a solution, there is this:

var myObject = {};
myObject['dynamicMethod'] = new function (parameters) {
    alert(parameters);
};

The only difference here is that you may have to iterate over what you intend on adding. This is pre-generating the methods, instead of simply dynamically handling them.

Omega
A: 

If you just want something like PHP's features, read the following solution I came up with. I'm assuming that you'll be putting this functionality on your own objects. Well, as long as they're not functions, you can have the following convention for convenience, and it should work on all browsers:

instead of myobj.foo or myobj['foo'], just use myobj('foo'), and make your object callable when you define it. But you'll have to avoid the use of "new" because "new" can never return a function in Javascript.

var NewFlexible = function() {
  var custom = {};
  return function(prop) {
    if (!(prop in custom)) custom.prop = null;
    return custom.prop;
  };
};

And then you can create objects like so:

myObj = NewFlexible();

Using something similar to the Douglas Crockford pattern, you could create "classes" that extend this:

var NewDerived = function(options) {
  var result = {};
  NewFlexible.apply(result, arguments); // parent constructor
  // go on to do what you have to do
  return result;
};

Or, to forget about constructors, you can just make a wrapper around objects:

var MakeFlexible = function (obj) { 
 return function(prop) { 
   if ('prop' in obj) return obj.prop; 
   obj.prop = null; return obj.prop;
 };
}

You'll just have to publish this documentation for all users of your code. It's actually good to expose your functionality through this convention because you don't want to freak people out by using nonstandard javascript.

Magarshak
But this *is* basically nonstandard Javascript. This is fine for quickie projects, but I wouldn't recommend starting a large code base using this pattern.
quixoto
Just trying to be helpful. It clearly seemed the guy wanted similar functionality to PHP for some reason, i.e. a convenient notation for accessing properties that weren't there. So the easiest thing I could think of is to have objects that support foo('bar') instead of foo['bar'], which is pretty close to what the guy wanted, without using nonstandard javascript properties. This is using quite standard Javascript. It will work on every browser. The fact that it might be an unusual desire is not my fault -- it's the closest you can get (IMHO) to answering the question while using correct JS.
Magarshak