4

I'm wondering if there's a better way to add dynamic methods to an existing object. Basically, I am trying to assemble new methods dynamically and then append them to an existing function.

This demo code works.

builder = function(fn, methods){

    //method builder
    for(p in methods){
        method = 'fn.' + p + '=' + methods[p];
        eval(method);
    }

    return fn;
}
test = {}
test = builder(test, {'one':'function(){ alert("one"); }','two':'function(){ alert("two"); }'} );

test.one();
test.two();
Geuis
  • 41,122
  • 56
  • 157
  • 219

5 Answers5

23

You don't need to eval them each time.

You can create existing function objects, then assign them as properties to your objects.

var methods = {
  'increment': function() { this.value++; },
  'display' : function() { alert(this.value); }
};

function addMethods(object, methods) {
  for (var name in methods) {
    object[name] = methods[name];
  }
};

var obj = { value: 3 };
addMethods(obj, methods);
obj.display();  // "3"
obj.increment();
obj.display();  // "4"

The canonical, object-oriented way however, is to use constructors and prototypes, but this isn't really dynamic in that each object you construct will have the same methods:

function MyObj(value) {
  this.value = value;
};
MyObj.prototype.increment = function() {
  this.value++;
};
MyObj.prototype.display = function() {
  alert(this.value);
}
var obj = new MyObj(3);
obj.display();  // "3"
obj.increment();
obj.display();  // "4"
thomaux
  • 19,133
  • 10
  • 76
  • 103
levik
  • 114,835
  • 27
  • 73
  • 90
10

mhmh - I may be a bit late, but anyway:

new Function(argName1,...,argNameN, body)

for example:

x = new Function("y","return y*5");
x(3)

not much better than eval, though. (it's a pity, but strings are used as code-description, not something more structured as in LISP)

blabla999
  • 3,130
  • 22
  • 24
5

If you need an object dynamically based on specific types... For instance:

var logTypes = ["fatal", "error", "warning", "info", "trace", "debug", "profile"];

Then you can keep a reference of the "this" object output and use it inside the methods.

function CustomLogger () {

   var outter = this;

   // creating the logger methods for all the log types and levels
   _.each(logTypes, function (logType) {
        outter[logType] = function (msg) {
           console.log("[%s] %s", logType, msg);
        };
   });
}

That way, you can get the new dynamic methods...

var logger = new CustomLogger();
logger.info("Super cool!");

This will output the following:

"[info] Super cool!"
Marcello DeSales
  • 21,361
  • 14
  • 77
  • 80
1

Your example could be accomplished without strings:

builder = function(fn, methods){

        //method builder
        for(p in methods){
                fn[p] = methods[p];
        }

        return fn;
}
test = {}
test = builder(test, {'one': function(){ alert("one"); },'two':function(){ alert("two"); }} );

test.one();
test.two();

I'm not sure how you are assembling these methods, but avoid using strings if you can. There is probably a better way.

Zach
  • 24,496
  • 9
  • 43
  • 50
0

Do you have to build the methods from a string? If not there are plenty of ways including adding the methods to an object prototype or the object definition directly. Most of all the common javascript libraries have methods for defining objects/methods on existing or creating "namespaces". Check out YUI/Prototype/jQuery etc for examples of how they implement.

Otherwise if you have to build from a string then evaling may be the best method for dynamically adding methods to an object definition.

Quintin Robinson
  • 81,193
  • 14
  • 123
  • 132