1

I know this may seem like a repeated question, but I am currently stuck as to the best way to approach this, limited mostly by my lack of knowledge. Thus I am here to learn.

I am trying to do some simple OOP with JavaScript but coming from C# I am having a few issues with how to best solve this problem. Below I have four "Classes"; DisplayEngine, DisplayElement, Box, and Grid.

I would like Box and Grid to inherit DisplayElement, and be able to call the base functions in each of their respective functions. Almost like super.call() or something.

How would you best approach this?

var DisplayEngine = function() {

    this.elements = [];

    this.add = function(element) {
        this.elements.push(element);
    };

    this.update = function() {
        this.elements.forEach(function(element) {
            element.update();
        })
    };

    this.draw = function() {
        this.elements.forEach(function(element) {
            element.draw();
        })
    };

};

var DisplayElement = function() {

    this.update = function() {
        console.log('DisplayElement update');
    };

    this.draw = function() {
        console.log('DisplayElement draw');
    };

};

var Box = function() {

    this.update = function() {
        console.log('Box update');
        // call DisplayElement.update()
    };

    this.draw = function() {
        console.log('Box draw');
        // call DisplayElement.draw()
    };

};

var Grid = function() {

    this.update = function() {
        console.log('Grid update');
        // call DisplayElement.update()
    };

    this.draw = function() {
        console.log('Grid draw');
        // call DisplayElement.draw()
    };

};

$(function() {
    var displayEngine = new DisplayEngine();
    var box = new Box();
    var grid = new Grid();

    displayEngine.add(box);
    displayEngine.add(grid);
    displayEngine.update();
    displayEngine.draw();
});
Adam K Dean
  • 7,387
  • 10
  • 47
  • 68
  • 2
    The *best* thing to do is step back and contemplate whether it makes sense to twist JavaScript into acting like C#. The inheritance systems are significantly different in both design and intent. – Pointy Feb 19 '14 at 19:18
  • The only thing close to what you mention is `prototype` – thatidiotguy Feb 19 '14 at 19:18
  • I agree with stepping back from "Classical OOP". Sub-type inheritance (ala C#) is 1) a means of sharing implementation and 2) a means of allowing sub-type polymorphism. However, JavaScript (being dynamically typed or "late bound") has no need for sub-type polymorphism (e.g. duck-typing works well), and inheritance is not the only way to share implementation. – user2864740 Feb 19 '14 at 19:20
  • does "Box.prototype = new DisplayElement();" not work for your needs? – dandavis Feb 19 '14 at 19:23
  • @dandavis I tried that, but how do I call the prototype version of the method? – Adam K Dean Feb 19 '14 at 20:18
  • @Pointy/@user2864740 totally agree with you. One of the things I have to do, as part of my transition from C# to JS is to get my head around the JavaScript way of doing things. – Adam K Dean Feb 19 '14 at 20:35
  • You may find this helpful http://stackoverflow.com/a/16063711/1641941 it covers constructor functions, prototype and "pseudo classical" inheritance patterns. – HMR Feb 20 '14 at 07:36
  • Thanks @HMR, I'll take a look at that later, sounds like it'll be very useful. – Adam K Dean Feb 20 '14 at 10:26

3 Answers3

3

Here is a way to do it with prototype, each "class" need to be in his own file, the important part is Grid.prototype = new DisplayElement(); This allow you to call function from the DisplayElement in Grid:

DisplayEngine.js

function DisplayEngine() {

    this.elements = [];

}

DisplayEngine.prototype.add = function(element) {
    this.elements.push(element);
}

DisplayEngine.prototype.update = function() {
    this.elements.forEach(function(element) {
        element.update();
    })
}

DisplayEngine.prototype.draw = function() {
    this.elements.forEach(function(element) {
        element.draw();
    })
}

DisplayElement.js

function DisplayElement() {

}

DisplayElement.prototype.updateElement = function() {
    console.log('DisplayElement update');
}

DisplayElement.prototype.drawElement = function() {
    console.log('DisplayElement draw');
}

Box.js

function Box() {

}

Box.prototype = new DisplayElement();

Box.prototype.update = function() {
    console.log('Box update');
    this.updateElement();
}

Box.prototype.draw = function() {
    console.log('Box draw');
    this.drawElement();
}

Grid.js

function Grid() {

}

Grid.prototype = new DisplayElement();

Box.prototype.update = function() {
    console.log('Grid update');
    this.updateElement();
}

Box.prototype.draw = function() {
    console.log('Grid draw');
    this.drawElement();
}

Main.js

$(function() {
    var displayEngine = new DisplayEngine();
    var box = new Box();
    var grid = new Grid();

    displayEngine.add(box);
    displayEngine.add(grid);
    displayEngine.update();
    displayEngine.draw();
});
Shryme
  • 1,572
  • 1
  • 14
  • 22
  • 1
    Thank you. This is exactly what I was looking for. I tried this previously, but I had the same method names (`update` and `update`), whereas you get around this by having `update` and `updateElement`. Sorry for my question being so brisk, but you interpreted it perfectly. Again, thank you! – Adam K Dean Feb 19 '14 at 20:33
0

To just answer to your question, declare your objects such as :

function DisplayElement() {};

DisplayElement.prototype.update = function() {
    console.log('DisplayElement update');
};
DisplayElement.prototype.draw = function() {
    console.log('DisplayElement draw');
};

// ...
// Now, instanciation :
var myElement = new DisplayElement();

Then, for inheritance :

function Box() {
    DisplayEngine.call(this, arguments); // Call the super constructor
}
Box.prototype = Object.create(DisplayEngine.prototype); // "Apply" the inheritance
Box.prototype.constructor = Box; // Redefine the constructor to Box because it was overriden by the previous line

I disagree about those saying that you doesn't need "classes" in Javascript. In implementations such as Node.js which will handle datas must have, in my opinion, classes. It's easier (always in my opinion) to read, maintain, and use.

Serge K.
  • 5,303
  • 1
  • 20
  • 27
  • 2
    it sounds like you conflate Classes with other objects like modules. Having organization is more important than having the inheritance provided by classes. – dandavis Feb 19 '14 at 20:31
  • @dandavis Thank you :) I'll take a look at the module pattern, which I don't really know. What do you mean by organization ? – Serge K. Feb 19 '14 at 22:28
  • i mean having related tools bundled together under a dot path. for example window.Math is not a class but it does organize lots of handy functions. window.Element is a class, does inherit, and also bundles useful methods. – dandavis Feb 19 '14 at 22:32
  • @dandavis The frontier is really tight for me. What's the main difference? Is it just coding style? – Serge K. Feb 19 '14 at 22:44
  • 2
    prototypal inheritance is the difference. Since JS swings fast and loose, you don't need inheritance to link sub-objects. JS's templated functions, those using 'this', allow methods to apply() to just about anything. If a method doesn't use the 'this' keyword in it's main scope, it can be called from anywhere as anything. ex: tools={num: Math }; tools.num.max(1,2,3)==3; Even if it does use 'this' internally, you can still call(), apply(), or bind() the method upon another object as needed. Inheritance is over-rated in JS. – dandavis Feb 19 '14 at 22:53
  • I understand it little better now. But in the scope of the question, prototypal inheritance was the good solution, right? – Serge K. Feb 19 '14 at 22:59
  • 2
    any solution that works is a good solution. If inheritance patterns make more sense to a coder coming from C#, it will likely be easier to plan, expand, and maintain by that coder. We don't see a big payoff in performance on shared prototype-based methods because browsers already recycle identical functions. This simple example doesn't really show off OOPs biggest advantage, organizing complexity without making it complicated. – dandavis Feb 19 '14 at 23:22
  • @dandavis OK I think I got it. Thank you very much, it was really interesting to me. :) – Serge K. Feb 19 '14 at 23:24
0

You can use the prototypal style like what Shryme explained, or you can use a library that mimcs the classical oop style in javascript, check Classing{js} : http://www.classingjs.co.nf/

m0stafa
  • 109
  • 1
  • 7