8

Possible Duplicate:
Self-references in object literal declarations

I have an object literal which is used as a configuration element and is looked up for keys.

customRendering:{
                  key1: func(){....},
                  key2: func(){....}
}

I have a situation where key2 and key3 can use the same function. Is there a way to assign the same function to both key2 and key3 without having to declare the function outside the object literal and without having to declare an extra key?

I was hoping I could do something like:

key2: key3: func(){....}
Community
  • 1
  • 1
ChrisOdney
  • 6,066
  • 10
  • 38
  • 48
  • key2 and key3 are the same there is no need for having 2 keys – Ibu Nov 17 '11 at 18:18
  • @Ibu, not necessarily, creating an object for a particular interface or API may require having values defined to `key1` and `key2`. – zzzzBov Nov 17 '11 at 18:29
  • 1
    I'm not sure why is this question marked as a duplicate, it is actually not. Declaring properties aliases is not the same as making self-references within object declaration. For aliases there is quite useful util: [split-keys](https://www.npmjs.org/package/split-keys). With that tool you can gracefully declare properties as a list of keys. – dy_ Oct 15 '14 at 09:55

4 Answers4

13

A safe way:

I don't know what I was thinking earlier. If you're fine with using a more verbose "literal" you can instantiate a custom function:

o = new function () {
  this.foo = function () { console.log('works'); };
  this.bar = this.foo;
};

This is a dirty nasty hack:

you could use a temporary variable to store the reference to the function while setting the object. Be careful to use a closure and to call var before using it so that you don't pollute the global namespace:

(function () {
  var o, baz;
  o = {
    foo: baz = function () {console.log('works')},
    bar: baz
  }
  //more code
}());

The reason I'm calling this a dirty nasty hack is that it makes the code less readable, it's harder to tell examining this code (especially if the object literal declaration was longer) where baz was set.

Better to just write the alias outside the object literal so that it's explicitly visible that it is an alias.

Note: the named function format doesn't work:

o = { //THIS WON'T WORK
  foo: function baz() {/* code */},
  bar: baz
}

There's no way within an object literal to define an alias using a shared reference.

You can use an aliasing function, but it wont be an identical reference:

o = {
  foo: function...
  bar: function () { return this.foo() } //even better if you use `apply` or `call`
}

The typical way to share a reference is after the object literal, which sounds like what you wanted to avoid:

o = {
  foo: function...
}
o.bar = o.foo;

Alternatively as you pointed out in your question (and for completeness) you could define the function outside of the object literal:

func = function () {/* code */};
o = {
  foo: func,
  bar: func
}

In response to @Peter about returning an object from a function

Using a self-executing anonymous function is another way of instantiating an object inline, and would make this entire question moot:

o = (function () {
  var o = {
    foo: function () {/*code*/}
  }
  o.bar = o.foo;
  return o;
}());

Or like this:

var o = (function () {
  var shared = function() { console.log("shared") };
  return {
    foo: shared,
    bar: shared
  }
}());
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • 1
    +1 I would definitely use apply or call – locrizak Nov 17 '11 at 18:18
  • I like your first code snippet, although I would probably make the anonymous function return the object itself. This way it becomes very explicit what variable is being set. – Peter Nov 17 '11 at 18:32
  • @Peter, which anonymous function? The wrapping closure is purely for preventing variables from leaking into global scope. – zzzzBov Nov 17 '11 at 18:34
  • @zzzzBov, I meant like this: `var obj = (function() { var baz; return { /*...*/ } })();` – Peter Nov 17 '11 at 18:37
  • @Peter, I've updated my answer to respond to that particular technique of instantiating an object. – zzzzBov Nov 17 '11 at 18:43
  • 1
    @zzzzBov Cool, I like it. Let me just make a couple tweaks, if you don't mind. – Peter Nov 17 '11 at 18:47
1

without having to declare the function outside the object literal

I think this part makes it impossible. However, while I use JavaScript all the time, I am not a professional JS ninja, so perhaps I am wrong.

Code for how I would do this (although it seems you already know you can do this, I thought it might be best to say it anyway):

customRendering = {};
customRendering.key1 = func(){....};
customRendering.key2 = customRendering.key1;
Levi Morrison
  • 19,116
  • 7
  • 65
  • 85
-1

Define the function aside from the object:

var func = function() { ... };
...
  customRendering: {
    key1: func,
    key2: func
  }
Aldo Stracquadanio
  • 6,167
  • 1
  • 23
  • 34
  • -1 Going to quote the question here. "Is there a way to assign the same function to both key2 and key3 without having to declare the function outside the object literal" – zzzzBov Nov 17 '11 at 18:30
-3

Sorry I understood your question incorrectly.

Here is a possible solution:

    var obj = {
      func1: function() {},
      func2: obj.func1
    }
ioseb
  • 16,625
  • 3
  • 33
  • 29
  • It wont work for me. In my case 'obj' is embedded in a self-invocated function and so 'this' doesn't refer to obj. – ChrisOdney Nov 17 '11 at 18:17
  • Sorry, I put this by mistake there. I changed "this" with actual object variable name. – ioseb Nov 17 '11 at 18:19
  • 2
    That code wont work. `obj` will be `undefined` until after the construction using the object literal, meaning that when the object literal is called. `obj.func1` will be trying to call `func1` on `undefined`, which will create an error. – zzzzBov Nov 17 '11 at 18:32