1

While playing around with a simple Javascript Object Initializer example, I could not find an explanation while the following code:

const obj = {
  self: this
};

console.log(obj);

would lead an Error: Maximum call stack size exceeded?

Meanwhile, a slightly different but may look similar initializer block as follows:

const obj = {
  self: obj
};

console.log(obj);

would lead an Error: Cannot access uninitialized variable. while the following example using method initializers works perfectly fine:

const obj = {
  name: 'Bob',
  a() {
    return obj.name;
  },
  b() {
    return this.name;
  },
};

console.log(obj.a());
console.log(obj.b());

Can you elaborate on the object initialization process and why the language allows the under initialization object and its this references usage inside method initializers and not in property values?

pilchard
  • 12,414
  • 5
  • 11
  • 23
tmarwen
  • 15,750
  • 5
  • 43
  • 62
  • First doesn't throw for me, and also `this` doesn't equal to `obj`, which you probably intended. Second you just use the variable before it's declaration finished, which isn't allowed. – ASDFGerte Sep 28 '21 at 10:52
  • 1
    You're only declaring the functions, not calling them, so it doesn't throw. where as your second example is directly trying to access the `obj` before the variable is fully initialized. – pilchard Sep 28 '21 at 10:53
  • 2
    #1 would not lead to any errors, rather to an unexpected value only, see https://stackoverflow.com/questions/4616202/self-references-in-object-literals-initializers . You can create circular references in JS. Objects are stored in the memory, and only you get in JS is a reference, you can do even `const arr = []; arr[0] = arr;` without any issues. – Teemu Sep 28 '21 at 10:55
  • @Teemu are you sure global `this` is undefined behavior? I've always seen `this === globalThis` – Newbie Sep 28 '21 at 11:30
  • 1
    @Newbie I didn't say global `this` is undefined, I said it could be unexpected value, when you expect it to refer to `obj` (in OP's example). – Teemu Sep 28 '21 at 11:32
  • @ASDFGerte indeed it throws in some context but not in others. Meanwhile I have no intention of having `self` refer to `obj` but simply experimenting with language semantics. @pilchard this is also my obvious understanding. But I wanted more elaborate explanation in regards of the language design. @Teemu thanks for the extra hint. I have already gone through the whole mentioned post answers which kinda cover part of the answers / explanations I am looking for. – tmarwen Sep 28 '21 at 11:42

1 Answers1

1

Case 1 this === global

Here this is the global javascript context. Typically is huge and contains many circular references. When you console.log() an object with circular references the outcome depends on the implementation (it does not throw an error on Chrome 93.0.4577.63).

console.log({ self: this });

See what is globalThis.

See how to print a circular reference.

Case 2 obj is undefined

This is invalid syntax. First the expression { self: obj } will be evaluated, then the assignment will be performed. But when the expression is evaluated obj does not exist hence leads to Error: Cannot access uninitialized variable..

const obj = { self: obj };

This will do what you expect:

const obj = {};
obj.self = obj;

Case 3

The last example is not related to the other examples at all.

  • You never create a circular reference nor attempt to log one.
  • You access obj from a() at a deferred time, so const obj = has already been performed.
const obj = {
    name: 'Bob',
    a() {
        // This is executed only when calling `a()`
        return obj.name;
    },
    b() {
        // `this` here is not the global context bu `obj`
        return this.name;
    },
};

// Both functions returns a string, so no circular dependency here 
console.log(obj.a());
console.log(obj.b());

This function will lead to the errors you see above:

const obj = {
    a() {
        obj.self = notExisting;
        return obj;
    },
    b() {
        this.self = this;
        return this;
    },
};
Newbie
  • 4,462
  • 11
  • 23