views:

70

answers:

5

I would like to create a Javascript class that I can use like so:

var f = new myFunction(arg1, arg2);
f.arg1; // -> whatever was passed as arg1 in the constructor
f();
f instanceof myFunction // -> true
typeof f // -> function

I can treat it like a normal object, even adding the native Function object to the prototype chain, but I can't call it like a function:

function myFunction(arg1, arg2) {
  this.arg1 = arg1;
  this.arg2 = arg2;
}
myFunction.prototype = Function
var f = new myFunction(arg1, arg2); // ok
f.arg1; // ok
f(); // TypeError: f is not a function, it is object.
f instanceof myFunction // -> true
typeof f // -> object

I can have the constructor return a function, but then it's not an instance of myFunction:

function myFunction(arg1, arg2) {
  var anonFunction = function() {
  };
  anonFunction.arg1 = arg1;
  anonFunction.arg2 = arg2;
  return anonFunction;
}
var f = new myFunction(arg1, arg2); // ok
f.arg1; // ok
f(); // ok
f instanceof myFunction // -> false
typeof f // -> function

Any suggestions? I should add that I really want to avoid using new Function() since I hate string code blocks.

A: 

This isn't possible. If it should be a instance of your function then it has to be a object. Why do you want this?

Mattias Jakobsson
I want to mimick Scala's `PartialFunction`. I had hoped it was possible because functions are objects in Javascript, but they seem to have some magic specialness that's outside of normal object things that you can manipulate.
pr1001
Ya, "Anonymous" example actually work (didn't think of that). But its using privats that you should not use. So I would strongly recommend against it.
Mattias Jakobsson
It's something a prototype language is only designed to do by changing prototypes.
Anonymous
Yes, I know. I was talking about the "__proto__" property.
Mattias Jakobsson
+1  A: 

function Foo() { var o = function() {return "FOO"}; o.__proto__ = Foo.prototype; return o; }

(new Foo()) instanceof Foo: true

(new Foo())(): FOO

Anonymous
+1  A: 

First and foremost, you should probably be considering some other way of doing this, because it is unlikely to be portable. I'm just going to assume Rhino for my answer.

Second, I'm not aware of any way in Javascript of assigning a function's body after construction. The body is always specified as the object is constructed:

// Normal function definitions
function doSomething() { return 3 };
var doSomethingElse = function() { return 6; };

// Creates an anonymous function with an empty body
var doSomethingWeird = new Function;

Now, there's a non-standard Mozilla extension in the form of a __proto__ property on every object. This allows you the change the inheritance chain of any object. You can apply this to your function object to give it a different prototype after construction:

// Let's define a simple prototype for our special set of functions:
var OddFunction = {
  foobar: 3
};

// Now we want a real function with this prototype as it's parent.
// Create a regular function first:
var doSomething = function() {
  return: 9;
};

// And then, change it's prototype
doSomething.__proto__ = OddFunction;

// It now has the 'foobar' attribute!
doSomething.foobar;  // => 3
// And is still callable too!
doSomething();  // => 9

// And some of the output from your example:
doSomething instanceof OddFunction;  // => true
typeof doSomething;  // => function
Shtééf
A: 

I dont know why you would want to do something like this. But here's a snippet which comes close,

function MyFunction(arg1, arg2)
{
    this.firstProp = arg1;
    this.secondProp = arg2;
}

var f = function(arg1, arg2) {
    return new MyFunction(arg1, arg2);
}(12,13);

alert("Arg1 " + f.firstProp) // 12;

alert("Arg2 " + f.secondProp) // 13;

alert(f instanceof MyFunction) // true;
Aravindan R
A: 

Here is what I think a more javascript way of doing what you want, except it doesn't use the instanceof for objects but an inner one.

var f = function(arg1, arg2){
    return {
        instanceOf:arguments.callee,
        arg1:arg1,
        arg2:arg2
    };
};
var fn = f(1, function(p){ alert(p); });
fn.arg1; // 1
fn.instanceOf === f; //true
typeof f; //function
typeof fn; //object
fn.arg2('hello'); //show alert hello
Mic