0

This sample achieves private variables of rectangle. The variables myLength and myWidth are different for different instances. So why is this not recommended approach?

var rectangle = function() {
    var myLength = 8;
    var myWidth = 6;

    var getMyLength = function () {
        return myLength;
    };

    var setMyLength = function (value) {
        myLength = value;
    };

    var getMyWidth = function () {
        return myWidth;
    };

    var setMyWidth = function (value) {
        myWidth = value;
    };

    var drawFigure = function() {
        console.log("Draw invoked for figure: " +
            getMyLength() + " * " + getMyWidth());
    };

    return {
        getMyLength: getMyLength,
        setMyLength: setMyLength,
        getMyWidth: getMyWidth,
        setMyWidth: setMyWidth,
        drawFigure: drawFigure
    }
};

Then we use it as follows:

var myRectangle = new rectangle();

myRectangle.drawFigure();           // Draw invoked for figure: 8 * 6

myRectangle.setMyLength(3);

myRectangle.setMyWidth(5);

myRectangle.drawFigure();           // Draw invoked for figure: 3 * 5

var myRectangle1 = new rectangle();

myRectangle1.drawFigure();          // Draw invoked for figure: 8 * 6
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
bschandramohan
  • 1,968
  • 5
  • 27
  • 52
  • 4
    *"So why is this not recommended approach?"* Who said it's not recommended? This is a very common approach when you need to protect variables. – cookie monster Jun 21 '14 at 04:03
  • 1
    ...and `new rectangle();` can just be `rectangle();`. No point to allocating a new object if you're going to ignore it and return a different one. – cookie monster Jun 21 '14 at 04:04
  • @cookiemonster Thanks. I see lots of examples using this.length and this.width instead of var. Why do you use this.methods then? One example page I am using to learn: http://phrogz.net/JS/classes/OOPinJS.html – bschandramohan Jun 21 '14 at 04:05
  • 1
    If they aren't worried about protecting the variables, then they would likely elect to use prototypal inheritance since then the methods that operate on the object properties don't need to be recreated every time they create a new object. – cookie monster Jun 21 '14 at 04:08
  • So, it's mainly for performance reasons. Since drawFigure gets created for every object, you avoid it using rectangle.prototype.drawFigure. And for prototype method to work, you require this.variables. Is that a correct understanding? Thanks again. – bschandramohan Jun 21 '14 at 04:11
  • 2
    Yes, the prototyped methods can only operate on public properties of the object. They have no special access to the variables outside of their typical variable scope. See some of the caveats from that page, like: *"Private functions and privileged methods, like private variables and public properties, are instantiated with each new object created. So each time new Person() is called, new copies of makeOlder(), toString(), getName(), eat(), exercise(), weigh(), getRace(), getAge(), and muchTimePasses() are created. For every Person, each time..."* – cookie monster Jun 21 '14 at 04:12
  • 1
    Function members are usually put on the prototype in JavaScript, it'll save resources and can implement certain patterns more easily. But prototype methods cannot access instance specific privates because they are in closure scope. More details and a pattern for protected here: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Jun 21 '14 at 05:04
  • 1
    what have you actually accomplished here? now your object is more annoying to work with. – Eevee Jun 21 '14 at 05:13
  • OKay... Just got to know this is IIFE or RME pattern discussed in the book "Object Oriented Javascript" by Nicholas Zakas. – bschandramohan Jun 21 '14 at 06:05

1 Answers1

2

In my opinion private variables are overrated. Do you really need to hide things from the programmer? No. Even if you made all your private variables public what difference would it make? In fact I advocate making everything public because:

  1. It would make debugging easier. If you console.log an object then you can inspect its public properties which makes debugging easier because you can see the state of the object.
  2. You don't need to create unnecessary closures. If you want a private variable and also want it to be accessible by a public method then you have to create a closure (one for each instance). If you make your properties public then you don't need closures. You can put the methods on the prototype. Hence you'll only have one method per class, shared by all the instances.
  3. You don't need to create unnecessary getters and setters. What's the point of making a variable private and then allowing anybody to modify it using getter and setter functions? You might as well make the variable public.

    Getters and setters, in my humble opinion, are only useful for phantom properties:

    var Person = defclass({
        constructor: function (firstName, lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        },
        getFullName: function () {
            return this.firstName + " " + this.lastName;
        },
        setFullName: function (fullName) {
            var name = fullName.split(" ");
            this.firstName = name[0];
            this.lastName = name[1];
        }
    });
    

Hence in my opinion you should have written your Rectangle class as follows:

var Rectangle = defclass({
    constructor: function (width, height) {
        this.width = width;
        this.height = height;
    }
});

We then use it as follows:

var rectA = new Rectangle(8, 6);

console.log(rectA);              // { width: 8, height: 6 }

rectA.width  = 3;
rectA.height = 5;

console.log(rectA);              // { width: 3, height: 5 }

var rectB = new Rectangle(8, 6);

console.log(rectB);              // { width: 8, height: 6 }

Finally, the definition of defclass:

function defclass(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

So that's just my two cents on the way you should create objects in JavaScript.

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • 1
    Getters and setters are also useful when you need to restrict/sanity check the value that is being set. – Jeremy J Starcher Jun 21 '14 at 04:52
  • 1
    That depends upon whether you want your validation logic to be a part of your class. In my opinion validation logic doesn't belong to the class itself. It easier to simply assume that the any modification to an object is valid rather than code defensively. I would rather write a separate function for validation: `if (isValid(value)) object.property = value;`. In doing so you're separating your validation logic from the setter allowing you to reuse it in other places. In addition you make the validation itself explicit, reduce the complexity of your class and reduce the coupling between them. – Aadit M Shah Jun 21 '14 at 04:59
  • 2
    Hide implementation from your public api. In other languages where your program depends on tons of other modules it only needs one bad programmer who hacked and depends on implementation. When a module is updated it can break the whole thing even though the updated part has the same public api. That being said; I don't use it much either – HMR Jun 21 '14 at 05:08