3

Sorry, I don´t know the name of this.

I want to have a function and an object with properties in only one variable.

Here is how it works:

var obj = function() {
    return "foo";
};

obj.prop = "bar";

obj(); // => "foo"
obj.prop; // => "bar"

This works fine, but I would like to change the order of this:

var obj = { prop: "bar" };
obj = function() {
    return "foo";
};

obj(); // => "foo"
obj.prop; // => undefined

Is there a way to do this?

I want do do this because I have a lot of properties to add to the object:

var obj = function() {
    return "foo";
};

obj.prop1 = "bar1";
obj.prop2 = "bar2";
obj.prop3 = "bar3";
obj.prop4 = "bar4";
obj.prop5 = "bar5";
obj.prop6 = "bar6";
obj.prop7 = "bar7";
//...
Martin
  • 1,283
  • 2
  • 14
  • 28

3 Answers3

6

This isn't possible because when you do:

obj = function() {
    return "foo";
};

...you're assigning the variable obj to the new function, so it no longer points to the original object you created ({ prop: "bar" }) at all.

So if you want to add properties to a function object, you must always create the function first, then add properties.

As an alternative, you could do something like this:

var props = {
    prop1: "bar1",
    prop2: "bar2"
};

var obj = function() {
    return "foo";
};

for (var key in props) {
    obj[key] = props[key];  
}

Or if you happen to have jQuery available (and don't have Object.assign available):

jQuery.extend(obj, props);

(Of course there are shims available for Object.assign, which would allow @Pointy's answer to work in older browsers.)

Matt Browne
  • 12,169
  • 4
  • 59
  • 75
  • In your loop, you should check that `props.hasOwnProperty(key)` http://stackoverflow.com/a/921808/1913729 – blex Sep 04 '15 at 18:26
  • Yes, this would work with little code. I will accept this answer, If there are no better solutions (performance). – Martin Sep 04 '15 at 18:27
  • 1
    @blex I don't think that's necessary in this case...the OP says nothing to indicate that the `props` object would be an instance of some prototype (i.e. that it would have inherited enumerable properties). – Matt Browne Sep 04 '15 at 18:29
  • 2
    @Martin Thanks...I could be wrong, but I don't see how you could make it perform better than this, unless the native implementation of `Object.assign` (available in newer browsers) has some internal performance optimization...in any case I wouldn't worry about it - better to be concerned about performance differences that are actually significant than little things like looping over a few dozen properties... – Matt Browne Sep 04 '15 at 18:32
5

If you want to do this with one statement, ES2015 (and some libraries) let you do:

var obj = Object.assign(
  function() { /* ... */ },
  { "hello": "world" }
);

Which will give you obj as a function with the property "hello". Note that this is really just the same thing as the separate assignment, but it's all wrapped up as one overall expression, which is nice because it means you can do something like

return Object.assign(function() { /* whatever */ }, {
  prop: whatever,
  // ...
});
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Yes, this would work, but I need a solution which also works in IE8 – Martin Sep 04 '15 at 18:22
  • I agree with @torazaburo...either his answer or mine should serve you equally well. The performance differences are insignificant. Avoid premature optimization. – Matt Browne Sep 04 '15 at 18:33
  • @MattBrowne Right. Wasn't my answer but whatever. –  Sep 04 '15 at 18:34
0

I also agree with Grundy, but you could do something like that:

var x = function(){
var obj = {};
  return {
    objToReturn: obj,
    objFunction: function(){return 'foo';},
    addItemsToObject: function (key, value) {
      obj[decodeURIComponent(key)] = value;
    }
   }
};    

I honestly don't know if that's what you really want, but in that case you can execute the "x" function and after you can access the "objFunction", the "objToReturn" or the "addItemsToObject" function.

So it will be something like that:

var y = x();

for (propertie in yourProperties){      
  y.addItemsToObject
    (propertie, yourProperties[decodeURIComponent(propertie)]);
}

And then:

y.objFunction();

'foo'

Hope that helps.