54

I'm trying to do someting like

o = {
  a: { foo: 42 },
  b: o.a
}

But that returns an error saying o is not defined. I know I can later do o.b = o.a. But I'm wondering if it's possible to define b while I'm in defining o.

fent
  • 17,861
  • 15
  • 87
  • 91

5 Answers5

69

This is ancient history now, but I just learned about getters and setters, which are perfect for your situation, and I'm sure people looking at this issue could get some value from it..

o = {
  a: { foo: 42 },
  get b() {
    return this.a
    }
  }

console.log(o.b) // => { foo: 42 }
ignarukih
  • 788
  • 1
  • 5
  • 7
  • 2
    Thanks for adding this – Clifford Fajardo Dec 02 '20 at 21:45
  • If you are using NodeJS you can refer to module.exports.[property]. – HKoncept Sep 06 '21 at 18:00
  • 2
    While this may work in certain scenarios, just like [method leveraging execution context](https://stackoverflow.com/a/6824158/11299053), it has to be used with caution: one might get unexpected results passing such object to standard methods, like `Object.values()` or `JSON.stringify()`. – Yevhen Horbunkov Dec 01 '21 at 10:25
56

As @RobG commented — no, you can't.

You can, however, use the this keyword inside of functions defined as properties of the object, like so:

o = {
  a: { foo: 42 },
  b: function () {
      return this.a;
  }
}

console.log(o.b()); // {foo: 42};
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 1
    you could also make the object a class and the KVs class properties – Dheeraj Bhaskar Jun 19 '18 at 13:13
  • While this may work in certain scenarios, just like [getter-based method](https://stackoverflow.com/a/42437104/11299053), it has to be used with caution: one might get unexpected results passing such object to standard methods, like `Object.values()` or `JSON.stringify()`. – Yevhen Horbunkov Dec 01 '21 at 10:23
17

It is not possible.

The object is not bound in any scope visible to EcmaScript expressions when the property values are evaluated.

Section 11.1.5 of the EcmaScript language spec explains how the object constructor syntax works.

The following describes how the object is created as a side-effect of evaluating the first property key value pair

The production PropertyNameAndValueList : PropertyAssignment is evaluated as follows:

  1. Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name.
  2. Let propId be the result of evaluating PropertyAssignment.
  3. Call the [[DefineOwnProperty]] internal method of obj with arguments propId.name, propId.descriptor, and false.
  4. Return obj.

Note that PropertyAssignment is evaluated after obj is created, but obj is never bound to any name accessible to an EcmaScript expression.

Only after all the property values are evaluated is anything assigned to o or any other symbol in your program.

Community
  • 1
  • 1
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • It is possible, see answers below – Sebastian Hernandez Jul 28 '20 at 14:14
  • @SebastianHernandez I'm not seeing where an answer below show's that it is possible without splitting the object's construction into before-assignment and after-assignment parts which seems at odds with the OP's "I know I can later do o.b = o.a. But I'm wondering if it's possible to define b while I'm in defining o." – Mike Samuel Jul 28 '20 at 16:32
  • 1
    You can use the getter approach for instance, with that approach you can access any property declared in the object, you can even do any operations with it. It might not be a process done stricktly during the object creation, however it works most of the time for the original need of using a value that hasn't yet been defined by the object. – Sebastian Hernandez Jul 28 '20 at 17:37
  • 1
    @SebastianHernandez, but the getter approach isn't the same as what the OP asked for; it creates an unsettable alias. – Mike Samuel Jul 28 '20 at 22:34
4
o = {};
o.a = {foo: 42};
o.b = o.a;
Hello71
  • 766
  • 8
  • 17
1

Yet another way to do it:

(function() {
    var some = { foo: 42 };
    window.o = {
        a: some,
        b: some
    };
})();

alert(o.b.foo);
Jaime
  • 6,736
  • 1
  • 26
  • 42