Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Classes & 'access modifiers' in javascript

Tags:

javascript

I am trying to understand how "classes" work in ES5 and how I can apply my knowledge of traditional, typed object oriented languages like Java to javascript.

In the following code sample I have commented with my questions.

var MyClass = (function () {

    // [What am I?] A private variable?
    var myVariable1

    // Constructor.
    function MyClass() {
        // Essentially a public variable.
        this.myVariable2 = 0;
    }

    // Public method returning myVariable1.
    MyClass.prototype.myMethod1 = function () {
        return myVariable1;
    };

    // Public method returning public variable.
    MyClass.prototype.myMethod2 = function () {
        return this.myVariable2;
    };

    // [What am I?] A private method?
    function myMethod3 () {
        return 0;
    }

    return MyClass;

}());

I am mostly wondering about the "private" stuff. Like, what happens if I have multiple instances of this class? Can they interfere with each others private variables and functions?

like image 337
datcat Avatar asked Jul 07 '16 10:07

datcat


People also ask

What are teaching classes?

The Classroom Assessment Scoring System™ (CLASS™) is an observational instrument developed at the School Center for Advanced Study of Teaching and Learning to assess classroom quality in PK-12 classrooms.

Is Google Classroom free for anyone?

"Google Classroom is available for free for schools that are using Google Apps for Education., but there's a paid G Suite Enterprise for Education tier that includes additional features, such as advanced videoconferencing features, advanced security and premium support.

How do I join a class in Classin?

Enter the classroom The “Enter” tab will show up 20 minutes before the lesson starts. You can click “enter” tab to enter into the classroom. Check your audio and video settings and preferences, and then click "Enter".


2 Answers

First I'll address this bit:

...and how I can apply my knowledge of traditional, typed object oriented languages like Java to javascript.

You can frequently get away with thinking of JavaScript as being a bit like Java/C#/etc., but if you do, A) It'll bite you at some point, because JavaScript is not like Java/C#/etc., it is fundamentally different even though it has some trappings that make it look similar; and B) You'll miss out on the true power of JavaScript by not knowing how to use its fundamentally-different nature. (How do I know? I did exactly that, came from a Java [and even C++] background and assumed JavaScript was similar.)

That's not remotely meant as any form of criticism, it's just a word to the wise. Try to learn in depth how JavaScript prototypical inheritance and closures work, and you'll find that the way you solve problems will be slightly different than the way you would in Java/C#/etc.

Answers inline:

var MyClass = (function () {

    // [What am I?] A private variable?
    // ==> A private *class* variable (static variable). Not instance-specific.
    var myVariable1

    // Constructor.
    function MyClass() {
        // Essentially a public variable.
        // ==> A public field/property/variable, choose your terminology. :-)
        // ==> The Java spec calls them both fields and variables (oddly).
        // ==> In JavaScript, they're called properties.
        this.myVariable2 = 0;
    }

    // Public method returning myVariable1.
    // ==> Correct, but note that myVariable1 is shared across all instances
    MyClass.prototype.myMethod1 = function () {
        return myVariable1;
    };

    // Public method returning public variable.
    // ==> Yes, note that this one is returning an instance-specific field/property/variable
    MyClass.prototype.myMethod2 = function () {
        return this.myVariable2;
    };

    // [What am I?] A private method?
    // ==> A private *class* method (static method), yes.
    function myMethod3 () {
        return 0;
    }

    return MyClass;

}());

I am mostly wondering about the "private" stuff. Like, what happens if I have multiple instances of this class? Can they interfere with each others private variables and functions?

Yes, as I mentioned in the comments, they're class-wide. If you wanted to have a private "instance field", you'd have to declare it within your constructor, and create any functions that needed to have access to it within the constructor so that they closed over it:

function MyClass(arg) {
    var privateInstanceInfo = arg; // We could also just use arg directly

    this.accessThePrivateInstanceInfo = function() {
        return privateInstanceInfo * 42;
    };
}
MyClass.prototype.useOnlyPublicInfo = function() {
    // This cannot access `privateInstanceInfo` directly.
    // It *can* access the function `accessThePrivateInstanceInfo`
    // because that's public:
    return accessThePrivateInstanceInfo();
};
var c = new MyClass(2);
console.log(c.useOnlyPublicInfo()); // 84

This is all down to a concept called closures, which is outlined in detail in this question and its answers: How do JavaScript closures work? I'll also reference my article from several years ago Closures are not complicated, which while it uses some older terms for things compared to the latest specification, still describes the concepts just fine.

The inline-invoked function (IIFE) you've used as a wrapper creates a single execution context that all of the functions within it close over. That means they have live access to the variables and functions defined within that context, even after the function returns. Since you only call it once, there's only one context, and so only one myVariable1 and myMethod3.

In my example creating private instance information, we use the fact that a new context is created for each call to the constructor. That context isn't shared with anything else, and so becomes instance-specific.

There's a way to get near-private instance properties without having to define functions in the constructor, which is to use a randomly-selected name:

function makeRandomName() {
    var str = "";
    while (str.length < 10) {
        str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
    }
    return "__" + str;
}
var MyClass = (function() {
    var pseudoPrivatePropName = makeRandomName();

    function MyClass() {
        this[pseudoPrivatePropName] = 42;
    }

    // ....

    return MyClass;
})();

The code inside the IIFE knows the name of the property, the code outside of it doesn't. Now, malicious code could still find the property, but it's become much more challenging, particularly if you have more than one. (And if you have more than one, you need a better name allocator than the one above.)

In ES2015 (ES6) you could use

var pseudoPrivatePropName = Symbol();

...instead of having a name allocator.

Details in this somewhat-outdated article in my blog.

like image 171
T.J. Crowder Avatar answered Oct 12 '22 23:10

T.J. Crowder


Use # for private, and _ for protected.

like image 34
satriabadakbiru Avatar answered Oct 13 '22 01:10

satriabadakbiru