Можно ли «импортировать» или «передать» заранее определенный объект в класс, имеющий доступ к методам этого класса? Важно отметить, что из соображений производительности мне необходимо убедиться, что я не создаю заново и не переопределяю «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
Есть ли какое-то значение в том, чтобы sub_property_b
быть добытчиком? Если да, какой код обращается к нему?
попытался выяснить, как я пытаюсь использовать Distinct_Class
Нет, это невозможно. При доступе к massive_entity_obj.property_1.sub_property_b
он ничего не знает о distinct_1
или distinct_2
(или о том, что они различны)! Если вы хотите, чтобы distinct_1.entities
имел другое поведение и другие свойства (и подсвойства), чем distinct_2.entities
, вам необходимо создать другой объект.
Я боялся, что поступаю неправильно. Спасибо за подтверждение.
@Occam ... известна ли структура переданного объекта или вы ищете обобщенно реализованный подход классов-оберток объектов для переданных объектов различной структуры/формы? С другой стороны, какова реальная причина поиска решения, описанного вами в первую очередь? Может быть, все установки/(предварительные) предположения, ведущие к такому подходу, просто ошибочны?
@Occam ... вы можете взглянуть на поздно предоставленный ответ, который полностью решает проблему представленного вами сценария.
Не таким образом. Я не знаю хорошего способа предоставить объекту и всем его свойствам доступ к функциям в таком объекте, определяемом классом. Даже если большой объект изначально был создан из класса, свойства объекта не будут иметь доступа к функциям класса, если только функции свойств не будут созданы только с использованием Стрелочных функций в конструкторе класса.
Лучше всего, вероятно, сделать одно из двух: вы можете либо создать класс со статическими функциями и переменными, либо создать объект из класса в глобальной области видимости.
Создать класс со статическими функциями довольно просто. Использование 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>
Не совсем понятно, где и как вы создаете экземпляр
new Distinct_Class