Как передать ссылку на объект в класс, имеющий доступ к методам класса в JS

Можно ли «импортировать» или «передать» заранее определенный объект в класс, имеющий доступ к методам этого класса? Важно отметить, что из соображений производительности мне необходимо убедиться, что я не создаю заново и не переопределяю «massive_entity_obj» в примере.

class Distinct_Class {
   entities = null;

   constructor(massive_entity_obj) {
      this.entities = massive_entity_obj;
   }

   unique_func_1() {
      const some_value = "calcs based on unique data of Distinct_Class";
      return some_value;
   }
}

// defined in a separate module
massive_entity_obj = {
   property_1: {
      sub_property_a: "something",
      get sub_property_b() {
         // call a function in Distinct_Class in the context of Distinct_Class
         return this.unique_func_1(); // <-- this does not work
      },
   },
};

const distinct_1 = new Distinct_Class(massive_entity_obj)
const distinct_2 = new Distinct_Class(massive_entity_obj)
let sub_prop = distinct_1.entities.property_1.sub_property_b
let other_sub_prop = distinct_2.entities.property_1.sub_property_b

Не совсем понятно, где и как вы создаете экземпляр new Distinct_Class

Bergi 21.08.2024 02:32

Есть ли какое-то значение в том, чтобы sub_property_b быть добытчиком? Если да, какой код обращается к нему?

Bergi 21.08.2024 02:33

попытался выяснить, как я пытаюсь использовать Distinct_Class

Occam 21.08.2024 05:23

Нет, это невозможно. При доступе к massive_entity_obj.property_1.sub_property_b он ничего не знает о distinct_1 или distinct_2 (или о том, что они различны)! Если вы хотите, чтобы distinct_1.entities имел другое поведение и другие свойства (и подсвойства), чем distinct_2.entities, вам необходимо создать другой объект.

Bergi 21.08.2024 10:52

Я боялся, что поступаю неправильно. Спасибо за подтверждение.

Occam 21.08.2024 12:08

@Occam ... известна ли структура переданного объекта или вы ищете обобщенно реализованный подход классов-оберток объектов для переданных объектов различной структуры/формы? С другой стороны, какова реальная причина поиска решения, описанного вами в первую очередь? Может быть, все установки/(предварительные) предположения, ведущие к такому подходу, просто ошибочны?

Peter Seliger 21.08.2024 18:06

@Occam ... вы можете взглянуть на поздно предоставленный ответ, который полностью решает проблему представленного вами сценария.

Peter Seliger 21.08.2024 20:10
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
7
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Не таким образом. Я не знаю хорошего способа предоставить объекту и всем его свойствам доступ к функциям в таком объекте, определяемом классом. Даже если большой объект изначально был создан из класса, свойства объекта не будут иметь доступа к функциям класса, если только функции свойств не будут созданы только с использованием Стрелочных функций в конструкторе класса.

Лучше всего, вероятно, сделать одно из двух: вы можете либо создать класс со статическими функциями и переменными, либо создать объект из класса в глобальной области видимости.

Использование статики

Создать класс со статическими функциями довольно просто. Использование static для определения переменных и функций по сути превращает ваш класс в отдельный объект, а также в класс. Если вы хотите узнать больше об операторе static, нажмите здесь. Вот пример:

class myClass {
 static myFunction(value) {
  console.info(value);
 }
}

var myobject = {
 property: {
  a: 'Hello!',
  b: function() {
   myClass.myFunction(this.a);
  }
 }
}

myobject.property.b();

Глобальный объект

Создание объекта из существующего класса, к которому ваш большой объект имеет доступ, с использованием переменной, позволит обеспечить большую гибкость, например, хранить изменяющиеся переменные и действовать больше как пользовательский объект. Это будет выглядеть так:

class myClass {
 constructor() {}
    
 myFunction(value) {
  console.info(value);
 }
}

var classobject = new myClass();

var myobject = {
 property: {
  a: 'Hello!',
  b: function() {
   classobject.myFunction(this.a);
  }
 }
}

myobject.property.b();

Я бы порекомендовал один из этих двух методов, перечисленных выше. Однако если вы намерены объединить существующий объект и класс без повторного создания объекта, вы можете попробовать способ, указанный ниже. Похоже, он просто не предназначен для этого:

Прямой доступ

Хоть и неудобно дано.

Единственный известный мне способ максимально напоминать ваш код — это назначить новый объект, созданный классом, как свойство каждого объекта, в котором вы хотите использовать функции, — что не особенно удобно. Только если вы присвоите свойствам вашего объекта объект, созданный myClass, или вызовете что-то вроде Object.assign(property, new myClass()) для каждого из них, это даст им возможность использовать ключевое слово this для доступа к функциям. Если вы это сделаете, будет похоже, что вы берете класс и объект и меняете их роли:

class myClass {
 value = 'World';

 constructor(existingobject) {
  existingobject.property.access = this;
 }

 myFunction(value) {
  console.info(`${value}, ${this.value}!`);
 }
}

var myobject = {
 property: {
  a: 'Hello',
  b: function() {
   this.access.myFunction(this.a);
  }
 }
}

new myClass(myobject);
myobject.property.b();

Затем, если вы хотите, чтобы myClass имел доступ к myObject, вы добавляете в конструктор что-то вроде this.object = existingobject.

Я бы рекомендовал по возможности хранить их отдельно, используя одно из первых двух предложений, особенно если многие свойства и подсвойства являются объектами, требующими использования функций класса.

То, что ищет ОП, может быть решено полностью в общих чертах.

Единственное предположение, которое нужно сделать в отношении вводимого «массивного объекта данных», заключается в том, что с ним придется иметь дело как со структурой данных, где каждая (собственная) запись этой структуры (пара ключ-значение), независимо от вложенных или нет, обрабатывается через дескриптор свойства .

Этот параметр позволяет использовать комбинированную стратегию клонирования и делегирования/привязки для геттеров и сеттеров, которые являются функциями, поэтому их контекст (thisArg) можно изменить с помощью привязки.

Реализуя этот подход как рекурсивную функцию, можно легко добиться глубокого и реального клонирования любого предоставленного объекта данных (благодаря клонированию дескрипторов свойств), а также иметь возможность перепривязать любой метод получения или установки к контексту задействованного экземпляра класса. во время создания/реализации.

// e.g. defined in separate modules

// ----- ----- ----- ----- -----
class DistinctClass {

  #state;
  entities = null;

  constructor(dataBlob, protectedState) {
    this.#state = structuredClone(protectedState);

    this.entities =
      cloneStructureAndRebindAnyGetAndSet(this, dataBlob);

    console.info({
      'injected blob': dataBlob,
      'this.entities': this.entities,
    });
  }
  uniqueDataProcessingMethod() {
    console.info('calcs based on unique instance data/state.');

    return structuredClone(this.#state);
  }
}
// ----- ----- ----- ----- -----

// ----- ----- ----- ----- -----
const massiveDataBlob_1 = {
   property_1: {
      subProperty_A: "sub property A",
      get subProperty_B() {
         // - invocation of a `DistinctClass` instance specific
         //   method within the context of this very instance.
         return this?.uniqueDataProcessingMethod?.();
      },
   },
};
// ----- ----- ----- ----- -----

// ----- ----- ----- ----- -----
const massiveDataBlob_2 = {
   property_2: {
      subProperty_C: "sub property C",
      get subProperty_D() {
         // - invocation of a `DistinctClass` instance specific
         //   method within the context of this very instance.
         return this?.uniqueDataProcessingMethod?.();
      },
   },
};
// ----- ----- ----- ----- -----

const distinct_A =
  new DistinctClass(massiveDataBlob_1, { foo: 'FOO', bar: 'BAR' });

const distinct_B =
  new DistinctClass(massiveDataBlob_2, { baz: 'BAZ', bizz: 'BIZZ' });

const distinctResult_A =
  distinct_A.entities.property_1.subProperty_B;

const distinctResult_B =
  distinct_B.entities.property_2.subProperty_D;

console.info({
  distinctResult_A,
  distinctResult_B,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
function isFunction(value) {
  return (
    typeof value === 'function' &&
    typeof value.call === 'function' &&
    typeof value.apply === 'function'
  );
}

function cloneStructureAndRebindAnyGetAndSet(context, data, result = {}) {
  if (Array.isArray(data)) {

    result = Array.map(item =>
      cloneStructureAndRebindAnyGetAndSet(context, item)
    );

  } else if (!!data && typeof data === 'object') {

    result = Object

      .keys(data)
      .reduce((target, key) => {

        const descriptor = Reflect.getOwnPropertyDescriptor(data, key);
        let { set, get, value } = descriptor;
  
        if (isFunction(set)) {
          set = set.bind(context);
        }
        if (isFunction(get)) {
          get = get.bind(context);
        }
        
        if (Object.hasOwn(descriptor, 'value')) {

          if (!!value && typeof value === 'object') {

            value = cloneStructureAndRebindAnyGetAndSet(context, value);
          }
          Reflect.defineProperty(target, key, { ...descriptor, value });

        } else {

          Reflect.defineProperty(target, key, {
            ...descriptor,
            ...(set ? { set } : {}),
            ...(get ? { get } : {}),
          });
        }
        return target;

      }, result);

  } else {

    result = data;
  }
  return result;
}
</script>

Другие вопросы по теме