0

I'm using prototype's standalone class inheritance: https://github.com/Jakobo/PTClass

And I have the following classes:

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);
    }

});

Where the idea is that yo would inherit from hello and override its sayHello method. But also be able to call the sayGoodbye method in its parent class.

So I call them like so:

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

However I get the error that Uncaught TypeError: Cannot read property 'name' of undefined for my yo class.

How do I properly inherit from my hello class?

Cameron
  • 27,963
  • 100
  • 281
  • 483
  • 1
    Just to put it out there: PrototypeJS's `Class` stuff is obsolete, and PrototypeJS isn't really maintained much these days. You'd be better off learning the new `class` syntax introduced in ES2015 (aka "ES6") and transpiling if necessary for older browsers. – T.J. Crowder Feb 14 '17 at 12:24

1 Answers1

1

The problem is that yo's initializer doesn't pass on the arguments you pass it to the superclass:

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

Consequently, the code in hello's initialize function tries to read the name property from args, but args is undefined. Hence the error.

Updated working example:

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>

And regarding my comment on the question, here's an ES2015+ version not using 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();

Note that we didn't need to define a constructor for yo at all, since it doesn't do anything. The JavaScript engine will create one for us, which looks like this:

constructor(...allArguments) {
    super(...allArguments);
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • The new ES6 stuff looks nice... But it's not supported in IE is it? – Cameron Feb 14 '17 at 12:34
  • @Cameron: No, but you can transpile with tools like [Babel](http://babeljs.io) as part of your distribution build process. – T.J. Crowder Feb 14 '17 at 12:36
  • What does the ES5 version of the ES6 code above look like? – Cameron Feb 14 '17 at 12:37
  • @Cameron: A fair bit uglier: http://stackoverflow.com/questions/30783217/why-should-i-use-es6-classes/30783368#30783368, but the end result is essentially the same and runs just as well (other than that there are things you can't do with the old syntax that you can with the new, such as subclassing `Array`). – T.J. Crowder Feb 14 '17 at 12:40
  • Could you show an example using ES5 and prototype? I tried here: https://jsfiddle.net/h2c5zcye/ but get an error about cannot set the property 'prototype'. I think if I can see an exact replica of my original code using prototype (so what class is doing underneath) I'd better understand it. Thanks! – Cameron Feb 14 '17 at 16:06
  • @Cameron: Look again at the ES5 example in [the answer I linked above](http://stackoverflow.com/questions/30783217/why-should-i-use-es6-classes/30783368#30783368). You don't use `this.prototype.sayHello = function...` in the constructor, you use `App.Hello.prototype.sayHello = function...` outside the constructor. – T.J. Crowder Feb 14 '17 at 16:12
  • Ah okies got it to work: https://jsfiddle.net/h2c5zcye/3/ Thanks. But is it possible to do it with Object literals like the `Class.create` example? So I can have nested methods? So have my `sayHello` and `sayGoodbye` methods sit under my `Hello` constructor? – Cameron Feb 14 '17 at 16:33
  • @Cameron: There's nothing about that which prevents your having nested methods. – T.J. Crowder Feb 14 '17 at 16:59
  • Could you show an example of how I could have my fiddle as nested? Perhaps a fork of the fiddle. I made a start on it: https://jsfiddle.net/6L1w0aL8/1/ but can't see how to get the constructor nested and how to nest `App.Yo`. Much appreciated for helping me get my head around this so far. – Cameron Feb 14 '17 at 17:03
  • @Cameron: We're really far afield at this point. If you have further questions, after doing your usual research and such, I suggest posting a question so people can answer it. – T.J. Crowder Feb 14 '17 at 17:10
  • I have asked a new question: http://stackoverflow.com/questions/42246752/using-object-literal-for-prototype-classes – Cameron Feb 15 '17 at 10:30