Каким образом можно создать объект, который будет иметь контекст родительского объекта?

Здравствуйте! У меня есть следующий код: <br/> <pre><code class="javascript">let arr=[{
        key1:1,
        key2:2,
        key3:3,
        children:{
            render(){
                console.log(this.key1,"Key");//undefined
            }
        }
    }]</code></pre> <br/> Возможно ли создать объект `children`, который будет ссылаться на контекст родительского объекта, не используя переменную `arr`?
  • 1 октября 2024 г. 15:44
Ответы на вопрос 3
Да, вы можете создать объект `children`, который будет ссылаться на контекст родительского объекта, используя стрелочные функции или связывание контекста с помощью `.bind`, но без использования переменной `arr`. Вот два способа, как это сделать:

1. **Использование стрелочной функции**:
   Стрелочные функции не имеют собственного контекста, поэтому они будут наследовать `this` от родителя. В вашем случае вы можете использовать стрелочную функцию внутри метода `render`.

```javascript
let arr = [{
    key1: 1,
    key2: 2,
    key3: 3,
    children: {
        render: () => {
            console.log(arr[0].key1, "Key"); // 1 Key
        }
    }
}];

arr[0].children.render();
```

2. **Использование метода `bind`**:
   Вы можете явно привязать контекст метода `render` к родительскому объекту.

```javascript
let arr = [{
    key1: 1,
    key2: 2,
    key3: 3,
    children: {
        render: function() {
            console.log(this.key1, "Key"); // 1 Key
        }
    }
}];

arr[0].children.render.bind(arr[0])();
```

В обоих вариантах `render` имеет доступ к `key1` родительского объекта, что позволяет корректно вывести его значение в консоль. Однако в первом варианте вы всё равно обращаетесь к `arr`, что, по сути, является ссылкой на родительский объект.

Если же вы хотите избежать использования `arr` и хотите сделать это более "чисто", вот еще один способ, как это сделать, используя `Proxy`:

```javascript
const parentObj = {
    key1: 1,
    key2: 2,
    key3: 3,
};

const childObj = {
    render() {
        console.log(this.key1, "Key"); // 1 Key
    }
};

// Создание прокси, который будет передавать контекст родителя
const proxiedChild = new Proxy(childObj, {
    get(target, prop, receiver) {
        if (prop === "render") {
            return target.render.bind(parentObj); // Привязываем метод к parentObj
        }
        return Reflect.get(target, prop, receiver);
    }
});

proxiedChild.render(); // 1 Key
```

Таким образом, вы создаете объект `children`, который имеет контекст родительского объекта, не используя переменную `arr`.
class Foo 
{
    constructor() {
        this.key1 = 'key 1'
        this.bar = new Bar(this)
    }
}

class Bar {

    constructor(parent) {
        this.parent = parent
    }

    redner() {
        console.log('Parent key 1:', this.parent.key1)
    }
}
function bindRootContext(obj, context = obj) {
  return new Proxy(obj, {
    get(target, key) {
      const val = target[key];

      if (val instanceof Function) {
        return val.bind(Array.isArray(target) && Object.hasOwn(Array.prototype, key)
          ? target
          : context
        );
      } else if (val instanceof Object) {
        return bindRootContext(val, context);
      }

      return val;
    },
  });
}


const obj = bindRootContext({
  name: 'Root',
  a: {
    name: 'A',
    logName() { console.log(this.name); },
    b: {
      name: 'B',
      logName() { console.log(this.name); },
      arr: [
        {
          name: '666',
          logName() { console.log(this.name); },
        },
        function() { console.log(this.name); },
      ],
      c: {
        name: 'C',
        logName() { console.log(this.name); },
      },
    },
  },
});

obj.a.b.c.logName(); // Root
obj.a.b.logName(); // Root
obj.a.logName(); // Root
obj.a.b.arr[0].logName(); // Root
obj.a.b.arr[1](); // Root
Похожие вопросы