4

How do i declare protected variable. Let me give an example here

// Constructor
function Car(){

   // Private Variable
   var model;
}

// Public variable
Car.prototype.price = "5 Lakhs";

// Subtype
function Indiancar(){
}

// Prototype chaining
Indiancar.prototype = new Car();


// Instantiating Superclass object
var c = new Car();

// Instantiating subclass object
var ic = new Indiancar();

in this I would like to have a variable that is accessible as ic.variabl that is also present in car class.

indianwebdevil
  • 4,879
  • 7
  • 37
  • 51
  • 3
    There is no such thing as a public, private, or protected variable in JavaScript. Stop trying to write JavaScript like Java or C#. – Matt Ball Sep 23 '11 at 18:59
  • 3
    That's not entirely true. Via closure, you can create accessor and setters for 'protected' variables without exposing it directly. – Tejs Sep 23 '11 at 19:01
  • @Tejs: Yes, but that does not change the fact that JavaScript has not concept of property visibility. What you described is a "hack". to achieve something similar. But actually this introduces other problems... – Felix Kling Sep 23 '11 at 19:15
  • I totally understand as its a way of mimicing or emulating these access specifiers. – indianwebdevil Sep 23 '11 at 19:24

3 Answers3

6

You would do something like this:

var Base = function()
{
    var somePrivateVariable = 'Hello World';

    this.GetVariable = function()
        {
            return somePrivateVariable;
        };

    this.SetVariable = function(newText)
        {
            somePrivateVariable = newText;
        };
};

var Derived = function()
{
};

Derived.prototype = new Base();

var instance = new Derived();

alert(instance.GetVariable());
instance.SetVariable('SomethingElse');
alert(instance.GetVariable());

Assuming I understood your question correctly.

EDIT: Updating with true 'private' variable.

Tejs
  • 40,736
  • 10
  • 68
  • 86
  • Your code gave me the inspiration for this minified version that I use in PHP code to make sure the 3rd party doesn't change the value `var e = function(){var i = '$data';this.z = function(){return i;};};var g = function(){};g.prototype = new e();t = new g();` The variable then can by called by t.z() or whatever letter you give it. – Tschallacka Sep 11 '12 at 14:25
  • 7
    Hmm.. it seems like you're creating private and public variables/methods well enough, but nothing here is really protected. For example: `var busyBody = new OtherGuy(); var innocentBase = new Base(); busyBody.stolenVar = innocentBase.GetVariable();` In other words, nothing is stopping a 3rd party from calling your `GetVariable` method on a `Base` instance. – eschwartz Nov 01 '12 at 13:45
  • Correct, `GetVariable` and `SetVariable` are public methods. `somePrivateVariable` is not exposed directly. – Tejs Nov 01 '12 at 14:33
  • Excellent. But what was the point of creating a derived class? Why not just say... var instance = new Base(); – Niko Bellic Feb 24 '15 at 19:02
5

There is a way to define protected variables in JavaScript:

A constructor function in javascript may return any object (not necesserily this). One could create a constructor function, that returns a proxy object, that contains proxy methods to the "real" methods of the "real" instance object. This may sound complicated, but it is not; here is a code snippet:

var MyClass = function() {
    var instanceObj = this;
    var proxyObj = {
        myPublicMethod: function() {
            return instanceObj.myPublicMethod.apply(instanceObj, arguments);
        }
    }
    return proxyObj;
};
MyClass.prototype = {
    _myPrivateMethod: function() {
        ...
    },
    myPublicMethod: function() {
        ...
    }
};

The nice thing is that the proxy creation can be automated, if we define a convention for naming the protected methods. I created a little library that does exactly this: http://idya.github.com/oolib/

slobo
  • 761
  • 2
  • 9
  • 16
0

As has been said, javascript doesn't have protected variables.

In the 10 years since this question was written, Typescript has become a thing, and people interested in OOP in javascript should check it out! It does support protected variables.

That said, I'd like to throw my hat into the ring and provide a method for emulating protected variables using plain javascript, since this is a top Google search result and the top-voted answer as of writing doesn't really fit the bill.

// Declare objects within an anonymous function to limit access.
var objectRefs = (function() {
  // This is the object we want to inherit from.
  function Base(param1, _protected) {
    var _public = this;
    var _protected = _protected || {};
    var _private = {};

    // Declare some variables
    _public.shared = "Anyone can access this!";
    _protected.inherited = "This is protected";
    _private.secretVar = "Children cannot access this.";

    // Let's try a few functions.
    _public.foo = function() {
      // We can access protected and private functions here. This would
      // not be possible if we attached it to the prototype.
      console.log(_protected.inherited);
      console.log(_private.secretVar);
      _private.secret();
    };

    _protected.bar = function() {
      // One thing to watch out for: private functions called after
      // construction do NOT have access to the object via 'this'. This is
      // masked by the fact that I assigned it to the '_public' var.
      // More reading: https://stackoverflow.com/q/20279484/3658757
      console.log(_public.shared);
    };

    _private.secret = function() {
      // The same warning in _protected.bar applies here too.
      console.log(_public.shared);
    };
  }

  // Inherits from Base
  function Derived(param1, _protected) {
    var _public = this;
    var _protected = _protected || {};
    var _private = {};

    // Inherit (ready for the magic?)
    Base.call(this, param1, _protected);

    // Since we passed a reference to the "_protected" object as an argument
    // to the Base object, it has been attaching all of its protected
    // variables to it. We can now access those variables here:

    // Outputs "This is protected"
    console.log(_protected.inherited);

    // We can also access protected functions:
    _protected.bar();

    // We can even override protected variables and functions.
    _protected.inherited = "New value!";

    // We cannot access private variables belonging to Base.
    // This fails:
    // console.log(_private.secretVar);
  }

  // We don't want to allow public access to the constructors, because this
  // would let outside code pass in a '_protected' var. Instead, we create new
  // objects that accept all params minus '_protected', and inherit from the
  // target object.
  return {
    Base: function(param1) {
      Base.call(this, param1);
    },
    Derived: function(param1) {
      Derived.call(this, param1);
    }
  };
}());

// Assign the constructors to variables for clarity.
var Base = objectRefs.Base;
var Derived = objectRefs.Derived;

// This is how you construct the object.
var newDerived = new Derived("param1");

// Public functions are accessible.
newDerived.foo();

// Protected functions are not. These fail:
// newDerived.bar();
// newDerived.protected.bar();

So that was fun! This structure makes protected variables function the way you'd expect: inheriting objects can access them, but they're inaccessible from the outside.

For reference, here's what the above code looks like in Typescript:

class Base
{
    // Declare some variables
    public shared: string = "Anyone can access this!";
    protected inherited: string = "This is protected";
    private secretVar: string = "Children cannot access this.";

    constructor(param1: string) {
        // We're not using param1; it's only there as an example.
        // If we didn't need any constructor code, we could leave this out.
        
        // Note that Typescript has type checking (hence the name)
    }

    // Let's try a few functions.
    public foo(): void {
        console.log(this.inherited)
        console.log(this.secretVar)
        this.secret();
    }

    protected bar(): void {
        console.log(this.shared);
    }

    private secret(): void {
        console.log(this.shared);
    }
}

class Derived extends Base {
        constructor(param1: string) {
            super(param1);

            // Outputs "This is protected"
            console.log(this.inherited);

            // We can also access protected functions:
            this.bar();

            // We can even override protected variables and functions.
            this.inherited = "New value!";
        }
}

// This is how you construct the object.
var newDerived = new Derived("param1");

// Public functions are accessible.
newDerived.foo();

// Protected functions are not. This fails:
// newDerived.bar();

Structurally, this is much clearer. As you're coding, you'll be given an error if you try to access a protected variable from outside the object.

But be aware: if you need the compiled javascript to limit outside access to those variables, Typescript won't do that for you. Here's what the compiled output looks like:

"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Base = (function () {
    function Base(param1) {
        this.shared = "Anyone can access this!";
        this.inherited = "This is protected";
        this.secretVar = "Children cannot access this.";
    }
    Base.prototype.foo = function () {
        console.log(this.inherited);
        console.log(this.secretVar);
        this.secret();
    };
    Base.prototype.bar = function () {
        console.log(this.shared);
    };
    Base.prototype.secret = function () {
        console.log(this.shared);
    };
    return Base;
}());
var Derived = (function (_super) {
    __extends(Derived, _super);
    function Derived(param1) {
        var _this = _super.call(this, param1) || this;
        console.log(_this.inherited);
        _this.bar();
        _this.inherited = "New value!";
        return _this;
    }
    return Derived;
}(Base));
var newDerived = new Derived("param1");
newDerived.foo();

As you can see, not only are the protected variables public, but so are the private ones!

If you need encapsulation in the browser, then you'll have to stick with workarounds like I outlined in the first chunk of code. If you're using encapsulation to help you reason about the code, Typescript is the way to go.

Obscerno
  • 193
  • 5
  • 16