By kpozin


2011-01-06 14:53:53 8 Comments

Is there any way to get something like the following to work in JavaScript?

var foo = {
    a: 5,
    b: 6,
    c: this.a + this.b  // Doesn't work
};

In the current form, this code obviously throws a reference error since this doesn't refer to foo. But is there any way to have values in an object literal's properties depend on other properties declared earlier?

22 comments

@alex-e-leon 2019-04-27 08:56:59

If you want to use native JS, the other answers provide good solutions.

But if you'd prefer to write self-referencing objects like:

{ 
  a: ...,
  b: "${this.a + this.a}",
}

I wrote an npm library called self-referenced-object that supports that syntax and returns a native object.

@Quentin 2019-05-14 13:51:40

Please avoid link only answers. Answers that are "barely more than a link to an external site” may be deleted.

@alex-e-leon 2019-05-15 14:26:54

@Quentin do you have any suggestions on how I can improve my answer? The other answers to this question cover how you might be able to write self-referencing objects in native javascript, but if you want to write self-referencing objects with a syntax similar to the syntax in the posters original question I think that the library that I wrote may be useful to others looking for a solution. Happy to get some feedback.

@c-chavez 2018-08-28 20:37:00

A different approach, to keep things a bit simpler and not define new functions in the object, is to keep the original object with its properties, create a second object with the dynamic properties that use the first object's properties and then merge using spread.

So:

Object

var foo = {
    a: 5,
    b: 6,
};

Object 2

var foo2 = {
    c: foo.a + foo.b
};

Merge

Object.assign(foo, foo2);

or

foo = {...foo, ...foo2};

Result of foo:

{ 
  "a":5,
  "b":6,
  "c":11
}

All within the same js, no new functions within the object, only using assign or spread.

@Dheeraj Bhaskar 2018-06-19 13:33:36

Note: This solution uses Typescript (you can use the vanilla JS which TS compiles to if needed)

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

    // this method is just to check/test this solution 
    check(){
        console.log(this.def.qwe);
    }
}

// these two lines are just to check
let instance = new asd();
instance.check();

Here were using class expressions to get the nested object literal interface we'd want. This is the next best thing IMHO to being able to reference the properties of an object during creation.

Main thing to note is while using this solution, you have exact same interface as you'd have had from an object literal. And the syntax is pretty close to an object literal itself (vs using a function, etc).

Compare the following

Solution I've proposed

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

Solution if object literals would've sufficed

var asd = {
    def : {
        ads:'asd',
        qwe: this.ads + '123';, //ILLEGAL CODE; just to show ideal scenario
    }
}

Another example

Here in this class, you can combine multiple relative path among themselves, which is not possible with an object literal.

class CONSTANT {
    static readonly PATH = new class {
        /** private visibility because these relative paths don't make sense for direct access, they're only useful to path class
         *
         */
        private readonly RELATIVE = new class {
            readonly AFTER_EFFECTS_TEMPLATE_BINARY_VERSION: fs.PathLike = '\\assets\\aep-template\\src\\video-template.aep';
            readonly AFTER_EFFECTS_TEMPLATE_XML_VERSION: fs.PathLike = '\\assets\\aep-template\\intermediates\\video-template.aepx';
            readonly RELATIVE_PATH_TO_AFTER_EFFECTS: fs.PathLike = '\\Adobe\\Adobe After Effects CC 2018\\Support Files\\AfterFX.exe';
            readonly OUTPUT_DIRECTORY_NAME: fs.PathLike = '\\output';
            readonly INPUT_DIRECTORY_NAME: fs.PathLike = '\\input';
            readonly ASSETS_DIRECTORY_NAME: fs.PathLike = '\\assets';
        };
    }
}

@Manngo 2018-07-08 00:44:03

Could it be because your answer is totally irrelevant? I agree that downvoters should explain, but your answer clear has nothing to do with the question …

@Dheeraj Bhaskar 2018-07-09 07:18:11

@Manngo thanks for pointing it out. Honestly, I'd the same question as OP and I use solution I've suggested. Unsure, why it's being considered irrelevant. If you do have the time, please explain so I can make the answer better or at least know where I'm wrong. I'm unfortunately, not understanding why this is not a reasonable solution.

@UDrake 2018-06-12 23:16:56

Here's a neat ES6 way:

var foo = (o => ({
    ...o,
    c: o.a + o.b
  }))({
    a: 5,
    b: 6
  });
  
console.log(foo);

I use it to do something like this:

const constants = Object.freeze(
  (_ => ({
    ..._,
    flag_data: {
      [_.a_flag]: 'foo',
      [_.b_flag]: 'bar',
      [_.c_flag]: 'oof'
    }
  }))({
    a_flag: 5,
    b_flag: 6,
    c_flag: 7,
  })
);

console.log(constants.flag_data[constants.b_flag]);

@Snekse 2018-02-13 19:14:40

Throwing in an option since I didn't see this exact scenario covered. If you don't want c updated when a or b update, then an ES6 IIFE works well.

var foo = ((a,b) => ({
    a,
    b,
    c: a + b
}))(a,b);

For my needs, I have an object that relates to an array which will end up being used in a loop, so I only want to calculate some common setup once, so this is what I have:

  let processingState = ((indexOfSelectedTier) => ({
      selectedTier,
      indexOfSelectedTier,
      hasUpperTierSelection: tiers.slice(0,indexOfSelectedTier)
                             .some(t => pendingSelectedFiltersState[t.name]),
  }))(tiers.indexOf(selectedTier));

Since I need to set a property for indexOfSelectedTier and I need to use that value when setting the hasUpperTierSelection property, I calculate that value first and pass it in as a param to the IIFE

@Indiana 2016-06-17 01:23:37

I use the following code as alternative, and it works. And the variable can be array too. (@ Fausto R.)

var foo = {
  a: 5,
  b: 6,
  c: function() {
    return this.a + this.b;
  },

  d: [10,20,30],
  e: function(x) {
    this.d.push(x);
    return this.d;
  }
};
foo.c(); // 11
foo.e(40); // foo.d = [10,20,30,40]

@animaacija 2015-08-11 00:00:42

just for the sake of thought - place object's properties out of a timeline:

var foo = {
    a: function(){return 5}(),
    b: function(){return 6}(),
    c: function(){return this.a + this.b}
}

console.log(foo.c())

there are better answers above too. This is how I modified example code you questioned with.

UPDATE:

var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);

@user993683 2016-12-06 05:42:33

In ES6 you can make this general approach much more elegant: var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} } so now you can just do foo.c instead of foo.c() :) (Feel free to paste that into your answer so formatting is better!)

@Gaurav 2016-11-21 18:47:22

How about this solution this will work with nested objects with array as well

      Object.prototype.assignOwnProVal
     = function (to,from){ 
            function compose(obj,string){ 
                var parts = string.split('.'); 
                var newObj = obj[parts[0]]; 
                if(parts[1]){ 
                    parts.splice(0,1);
                    var newString = parts.join('.'); 
                    return compose(newObj,newString); 
                } 
                return newObj; 
            } 
            this[to] = compose(this,from);
     } 
     var obj = { name : 'Gaurav', temp : 
                  {id : [10,20], city:
                        {street:'Brunswick'}} } 
     obj.assignOwnProVal('street','temp.city.street'); 
     obj.assignOwnProVal('myid','temp.id.1');

@voscausa 2016-11-08 23:43:06

Now in ES6 you can create lazy cached properties. On first use the property evaluates once to become a normal static property. Result: The second time the math function overhead is skipped.

The magic is in the getter.

const foo = {
    a: 5,
    b: 6,
    get c() {
        delete this.c;
        return this.c = this.a + this.b
    }
};

In the arrow getter this picks up the surrounding lexical scope.

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  

@Aluan Haddad 2017-04-18 01:56:45

es5 also has properties you just need to use Object.defineProperty(foo, 'c', {get:function() {...}}) to define them. This is easily done in an unobtrusive way in a factory such as this one. Of course if you can use the get sugar it is more readable but the capability has been there.

@daviestar 2016-08-13 15:40:36

if your object is written as a function which returns an object, AND you use ES6 object-attribute 'methods', then it's possible:

const module = (state) => ({
  a: 1,
  oneThing() {
    state.b = state.b + this.a
  },
  anotherThing() {
    this.oneThing();
    state.c = state.b + this.a
  },
});

const store = {b: 10};
const root = module(store);

root.oneThing();
console.log(store);

root.anotherThing();
console.log(store);

console.log(root, Object.keys(root), root.prototype);

@monzonj 2016-03-28 12:41:11

For completion, in ES6 we've got classes (supported at the time of writing this only by latest browsers, but available in Babel, TypeScript and other transpilers)

class Foo {
  constructor(){
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
  }  
}

const foo = new Foo();

@user3606367 2014-05-07 10:15:56

The key to all this is SCOPE.

You need to encapsulate the "parent" (parent object) of the property you want to define as it's own instantiated object, and then you can make references to sibling properties using the key word this

It's very, very important to remember that if you refer to this without first so doing, then this will refer to the outer scope... which will be the window object.

var x = 9   //this is really window.x
var bar = {
  x: 1,
  y: 2,
  foo: new function(){
    this.a = 5, //assign value
    this.b = 6,
    this.c = this.a + this.b;  // 11
  },
  z: this.x   // 9 (not 1 as you might expect, b/c *this* refers `window` object)
};

@user663031 2014-09-06 17:19:17

This is not even valid JS.

@Bergi 2015-08-01 19:27:45

@T.J. Crowder 2012-05-26 12:11:31

The obvious, simple answer is missing, so for completeness:

But is there any way to have values in an object literal's properties depend on other properties declared earlier?

No. All of the solutions here defer it until after the object is created (in various ways) and then assign the third property. The simplest way is to just do this:

var foo = {
    a: 5,
    b: 6
};
foo.c = foo.a + foo.b;

All others are just more indirect ways to do the same thing. (Felix's is particularly clever, but requires creating and destroying a temporary function, adding complexity; and either leaves an extra property on the object or [if you delete that property] impacts the performance of subsequent property accesses on that object.)

If you need it to all be within one expression, you can do that without the temporary property:

var foo = function(o) {
    o.c = o.a + o.b;
    return o;
}({a: 5, b: 6});

Or of course, if you need to do this more than once:

function buildFoo(a, b) {
    var o = {a: a, b: b};
    o.c = o.a + o.b;
    return o;
}

then where you need to use it:

var foo = buildFoo(5, 6);

@David Kennell 2018-05-05 01:27:39

For my own sanity, I'm trying to find some kinda of official documentation that says basically the same thing - that an object's this is only available to methods of said object, and no other kinds of properties. Any idea where I could find that? Thanks!

@T.J. Crowder 2018-05-05 09:24:58

@DavidKennell: Doesn't get more official than the specification. :-) You'd probably start here and follow it through. It's fairly awkard language, but basically you'll see in the various subclauses of Property Definition Evaluation that the object isn't available to the operations determining the values of property initializers.

@slicedtoad 2015-03-24 21:06:12

The other answers posted here are better but here's an alternative that:

  • Sets the value at initialization (not a getter, or derived, etc)
  • Doesn't require any type of init() or code outside of the object literal
  • Is an object literal and not a factory function or other object creation mechanic.
  • Shouldn't have any performance impact (except at initialization)

Self-executing anonymous functions and window storage

var foo = {
    bar:(function(){
        window.temp = "qwert";
        return window.temp;
    })(),
    baz: window.temp
};

The order is guaranteed (bar before baz).

It pollutes window of course, but I can't imagine someone writing a script that requires window.temp to be persistent. Maybe tempMyApp if you're paranoid.

It's also ugly but occasionally useful. An example is when you are using an API with rigid initialization conditions and don't feel like refactoring so the scoping is correct.

And it's dry, of course.

@Rick O'Shea 2014-09-13 21:36:40

Creating new function on your object literal and invoking a constructor seems a radical departure from the original problem, and it's unnecessary.

You cannot reference a sibling property during object literal initialization.

var x = { a: 1, b: 2, c: a + b } // not defined 
var y = { a: 1, b: 2, c: y.a + y.b } // not defined 

The simplest solution for computed properties follows (no heap, no functions, no constructor):

var x = { a: 1, b: 2 };

x.c = x.a + x.b; // apply computed property

@Henry Wrightson 2013-07-02 09:04:12

Some closure should deal with this;

var foo = function() {
    var a = 5;
    var b = 6;
    var c = a + b;

    return {
        a: a,
        b: b,
        c: c
    }
}();

All the variables declared within foo are private to foo, as you would expect with any function declaration and because they are all in scope, they all have access to each other without needing to refer to this, just as you would expect with a function. The difference is that this function returns an object that exposes the private variables and assigns that object to foo. In the end, you return just the interface you want to expose as an object with the return {} statement.

The function is then executed at the end with the () which causes the entire foo object to be evaluated, all the variables within instantiated and the return object added as properties of foo().

@user663031 2014-09-06 17:17:52

It is confusing and misleading to call this a "closure". Although opinions differ on the precise meaning returning an ojbect value from a function does not constitute a closure in anyone's book.

@davedambonite 2013-05-24 22:25:16

You could do it like this

var a, b
var foo = {
    a: a = 5,
    b: b = 6,
    c: a + b
}

That method has proven useful to me when I had to refer to the object that a function was originally declared on. The following is a minimal example of how I used it:

function createMyObject() {
    var count = 0, self
    return {
        a: self = {
            log: function() {
                console.log(count++)
                return self
            }
        }
    }
}

By defining self as the object that contains the print function you allow the function to refer to that object. This means you will not have to 'bind' the print function to an object if you need to pass it somewhere else.

If you would, instead, use this as illustrated below

function createMyObject() {
    var count = 0
    return {
        a: {
            log: function() {
                console.log(count++)
                return this
            }
        }
    }
}

Then the following code will log 0, 1, 2 and then give an error

var o = createMyObject()
var log = o.a.log
o.a.log().log() // this refers to the o.a object so the chaining works
log().log() // this refers to the window object so the chaining fails!

By using the self method you guarantee that print will always return the same object regardless of the context in which the function is ran. The code above will run just fine and log 0, 1, 2 and 3 when using the self version of createMyObject().

@user663031 2014-09-06 17:18:45

Good examples, except you've left out all the semicolons.

@Kerem Baydoğan 2017-01-16 19:44:49

No semicolons – It's fine Really!

@zzzzBov 2013-04-11 22:32:13

Simply instantiate an anonymous function:

var foo = new function () {
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
};

@Bergi 2015-08-01 16:11:07

@zzzzBov 2015-08-01 16:54:16

@Bergi, why? Because someone might instantiate another of the same object from it? It's not like they can't just clone an object literal. It's no different than passing an argument like new Point(x, y) except that the function isn't named for reuse.

@Bergi 2015-08-01 18:16:34

@zzzzBov: Of course they can just clone the object, but compared to an IEFE solution (like in TJCrowder's answer) your solution leaks the constructor function and creates a superfluous prototype object.

@zzzzBov 2015-08-01 19:09:09

@Bergi, sure, but this is significantly more expressive.

@Bergi 2015-08-01 19:13:07

@zzzzBov: Just use var foo = function() { this.…; return this; }.call({}); which is syntactically not much different but semantically sane.

@zzzzBov 2015-08-01 19:22:44

@Bergi, if you feel it's that important, why not add your own answer to the mix?

@Bergi 2015-08-01 19:27:31

@zzzzBov I think it's just a variation of TJ's answer

@Mephiztopheles 2015-12-07 08:49:19

not a bad idea!

@Randy 2016-03-11 14:24:07

This certainly is a bad idea. If you would know how the this keyword gets bound, you would see that if you call foo from say the global scope, this wont work in strict mode because the this keyword is undefined. Next to that, if you dont work in strict mode, the global scope now has the a, b and c variable in its scope. That may cause serious side effects.

@zzzzBov 2016-03-11 14:55:15

@randy, you've apparently missed that the new keyword was used to instantiate the function as an instance. foo will be an object after the assignment, not a function. Please re-evaluate your comment and vote.

@Randy 2016-03-11 14:58:12

You've got this. I indeed did not notice the new keyword.

@Rafael Rocha 2013-01-08 00:21:05

You can do it using the module pattern. Just like:

var foo = function() {
  var that = {};

  that.a = 7;
  that.b = 6;

  that.c = function() {
    return that.a + that.b;
  }

  return that;
};
var fooObject = foo();
fooObject.c(); //13

With this pattern you can instantiate several foo objects according to your need.

http://jsfiddle.net/jPNxY/1/

@Hollister 2013-12-26 01:24:42

This isn't an example of the module pattern, just a function. If the last line of the foo definition was }();, it would self execute and return an object, not a function. Also, foo.c is a function, so writing to it clobbers that function and the next invocation via fooObject.c() will fail. Maybe this fiddle is closer to what you're going for (it's also a singleton, not designed to be instantiated).

@Rafael Rocha 2014-01-16 19:48:44

"The Module pattern was originally defined as a way to provide both private and public encapsulation for classes in conventional software engineering". From: Learning JavaScript Design Patterns. That's object follow the module pattern described above but maybe it isn't the best one to explain that because is not showing public and private properties/methods. This one jsfiddle.net/9nnR5/2 is the same object with public and private properties/methods. So both of them are following this pattern

@ken 2011-01-06 18:55:45

There are several ways to accomplish this; this is what I would use:

function Obj() {
 this.a = 5;
 this.b = this.a + 1;
 // return this; // commented out because this happens automatically
}

var o = new Obj();
o.b; // === 6

@kpozin 2011-01-15 17:01:45

This works, but eliminates the advantages of the object literal notation.

@ken 2011-01-16 00:16:21

True, sorry I missed the object-literal tag originally. I mostly only use object literals for data structures, and anytime I want any additional logic (which might resemble a class) I create the object as the result of a function for this very reason.

@Felix Kling 2011-01-06 14:59:53

You could do something like:

var foo = {
   a: 5,
   b: 6,
   init: function() {
       this.c = this.a + this.b;
       return this;
   }
}.init();

This would be some kind of one time initialization of the object.

Note that you are actually assigning the return value of init() to foo, therefore you have to return this.

@Billy Moon 2011-07-26 01:12:36

you can also delete this.init before return this so that foo is not poluted

@T.J. Crowder 2014-05-19 07:30:37

@BillyMoon: Yes indeed, although doing so impacts performance of all subsequent property accesses on that object, on many engines (V8, for instance).

@Muhammad Umer 2015-06-01 03:01:59

this in ES6 classes works as expected. So no need to call init there.

@Felix Kling 2015-06-01 03:02:53

@MuhammadUmer: Not sure how ES6 classes are relevant to the question.

@Muhammad Umer 2015-06-01 03:20:26

it shows another way to solve problem that wasn't available.

@Felix Kling 2015-06-01 03:45:01

@MuhammadUmer: classes are just syntactic sugar for constructor functions, so they don't really provide anything new. Either way, the main focus of this question are object literals.

@akantoword 2016-07-26 00:56:17

why do you have to return this at the end?

@Felix Kling 2016-07-26 05:16:17

@akantoword: I'm assigning the return value of init to foo, so I have to return the object itself.

@akantoword 2016-07-26 17:18:13

@FelixKling but why do you have to return something though, even if you don't have that return statement, shouldn't the init function do it's job of creating 'c'? why does it have to have the return statement to work?

@Felix Kling 2016-07-26 18:05:10

@akantoword: Remove the return statements and try it. Of course c is created, but because init doesn't return anything, foo will be undefined, so there is no way to use / access the object afterwards. Again: The return value of init is assigned to foo.

@akantoword 2016-07-26 18:58:18

@FelixKling why is the return value of init assigned to foo? sorry if this is off topic, but it doesn't make sense to me that init has to return something because it's purpose is to create c. to me, init is just another property of foo, so when foo is defined with the object literal, it shouldn't be dependent on init to return itself. I'm pretty sure I'm missing something very basic here, but I don't know what.

@Felix Kling 2016-07-26 19:41:39

@akantoword: In the last line, init is called immediately. If we omit what's inside the object literal, it would look like var foo = { ... }.init();. Is it clearer now why the return value of init is assigned to foo? We could also do this in multiple statements, then init wouldn't have to return anything: var foo = { ... }; foo.init();.

@akantoword 2016-07-26 19:48:34

@FelixKling that made it much more clear, thank you! I didn't know it'd make a difference with 2 statements vs 1.

@Felix Kling 2016-07-26 19:51:11

@akantoword: Great :) since object literals are a single expression, the init() call was directly appended the literal to keep it a single expression. But of course you can call the function separately of you want to.

@tambre 2018-03-18 16:44:58

@T.J.Crowder Performance impact is gone since Chrome 60.

@T.J. Crowder 2018-03-18 17:07:02

@tambre: Interesting. But of course, that's just V8, not other engines.

@CMS 2011-01-06 14:58:54

Well, the only thing that I can tell you about are getters:

var foo = {
  a: 5,
  b: 6,
  get c () {
    return this.a + this.b;
  }
};

foo.c; // 11

This is a syntactic extension introduced by the ECMAScript 5th Edition Specification, the syntax is supported by most modern browsers (including IE9).

@jake 2013-02-02 16:21:21

Very helpful answer. More info on 'get' can be found here: developer.mozilla.org/en-US/docs/JavaScript/Reference/Operat‌​ors/…

@Fausto R. 2013-11-04 14:51:25

it doesn't work if a is an array

@Charlie Martin 2014-09-19 19:04:59

@FaustoR. Yes it does.

@HBP 2015-05-02 06:21:46

Beware that with this solution if the values of foo.a or foo.b are changed then the value of foo.c will also change in synchronism. This may or may not be what is required.

@Randy 2016-03-11 14:28:33

@HBP That would be the exact same thing as what would happen in the question, so it seems to me like that is exactly what the expected result had to be.

@Andrew 2016-05-26 14:49:25

beautiful... as mentioned, if you are looking for dynamic property, this is the answer, otherwise the current top answer or similar might be for you.

@Yuval A. 2016-07-03 12:49:22

Does the "function" c actually gets executed each time foo.c is dereferenced?

@AVProgrammer 2016-08-23 18:17:56

This looks functionally equivalent to: ... c: function() { return this.a + this.b; } ... foo.c(), any gotchas with this assumption?

@aug 2016-09-07 23:40:21

FYI getter functions do not allow parameters I believe -- does not apply to this case but I think that's one difference to be noted.

@Radex 2017-05-02 18:30:26

do you think it is possible to "imitate" getter features in es3? maybe a polify?

@Tomanow 2017-06-15 14:53:13

Does this "syntactic extension" have a name? If not, can I name it something awesome?

@CMCDragonkai 2017-11-20 05:01:17

Also wanted to mention that if you assign the getter prop to another object, the result is evaluated, so you're not moving a function, where the this binding can be lost, but also means you're not moving the "getter", you're evaluating the getter and then copying the result.

@Z. Khullah 2018-04-18 20:22:20

Note that this binds to the deepest nested object. E.g.: ... x: { get c () { /*this is x, not foo*/ } } ...

@Z. Khullah 2018-04-19 20:11:27

To complete my above statement, since foo is beeing declared as a variable and c will only be evaluated at the time it is invoked, using foo inside c will work, as opposed to this (be careful though)

@CertainPerformance 2018-12-06 09:56:28

If one wanted further optimization, one could also assign the c property in the getter, so that it's only calculated once, rather than on every access of .c.

Related Questions

Sponsored Content

38 Answered Questions

[SOLVED] How do I remove a property from a JavaScript object?

71 Answered Questions

[SOLVED] What is the most efficient way to deep clone an object in JavaScript?

62 Answered Questions

[SOLVED] How do I correctly clone a JavaScript object?

36 Answered Questions

[SOLVED] Length of a JavaScript object

19 Answered Questions

[SOLVED] Checking if a key exists in a JavaScript object?

44 Answered Questions

[SOLVED] How to check if an object is an array?

46 Answered Questions

41 Answered Questions

[SOLVED] Detecting an undefined object property

26 Answered Questions

[SOLVED] Storing Objects in HTML5 localStorage

23 Answered Questions

[SOLVED] How can I add a key/value pair to a JavaScript object?

Sponsored Content