1

Use case is similar to "How can I use an object as a function and an object?"

My current solution:

var newObj = function(_id){
  var obj = function(arg){
    console.log('call', _id, arg);
  }
  obj.test = function(arg){
    console.log('test', _id, arg);
  }
  console.log('new', _id);
  return obj
}

var obj = newObj('1');
obj('2');
obj.test('3');

Now, this works perfectly, if you have small number of objects.

But, when you get large number of methods and a lot of objects, you'd want to move all methods to prototype. How is it possible to do?

Naive solution, like this:

var Obj = function(id){
  this.id = id
  console.log('new',id)
}
Obj.prototype = function(arg){
  console.log('call', this.id, arg)
}
Obj.prototype.test = function(arg){
  console.log('test', this.id, arg)
}
var obj = new Obj('1');
obj('2'); // this fails with "TypeError: obj is not a function"
obj.test('3');

does not work.

EDIT: End objective is to shorten syntax of the most used method of an object.

For example: bus object has method post. This method is called 99.99% time, when you are doing something with bus. Always writing bus.post(...) is redundant. Creating closures or bindings is also not an option, as there are many buses.

Current solution (without prototype) works fine though, with small number of objects.

Community
  • 1
  • 1
metalim
  • 1,479
  • 1
  • 12
  • 22
  • possible duplicate of [Can a JavaScript object have a prototype chain, but also be a function?](http://stackoverflow.com/questions/340383/can-a-javascript-object-have-a-prototype-chain-but-also-be-a-function) – franciscod Jul 15 '15 at 10:31
  • but why you want this? first case only works because you return function instead of object – Grundy Jul 15 '15 at 10:32
  • Please explain your end objective. Not what you think you need to do to do what you want to do, but what you actually want to do. Give an example of your machinery in actual use or as you hope to use it. –  Jul 15 '15 at 10:35
  • End objective is to shorten syntax of the most used method of an object. For example: `bus` object has method `post`. This method is called 99.99% time, when you are doing something with `bus`. – metalim Jul 15 '15 at 13:46
  • That sounds like an unnecessary complication to me. I'd just keep it simple. – 1983 Jul 21 '15 at 09:31

3 Answers3

1

Please see the linked question in the comments.

The best you can do is create an object to hold your reusable functions, and then copy those properties onto each new function object you want to create.

var reusablefuncs = {
    f1: function(){ return 'f1'; },
    f2: function(){ return 'f2'; }
};

var f = function(){
    return 'f';
};

Object.keys(reusablefuncs).forEach(function(prop){
    f[prop] = reusablefuncs[prop];
});

console.log(f(), f.f1(), f.f2());

But -- why do you want to do this?

1983
  • 5,882
  • 2
  • 27
  • 39
  • 1
    in new browsers you can use [`Object.setPrototypeOf`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) instead – Grundy Jul 15 '15 at 11:38
  • 1
    @Grundy Yeah. You'd have to define `reusablefuncs` as a function itself to make sure that `call`, `apply`, etc. remain in the prototype chain. – 1983 Jul 15 '15 at 11:46
1

You cannot directly do what you want to. A function is a function and has a function prototype. What you can do is place a single object as a property on each function, and invoke your routines through it.

This would be used like this:

var obj = newObj('1');
obj('2');
obj.methods.test('3');
    ^^^^^^^ INVOKE VIA METHODS PROPERTY

You can think of this as sort of a hand-rolled prototype.

Now we will arrange for the methods property to return a hash of functions correctly bound to this, allowing access to id, for example. To solve this, we'll add methods to the function as a gettable property, returning a hash of methods, each bound to the proper this:

var Obj = function(id){
  this.id = id
  console.log('new',id)
  Object.defineProperty(this, 'methods', {
    get: function() { return methods(this); }
  });
}

Now define methods as

function methods(obj) {
  return {
    test: function(arg) {
      console.log('test', this.id, arg);
    }.bind(obj)
};

The only footprint now on the individual function objects is the single methods property. Everything else is shared. However, there is a run-time cost per-access for invoking the methods function. You can't have it both ways: either you can pre-bind and place the methods on each object, or you can late-bind when methods is accessed.

0

I think you missunderstood prototypes in javascript.

You do not have objects with prototypes you have functions/constructors with prototypes which you use to create objects/instances from.

You are defining a constructor and then you create an instance from that so you can not use it as a function. If you want a function with properties do it like that:

var newObj = function () {
    // do the funciton logic here
};

newObj.property1 = 'value'; // define the properties you need.

Now you have a function which you can use LIKE an object, but keep in mind that it is just a function and if you create instances from it those will not hold the defined properties.

DavidVollmers
  • 677
  • 5
  • 17