Joseph
Joseph

Reputation: 3959

Trying to get "classes" in Javascript to play nice

So I know that classes in Javascript are a bit different as Javascript has this whole everything is an object thing. I'm trying to build a class that contains the information to create a simple div in HTML.

Please see the following code:

Javascript:

$(document).ready(function(){
    var test1 = new OutputHTMLChunk();
    test1.setClass('test');
    test1.setHTMLContent('Test');
    $('#main_container').append(test1.getOutputArea());

    var test2 = new OutputHTMLChunk();
    test2.setClass('wooo');
    test2.setHTMLContent('This is test2');
    $('#main_container').append(test2.getOutputArea());
    $('#main_container').append(test1.getOutputArea());
});

var OutputHTMLChunk = (function(){

    var _part1 = '<div class="';
    var _outputClass = 'output_area';
    var _part2 = '">';
    var _part3 = '</div>';
    var _HTMLContent = '';

    function OutputHTMLChunk(){

    }

    OutputHTMLChunk.prototype.setClass = function(classValue){
        _outputClass = classValue;
    }

    OutputHTMLChunk.prototype.getClass = function(){
        return _outputClass;
    }

    OutputHTMLChunk.prototype.setHTMLContent = function(HTMLContent){
        _HTMLContent = HTMLContent;
    }

    OutputHTMLChunk.prototype.getHTMLContent = function(){
        return _HTMLContent;
    }

    var AssembleArea = function(){
        var output = _part1 + _outputClass + _part2 + _HTMLContent + _part3;
        return output;
    }

    OutputHTMLChunk.prototype.getOutputArea = function(){
        return AssembleArea();
    }

    return OutputHTMLChunk;
})();

Output:

<div class="test">Test</div>
<div class="wooo">This is test2</div>
<div class="wooo">This is test2</div>

So I read here that this is the reason that the second call of test1 is using the variable from test2, it's because the variables are not unique to the newly created objects.

Now if I follow that and change OutputHTMLChunk to the following, my output is still incorrect:

Javascript:

var OutputHTMLChunk = (function(){

    this._part1 = '<div class="';
    this._outputClass = 'output_area';
    this._part2 = '">';
    this._part3 = '</div>';
    this._HTMLContent = '';

    function OutputHTMLChunk(){

    }

    OutputHTMLChunk.prototype.setClass = function(classValue){
        this._outputClass = classValue;
    }

    OutputHTMLChunk.prototype.getClass = function(){
        return this._outputClass;
    }

    OutputHTMLChunk.prototype.setHTMLContent = function(HTMLContent){
        this._HTMLContent = HTMLContent;
    }

    OutputHTMLChunk.prototype.getHTMLContent = function(){
        return this._HTMLContent;
    }

    var AssembleArea = function(){
        var output = this._part1 + this._outputClass + this._part2 + this._HTMLContent + this._part3;
        return output;
    }

    OutputHTMLChunk.prototype.getOutputArea = function(){
        return AssembleArea();
    }

    return OutputHTMLChunk;
})();

Output:

<div class="output_area"></div>
<div class="output_area"></div>
<div class="output_area"></div>

All in all, what I really want from this is the following output:

<div class="test">Test</div>
<div class="wooo">This is test2</div>
<div class="test">Test</div>

Upvotes: 0

Views: 95

Answers (2)

Dan D.
Dan D.

Reputation: 74655

Note the differences:

  1. The _part variables are constants.
  2. The constructor OutputHTMLChunk sets the instance variables.
  3. Each of methods uses this.variable to access the instance variables.
  4. As AssembleArea is not a method on the object but it still needs the object we bind it to this for it by using AssembleArea.call(this) if it was a method we could have used this.AssembleArea().

In:

var OutputHTMLChunk = (function(){

    var _part1 = '<div class="';
    var _part2 = '">';
    var _part3 = '</div>';

    function OutputHTMLChunk(){
      this._outputClass = 'output_area';
      this._HTMLContent = '';
    }

    OutputHTMLChunk.prototype.setClass = function(classValue){
        this._outputClass = classValue;
    }

    OutputHTMLChunk.prototype.getClass = function(){
        return this._outputClass;
    }

    OutputHTMLChunk.prototype.setHTMLContent = function(HTMLContent){
        this._HTMLContent = HTMLContent;
    }

    OutputHTMLChunk.prototype.getHTMLContent = function(){
        return this._HTMLContent;
    }

    var AssembleArea = function(){
        var output = _part1 + this._outputClass + _part2 + this._HTMLContent + _part3;
        return output;
    }

    OutputHTMLChunk.prototype.getOutputArea = function(){
        return AssembleArea.call(this);
    }

    return OutputHTMLChunk;
})();

To make AssembleArea a method, rather ones above use the following definitions for AssembleArea and getOutputArea:

    OutputHTMLChunk.prototype.AssembleArea = function(){
        var output = _part1 + this._outputClass + _part2 + this._HTMLContent + _part3;
        return output;
    }

    OutputHTMLChunk.prototype.getOutputArea = function(){
        return this.AssembleArea();
    }

Perhaps the difference will be apparent.

Upvotes: 2

Bergi
Bergi

Reputation: 664579

You need to place instance-specific properties (and variables) in the constructor, not your class IEFE module.

var OutputHTMLChunk = (function(){
    function OutputHTMLChunk(){
        this._part1 = '<div class="';
        this._outputClass = 'output_area';
        this._part2 = '">';
        this._part3 = '</div>';
        this._HTMLContent = '';
    }

    OutputHTMLChunk.prototype.…
    OutputHTMLChunk.prototype.getOutputArea = function(){
        return this._part1 + this._outputClass + this._part2 + this._HTMLContent + this._part3;
    };
    return OutputHTMLChunk;
})();

Of course, those three "parts" are non instance-specific, you can make those "static" constant values in your class scope. However, there's actually no reason to do so as you're not using them in multiple locations, your code would be much clearer if you simply placed literals in your getOutputArea method.

Upvotes: 2

Related Questions