1

I realise that this has been asked but have researched and failed - sorry!

I want to implement encapsulation in JS as simply as possible. I realise that any 'var' in the class will be private.

I am simply unsure how to GET and SET values of any private var. In the example below the interface methods for GETTING and SETTING 'colour' do not work because those functions cannot access the private 'colour' property of the object. I cannot find a clear example showing me how to implement this.

I am not even sure that using '.prototype' is the best way to add those methods to the class.

Thank you!

<button onclick="testOOP()">Click me</button>

<script>
//<!-- 
function testOOP(){
var v1 = new vehicle(4, "red"); //setting new values during instantiation
var v2 = new vehicle(2, "blue");
showVehDetails(v1);
showVehDetails(v2);
v2.wheels=1;            //demonstrating no encapsulation
showVehDetails(v2);
v2.setcolour("orange");     //using an interface - fails
showVehDetails(v2);
}

    function showVehDetails(v){
        document.write("This vehicle is " + v.getcolour() + " and has " + v.getwheels() + " wheels.<br/>");
    }

    //*************'vehicle' - Class definition**************
    function vehicle(thewheels, thecolour){
        this.wheels = thewheels;            //public property
        var colour = thecolour;             //private property
    }   
    vehicle.prototype = {
        constructor: vehicle,
        getcolour: function(){
            return this.colour;         //but how to create a GETTER for colour?
        },
        getwheels: function(){
            return this.wheels;
        },
        setwheels: function(newwheels){
            this.wheels = newwheels;
        },
        setcolour: function(newcolour){   //and how to create a SETTER for colour?
            this.colour = newcolour;
        }
    }
    //************End class definition************************
   //-->
 </script>
Rich
  • 35
  • 4
  • mmm in javascript doest exist real classs, always prototype an inteherance – Álvaro Touzón Nov 21 '17 at 20:11
  • If you want to enable getting and setting, just make them public properties?! – Bergi Nov 21 '17 at 20:13
  • @Bergi, this is an academic exercise to find the simplest way to demonstrated encapsulation using JavaScript. I normally would work with public properties, or _properties. – Rich Nov 21 '17 at 23:42

1 Answers1

3

Any vars declared in a constructor will not exist outside of that constructor. You need to attach things to this in order for prototype methods to see it. JavaScript doesn't have a concept of private members.

function Vehicle(thewheels, thecolour){
  this.wheels = thewheels;
  this.colour = thecolour;
}

Vehicle.prototype = {
  getColour: function() {
    return this.colour;
  }
  // etc
};

...but you have to ask yourself, what benefits do you gain around putting getters/setters around these members? It is pretty rare to use the getter/setter pattern in JavaScript. Usually you just create public members. Using things like an _ prefix for members is the typical way to signal "I know this is accessible, but you're not supposed to modify this directly."

If you do want to make things truly "private," you'll need to do some tricks with closures:

function Vehicle(theWheels, theColor) {
  return {
    getColour: function() { return theColor; },
    setColour: function(value) { theColor = value; }
  };
}

...but the downside to this approach is every Vehicle object has its own copy of these functions; you don't gain the memory benefits of a prototype.

Update:

Also of note: if you do want to trigger logic on changing members by wrapping in methods, there are nicer ways to create getters and setters in modern JS:

function Vehicle(theWheels, theColor) {
  this._wheels = theWheels;
  this._color = theColor;
}

Vehicle.prototype = {
  get color() { return this._color; },
  set color(value) { this._color = value; console.log('Changed color'); },

  get wheels() { return this._wheels; },
  set wheels(value) { this._wheels = value; }
}

The caller just accesses .wheels and .color like normal properties, and it will invoke your methods.

Jacob
  • 77,566
  • 24
  • 149
  • 228
  • own methods can be mostly recycled, only the activation envelope would need to be unique per-instance, so there's not as much of a memory dis-advantage as one might expect here. – dandavis Nov 21 '17 at 20:35
  • I looked at 'get' and 'set' but they only seem to work with public properties. In the 'real' world I will use them; but in this academic exercise I cannot! – Rich Nov 21 '17 at 23:40
  • @Jacob Thank you! That works well - even if I do not understand how placing those functions in 'return' works. Is there any way to combine both solutions you provide? ie to use 'get' and 'set' with private (not just _hidden) properties? I have posted a follow-up question here: https://stackoverflow.com/questions/47431014/how-to-implement-validation-with-encapsulation – Rich Nov 22 '17 at 09:32