Наследование классов с интерфейсом класса прототипа

Я использую автономное наследование классов прототипа: https://github.com/Jakobo/PTClass

И у меня есть следующие классы:

App.hello = Class.create({

    initialize: function(args) {
        this.name = args.name
    },

    sayHello: function() {
        console.log('Hello, ' + this.name);
    },

    sayGoodbye: function() {
        console.log('Goodbye, ' + this.name);
    }

});

App.yo = Class.create(App.hello, {

    initialize: function($super) {
        $super();
    },

    sayHello: function() {
        console.log('Yo, ' + this.name);
    }

});

Где идея состоит в том, что yo наследуется от hello и переопределяет его метод sayHello. Но также иметь возможность вызывать метод sayGoodbye в своем родительском классе.

Поэтому я называю их так:

var test = new App.hello({name: 'Cameron'});
    test.sayHello();
    test.sayGoodbye();
var test2 = new App.yo({name: 'Cameron'});
    test2.sayHello();
    test2.sayGoodbye();

Однако я получаю сообщение об ошибке, что Uncaught TypeError: Cannot read property 'name' of undefined для моего класса yo.

Как мне правильно наследовать от моего класса hello?


person Cameron    schedule 14.02.2017    source источник
comment
Просто хочу отметить: Class материал PrototypeJS устарел, и в наши дни PrototypeJS практически не поддерживается. Вам лучше изучить новый синтаксис class, представленный в ES2015 (он же ES6), и при необходимости транспилировать его для старых браузеров.   -  person T.J. Crowder    schedule 14.02.2017


Ответы (1)


Проблема в том, что initializer yo не передает аргументы, которые вы передаете суперклассу:

initialize: function($super, args) { // ***
    $super(args);                    // ***
},

Следовательно, код в функции initialize hello пытается прочитать свойство name из args, но args является undefined. Отсюда ошибка.

Обновленный рабочий пример:

var App = {};

App.hello = Class.create({

    initialize: function(args) {
        this.name = args.name
    },

    sayHello: function() {
        console.log('Hello, ' + this.name);
    },

    sayGoodbye: function() {
        console.log('Goodbye, ' + this.name);
    }

});

App.yo = Class.create(App.hello, {

    initialize: function($super, args) {
        $super(args);
    },

    sayHello: function() {
        console.log('Yo, ' + this.name);
    }

});

var test = new App.hello({name: 'Cameron'});
    test.sayHello();
    test.sayGoodbye();
var test2 = new App.yo({name: 'Cameron'});
    test2.sayHello();
    test2.sayGoodbye();
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.min.js"></script>


И что касается моего комментария к вопросу, вот версия ES2015+, не использующая PrototypeJS:

const App = {};

App.hello = class {
    constructor(args) {
        this.name = args.name
    }

    sayHello() {
        console.log('Hello, ' + this.name);
    }

    sayGoodbye() {
        console.log('Goodbye, ' + this.name);
    }
};

App.yo = class extends App.hello {
    sayHello() {
        console.log('Yo, ' + this.name);
    }
};

const test = new App.hello({name: 'Cameron'});
      test.sayHello();
      test.sayGoodbye();
const test2 = new App.yo({name: 'Cameron'});
      test2.sayHello();
      test2.sayGoodbye();

Обратите внимание, что нам вообще не нужно было определять constructor для yo, так как он ничего не делает. Движок JavaScript создаст его для нас, который будет выглядеть так:

constructor(...allArguments) {
    super(...allArguments);
}
person T.J. Crowder    schedule 14.02.2017
comment
Новый материал ES6 выглядит красиво... Но он не поддерживается в IE, не так ли? - person Cameron; 14.02.2017
comment
@Cameron: Нет, но вы можете транспилировать с помощью таких инструментов, как Babel, как часть процесса сборки вашего дистрибутива. - person T.J. Crowder; 14.02.2017
comment
Как выглядит ES5-версия приведенного выше кода ES6? - person Cameron; 14.02.2017
comment
@Cameron: немного уродливее: stackoverflow.com/questions/30783217/, но конечный результат практически такой же и работает так же хорошо (кроме того, что есть вещи, которые вы не можете сделать со старым синтаксисом, но можете с новым , например создание подкласса Array). - person T.J. Crowder; 14.02.2017
comment
Не могли бы вы показать пример с использованием ES5 и прототипа? Я пробовал здесь: jsfiddle.net/h2c5zcye, но получаю сообщение об ошибке о невозможности установить свойство "прототип". Я думаю, что если я увижу точную копию моего исходного кода с использованием прототипа (так что класс делает внизу), я лучше его пойму. Спасибо! - person Cameron; 14.02.2017
comment
Хорошо, все заработало: jsfiddle.net/h2c5zcye/3 Спасибо. Но возможно ли это сделать с литералами Object, как в примере Class.create? Итак, у меня могут быть вложенные методы? Итак, мои методы sayHello и sayGoodbye находятся в моем конструкторе Hello? - person Cameron; 14.02.2017
comment
@Cameron: в этом нет ничего, что мешало бы вам использовать вложенные методы. - person T.J. Crowder; 14.02.2017
comment
Не могли бы вы показать пример того, как моя скрипка может быть вложенной? Возможно, вилка скрипки. Я начал с этого: jsfiddle.net/6L1w0aL8/1, но не понимаю, как получить вложенный конструктор и как вложить App.Yo. Большое спасибо за то, что помогли мне понять это до сих пор. - person Cameron; 14.02.2017
comment
@Cameron: На данный момент мы действительно далеко. Если у вас есть дополнительные вопросы, после вашего обычного исследования и тому подобного, я предлагаю опубликовать вопрос, чтобы люди могли на него ответить. - person T.J. Crowder; 14.02.2017
comment
Я задал новый вопрос: stackoverflow.com /вопросы/42246752/ - person Cameron; 15.02.2017