Hydrothermal
Hydrothermal

Reputation: 5081

Is it safe/acceptable to attach properties to function objects?

Let's say I have a function.

function foo() {
    var bar = true;
    if(bar) {
        //Do x
    }
}

In this example, bar is some condition, like a regular expression. I would like it to be globally accessible, so I can change the condition and run foo() again. I could do this by making it a global variable:

var bar = true;

function foo() {
    if(bar) {
        //Do x
    }
}

foo();
bar = false;
foo();

or an argument to the function:

function foo(bar) {
    if(bar) {
        //Do x
    }
}

foo(true);
foo(false);

or even a separate global object:

var foo_options = {
    bar: true
};

function foo() {
    if(foo_options.bar) {
        //Do x
    }
}

foo();
foo_options.bar = false;
foo();

I would like to avoid creating a single global variable to hold the condition, because it seems unnecessarily clutter-inducing to have a global variable (even if it's well-named) to hold something that is really only used in one place. I don't want to have to pass the condition as an argument, because this function is going to be called many times and I might not actually be able to control the arguments that the function is called with. A global object seems unnecessary for similar reasons to a global variable, but it's also very clunky.

I am currently considering giving the foo() function a property, which is possible because of how JavaScript treats functions (and almost everything else that isn't a string or number) as objects:

function foo() {
    if(foo.bar) {
        //Do x
    }
}
foo.bar = true;

foo();
foo.bar = false;
foo();

I've tested this and it's possible, but I am concerned about whether or not it's a good idea or dangerous in any way. Advice?

Upvotes: 1

Views: 63

Answers (3)

nepeo
nepeo

Reputation: 509

You could bind the function and the variable to a single object? Safer and doesn't modify the default object.

var myObject = {
    foo : 1234,
    bar : function(){
        console.log(this.foo)
    }

}

myObject.bar();

Upvotes: 1

gkunz
gkunz

Reputation: 1423

For this problem a function factory is probably the easiest and most meaningful solution like already suggested. A different solution, if you prefer to have a "singleton" rather than a function factory which creates new functions every time you want to change your options, would be to use a closure with an "interface object" that you return:

var Foo = (function() {
  var bar = true;

  function foo() {
    if(bar) {
      //Do x
    }
  }

  return {
    setBar: function(b) {
      bar = b;
    },
    getBar: function() {
      return bar;
    },
    foo: foo
  };
}());

Foo.setBar(false);
Foo.foo();

Upvotes: 0

Denys Séguret
Denys Séguret

Reputation: 382170

Adding properties to default objects is often frown upon but, provided you don't replace standard properties (for example length), you should be fine.

A cleaner solution is to use a closure to store your variable, using a function factory :

function makeFoo(foo_options){
    return function(){
      console.log("bar : ", foo_options.bar);
    }
}
var foo1 = makeFoo({bar:3}),
    foo2 = makeFoo({bar:0});
foo1(); // logs bar : 3
foo2(); // logs bar : 0

The added benefit is that you can simply have several functions with different options.

Upvotes: 2

Related Questions