Можно ли моделировать наследование? - PullRequest
3 голосов
/ 06 ноября 2019

Моим основным источником информации по этому вопросу является урок Джеймса Шора по этому адресу: http://www.objectplayground.com/ ... После нескольких просмотров видео я забрал достаточно, чтобы связать воедино серию классов, ноЯ до сих пор не понимаю, что происходит под капотом. То, как Джеймс объяснил это классическим наследованием модели (которое, я полагаю, относится к использованию классов для организации данных, а не к более старому способу работы), работает следующим образом:

Когда оценивается любое выражение определения функции, дваобъекты созданы. Первый созданный объект - это конструктор (который я называю cStruct для целей этого вопроса), и его можно идентифицировать по его члену, называемому prototype, который, по его словам и многим другим источникам, указывает на Prototype объекта функции или Function.prototype. Но тогда это становится странным, потому что второй созданный объект - это прототип (или proType), который, в свою очередь, идентифицируется его собственным членом, называемым конструктором, который указывает на cStruct, а также имеет свой собственный член-прототип, который указывает на Объект Прототип объекта , или просто Object.prototype. Ладно, достаточно просто (ха!), Но потом он (и другие источники) продолжит;Когда один класс расширяет другой, мы отказываемся от расширяющихся (более новых / более узких) классов proType, заменяя их на новые, которые фактически указывают на расширенные (оригинальные / более старые / более широкие) классы proType.

ХорошоТаким образом, в этом описании я попытался воссоздать модель наследования, используя только объекты с прототипами null в качестве строительных блоков, чтобы я мог просматривать результаты в консоли, не просматривая все то, что я пока не понимаю. По сути, я ищу дымящийся пистолет наследства;доказательство того, что это не просто фокус . Кажется, что это возможно, но как только логика установлена ​​в форме кода, неудивительно, что она не доставляет унаследованные свойства. Вы поймете, что я имею в виду.

Общая практика --- Три класса

function ExampleClass_A (  ) {  }
function ExampleClass_B (  ) {  }
function ExampleClass_C (  ) {  }

Буквальная интерпретация

NOTE Это буквально эмулируемые классы. Они демонстрируют то, что, как я понимаю, происходит за кулисами во время написания классов. На этом примечании переменную c можно почти игнорировать, пока мы не начнем расширять классы позже

a = Object.create( null );
b = Object.create( null );
c = Object.create( null );  // this represents the Object Prototype
cStruct_A               = a;
proType_A               = b;
proType_A.prototype     = c;
cStruct_A.prototype     = b;
proType_A.constructor   = a;
delete a; delete b;

a = Object.create( null );
b = Object.create( null );
cStruct_B               = a;
proType_B               = b;
proType_B.prototype     = c;
cStruct_B.prototype     = b;
proType_B.constructor   = a;
delete a; delete b;

a = Object.create( null );
b = Object.create( null );
cStruct_C               = a;
proType_C               = b;
proType_C.prototype     = c;
cStruct_C.prototype     = b;
proType_C.constructor   = a;
delete a; delete b; delete c;

Обычная практика --- линейное расширение класса

РЕДАКТИРОВАТЬ @ Vog, я не уверен, что такое композиция объектов, но если бы мне пришлось угадывать, я бы сказал, что это был альтернативный шаблон расширения / создания экземпляров класса по сравнению с линейным, который яЯ написал в этом вопросе, где я должен был предположить, что какая-то форма наследования имела место в любом случае. Я, конечно, не готов принять один шаблон за другим, поскольку я просто пытаюсь понять, как вообще работает механизм, который делает эти шаблоны жизнеспособными, в первую очередь.

ExampleClass_B.prototype = Object.create( ExampleClass_A.prototype );
ExampleClass_C.prototype = Object.create( ExampleClass_B.prototype );

Буквальная интерпретация

ПРИМЕЧАНИЕ Если я правильно понимаю, для наследования должно работать proType всех подклассов, следующих за мастер-классом, или один другой должен указыватьдо proType своего родительского класса. Итак, здесь мы покончили с двумя из трех классов proType и заменили их на те, которые были указаны в соответствующем «последующем» месте.

a                       = Object.create( null );
a.prototype             = proType_A;
a.constructor           = cStruct_B;
alt_proType_B           = a;
cStruct_B.prototype     = alt_proType_B;
delete proType_B;
delete a;

a                       = Object.create( null );
a.prototype             = alt_proType_B;
a.constructor           = cStruct_C;
alt_proType_C           = a;
cStruct_C.prototype     = alt_proType_C;
delete proType_C;
delete a;

CommonПрактика --- реализация

var exampleInstance_W = new ExampleClass_A();   //  
var exampleInstance_R = new ExampleClass_B();   //  randomly chosen names
var exampleInstance_T = new ExampleClass_C();   //  

Буквальная интерпретация

a = Object.create( null );
a.prototype             = proType_A;
nstance_W               = a;
delete a;

a = Object.create( null );
a.prototype             = alt_proType_B;
nstance_R               = a;
delete a;

a = Object.create( null );
a.prototype             = alt_proType_C;
nstance_T               = a;
delete a;

Обычная практика --- задания

ExampleClass_A.prototype.prop_a = "test a,";
ExampleClass_B.prototype.prop_b = "test b,";
ExampleClass_C.prototype.prop_c = "test c";

Буквальная интерпретация

ПРИМЕЧАНИЕ Здесь я начинаю видеть, что что-то может быть не так

cStruct_A.prototype.prop_a = "test a,";
cStruct_B.prototype.prop_b = "test b,";
cStruct_C.prototype.prop_c = "test c";

//  proType_A.prop_a = "test a";    //
//  proType_B.prop_b = "test b";    //  Kind of cool that this works
//  proType_C.prop_c = "test c";    //

Тест --- общепринятая практика

console.log(
    exampleInstance_T.prop_a,  //  successful log
    exampleInstance_T.prop_b,  //  successful log
    exampleInstance_T.prop_c,  //  successful log
);

Тест --- буквальная интерпретация

ПРИМЕЧАНИЕ Теперь для кульминации всех этих усилий. Как странно, что эти журналы дают разные результаты ...

console.log(
    nstance_T.prototype.prop_a,     //  unsuccessful log
    nstance_T.prototype.prop_b,     //  unsuccessful log
    nstance_T.prototype.prop_c,     //  successful log
);

console.log(
    nstance_R.prototype.prop_a,     //  unsuccessful log
    nstance_R.prototype.prop_b,     //  successful log
    nstance_R.prototype.prop_c,     //  unsuccessful log
);

console.log(
    nstance_W.prototype.prop_a,     //  successful log
    nstance_W.prototype.prop_b,     //  unsuccessful log
    nstance_W.prototype.prop_c,     //  unsuccessful log
);

console.log(                        //  Kind of lame that this does't work
    nstance_W.prop_a,               //  
    nstance_R.prop_b,               //  I mean it makes sense when you follow the
    nstance_T.prop_c,               //  established logic, but at the same time
);                                  //  it means that I'm missing something.

Другими словами, если каждый Буквальная интерпретация кодовый блок просто эмулирует Обычную практику кодовый блок над нимпочему nstance_t не имеет доступа к .prop_a и .prop_b? Это как-то связано с моей конфигурацией? Я упускаю суть? Помоги мне, ребята. Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 07 ноября 2019

Почему nstance_t не имеет доступа к .prop_a и .prop_b? Это как-то связано с моей конфигурацией? Я упускаю суть?

Похоже, вы ожидали, что .prototype устанавливает цепочку наследования объекта. Это не так, это просто обычное свойство, и присвоение ему ничего не делает.

Фактическая ссылка на объект (или null), от которого наследуется объект, является внутренней, часто обозначаемой как [[прототип]] . Вам нужно позвонить Object.getPrototypeOf(…), чтобы получить к нему доступ. Для его настройки вы можете использовать Object.create, Object.setPrototypeOf или new.

Я считаю, что это код, который вы ищете:

Обычная практика -ES6

class A {}
class B extends B {}
const instance = new B

Обычная практика - ES5

function A() {}
function B() {}
B.prototype = Object.create(A.prototype)
B.prototype.constructor = B
const instance = new B

Литеральная интерпретация (отношений объекта, игнорируя вызовы конструктора)

A_prototype = Object.create(Object.prototype)
A_constructor = new Function(…)
A_prototype.constructor = A_constructor
A_constructor.prototype = A_prototype

B_prototype = Object.create(A_constructor.prototype)
B_constructor = new Function(…)
B_prototype.constructor = B_constructor
B_constructor.prototype = B_prototype

instance = Object.create(B_constructor.prototype)

Теперь вы можете назначать свойства A_prototype / A_constructor.prototype и B_prototype / B_constructor.prototype и видеть, что они наследуются instance.

1 голос
/ 06 ноября 2019

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

Мантра здесь - всегда использовать композицию объектов вместо наследования, когда это возможно (что, на мой взгляд, практически всегда так).

Это отличается от, скажем, моделирования правильной системы типов поверх JavaScript. Или моделирование деконструкции и сопоставление структурных паттернов. Эти игрушки также никогда не могут быть использованы в производстве, но, по крайней мере, вы создадите что-то, что позже захотите использовать «по-настоящему».

Обратите внимание, что наследование не выполняло своих обещаний ни на одном языкеБудь то C ++, Python, Ruby, PHP, Smalltalk, Java и так далее. Вы можете найти ранние подсказки даже в книге GoF (https://en.wikipedia.org/wiki/Design_Patterns),, которая является своего рода библией для большинства ОО-программистов. Там, хотя наследование не подвергается прямой критике, вы можете обобщить целый подраздел образцов как «какзаменить сложную в обслуживании структуру наследования хорошо поддерживаемой структурой композиции объектов ".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...