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>
Any var
s 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.