Вот несколько старых вопросов, в которых обсуждается прототипное наследование и делегирование Javascript, например:
- Преимущества прототипного наследования по сравнению с классическим?
- классическое наследование и прототипное наследование в javascript
Мне интересно, какова текущая (2018) рекомендация по использованию прототипов/прототипного наследования в Javascript.
Насколько я понимаю, более новые версии JavaScript (ES6) и TypeScript больше ориентированы на традиционное наследование на основе классов. (Сам я еще не использовал ES6 или TS на практике.) Верно ли это наблюдение?
На самом деле этот код на основе классов действительно прост и понятен:
class A { a: "a" }
class B extends A { b: "b" }
let a = new A(), b = new B();
EDIT 2: в TypeScript это будет:
class A { a = "a" }
class B extends A { b = "b" }
let a = new A(), b = new B();
EDIT: на самом деле синтаксис ES6 сложнее:
class A { constructor() { this.a = "a"; } }
class B extends A { constructor() { super(); b = "b"; } }
let a = new A(), b = new B();
Для использования прототипов есть больше вариантов, и на самом деле я пока не нашел ни одного столь же простого и "хорошего".
EDIT: Чего я хочу добиться, так это того, что я создаю b как экземпляр B с прототипом A таким образом, чтобы при динамическом изменении свойства A изменение также влияло на b :
Простой подход:
var A = { a: "a" }
var B = Object.create(A, {b: {value: "b"}});
var a = Object.create(A), // direct instance of A
b = Object.create(B); // indirect instance of A
console.log(b.a); // "a"
A.a = "a++"; // change the base prototype (will affect B, a, and b)
console.log(b.a); // "a++"
Было бы намного лучше, если бы второй аргумент также мог быть простым объектом с парами ключ-значение, а не дескрипторами свойств (см. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
В большинстве случаев используется функция конструктора, например. в https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
function A() { this.a = "a"; }
function B() { this.b = "b"; }
B.prototype = new A();
var a = new A(), b = new B();
console.log(b.a); // "a"
A.a = "a++";
console.log(b.a); // return "a" instead of "a++" as b.a is overwritten in constructor
Кроме того, это не так приятно, так как здесь вы не можете изменить A.a таким образом, чтобы b.a также изменился, что является IMO ключевым моментом в прототипном наследовании. Так может это?
function A() {}
A.prototype.a = "a";
function B() {}
B.prototype = Object.create(A.prototype);
B.prototype.b = "b";
var a = new A(), b = new B();
function A() { this.a = "a"; }
function B() { this.b = "b"; }
B.prototype = new A();
var a = new A(), b = new B();
console.log(b.a); // "a"
A.a = "a++";
console.log(b.a); // still "a" instead of "a++"
Не дает ожидаемого результата. И, ну, вы не хотите писать это, не так ли?
Конечно, вы можете поместить создание в функцию конструктора, как описано https://stackoverflow.com/a/16872315/1480587 но я думаю, что это все еще не так красиво и просто для синтаксиса класса. На самом деле, я ищу что-то вроде этого (похоже на объявление объекта Kotlin ):
object A { a: "a" }
object B extends A { b: "b" }
let a = new A(), b = new B();
Итак, что бы вы порекомендовали? Есть ли что-то близкое?
Особенно, если вы хотите использовать некоторую инкапсуляцию и иметь члены частного объекта, невидимые для клонированных объектов?
Предоставляет ли TypeScript хорошее решение?
Перейти на Котлин?
Или вообще следует вернуться к наследованию на основе классов, поскольку это то, что все остальные используют и понимают?
class
— это просто синтаксический сахар для прототипов, попробуйтеclass X{}
иconsole.log(typeof X)
. - person georg   schedule 01.03.2018