Search code examples
javascriptprototype-chain

Change nested objects to the same object whose values which are objects are the objects with parents as prototype


Experimenting with an idea. Given an object like:

T = {
  a: 2,
  b: 9,
  c: {
    a: 3,
    d: 6,
    e: {
      f: 12
    }
  }
}

I want to mutate it such that every value that is an object, changes to the same object, with the parent object as prototype.

Meaning I'd like to be able to have the following outputs:

> T.c.b
9
> T.c.e.b
9
> T.c.e.a
3
> T.c.c.c
{a: 3, d: 6, e:[Object]}

I have already created the following functions that work almost as expected:

function chainer(object) {
    for (const key in object) {
        if (object[key] !== null && typeof (object[key]) === 'object') {
            let Constructor = function () {
            };
            Constructor.prototype = object;
            let objectValue = {...object[key]};
            object[key] = new Constructor();
            for (const savedKey in objectValue) {
                object[key][savedKey] = objectValue[savedKey];
            }
        }
    }
}

function chain(object) {
    chainer(object);
    for (const key in object) {
        if (object[key] !== null && typeof (object[key]) === 'object') {
            chainer(object[key]);
        }
    }
}

With the previous example it works as expected. Nevertheless, when I try with the following:

T = {a:4, g:{g:{g:{g:{g:{g:{g:{}}}}}}}}

The following output happens:

> T.a
4
> T.g.a
4
> T.g.g.a
4
> T.g.g.g.a
undefined
> T.g.g.g.g.a
undefined

I find it weird it only works up to a point, it makes me think perhaps its an issue with some limit I'm not aware.

Anyway, I'm getting dizzy and out of ideas, any thoughts?


Solution

  • This seems to work fine:

    ouroboros = (x, parent = null) => {
        if (!x || typeof x !== 'object')
            return x;
        let r = Object.create(parent);
        Object.entries(x).forEach(([k, v]) => r[k] = ouroboros(v, r));
        return r;
    };
    
    //
    
    
    T = ouroboros({x: 4, a: {b: {c: {d: {e: {}}}}}});
    console.log(T.a.b.c.a.b.c.a.b.c.a.b.c.a.b.c.x);

    or, mutating objects, instead of copying:

    ouroboros = (x, parent = null) => {
        if (x && typeof x === 'object') {
            Object.setPrototypeOf(x, parent);
            Object.values(x).forEach(v => ouroboros(v, x));
        }
    };