4

As an siginificantly simplified scenario, say I have 2 Javascript objects defined as below:

var ClassA = Class.extend({
    'say': function(message) {
        console.log(message);
    }

    ... // some more methods ...
});

var ClassB = Class.extend({
    init: function(obj) {
        this._target = obj;
    }
});

I'd suppose that in Javascript there is some kind of mechanism could enable us to do the following trick:

var b = new ClassB( new ClassA() );
b.say("hello");

I'd like to find a way to detect if there is a method called upon ClassB, and the method is not defined in ClassB, then I can automatically forward the method call to be upon ClassA, which is a member variable in ClassB.

In a realworld scenario, ClassA is an object implemented as brwoser plugin and inserted into the webpage using <object> tag. It's method is implemented in C++ code so there is no way I can tell its methods from its prototype and insert it to ClassB's prototype beforehand.

I'd like to use the technical to create a native Javascript object, with a narraw-ed version of ClassA's interface. Is there a way I can do this?

hugomg
  • 68,213
  • 24
  • 160
  • 246
Jay Zhu
  • 1,636
  • 13
  • 17
  • 1
    Sounds like you actually want ClassB to inherit the functions of ClassA. Anyway, `Class.extend({})` is no native JS mechanism, what framework are you using? – pixelistik Jul 09 '12 at 11:52
  • @pixelistik I believe he added an extend method to `Object`. – Joseph Jul 09 '12 at 11:55
  • @pixelistik in project I am using JS.Class (http://jsclass.jcoglan.com), while in this example I am using John Resig's Simple Inheritance (http://ejohn.org/blog/simple-javascript-inheritance/). Should not have too much difference though. – Jay Zhu Jul 10 '12 at 01:54

2 Answers2

3

I don't think there is a quick cross-browser solution to this.

If you only need Firefox, then use __noSuchMethod__

See here: is-there-such-a-thing-as-a-catch-all-key-for-a-javascript-object and here: javascript-getter-for-all-properties

Otherwise, I would try something like this:

var b = new ClassB( new ClassA() );

// functionToCall is a string containing the function name
function callOnB(functionToCall) {
    if(typeof b[functionToCall] === function) {
        b[functionToCall]();
    } else {
        b._target[functionToCall](); // otherwise, try calling on A
    }
}

This is using the Square Bracket Notation where

b.say('hello')

is the same as

b['say']('hello')

Of course, you should probably expand this to take arguments in:

function callOnB(functionToCall, listOfArguments) {...}
Community
  • 1
  • 1
jfrej
  • 4,548
  • 29
  • 36
  • BTW, some sorts of evil browser objects (like IE xml stuffs) might give type errors if you access b[functionName] like that or might return "object" to the typeof. You might want to just do a `(functionToCall in b)` test instead. – hugomg Jul 09 '12 at 12:44
  • Also, since we are talking about evil plugin objects, they might not have a call or apply method so you might need to do something like `switch(args.length){ case 1: return f(a) case 2: return f(a,b); ... }` to manually handle multiple arguments. – hugomg Jul 09 '12 at 12:46
1

Thanks to jfrej's hint on noSunchMethod, I did some more research on it and it turns out what I need is quit fit with Harmony Proxies(here and here). And an example can be found at http://jsbin.com/ucupe4/edit#source

Another related post: http://dailyjs.com/2010/03/12/nosuchmethod/

Jay Zhu
  • 1,636
  • 13
  • 17