JavaScript module template - private variables versus static variables

So, this is an example of the famous JavaScript module template:

var Person = (function() { var _name; // so called 'private variable' function Person(name) { _name = name; } Person.prototype.kill = function() { console.log(_name + ' has been shot'); }; return Person; })(); var paul = new Person('Paul'); paul.kill(); 

So far so good? This leads the magazine 'Paul has been shot' to the console, which is what we want.

But.

Is _name really a private variable? I would define a private variable as a variable that belongs to an instance of an object that is inaccessible to the outside world. The last part works, I cannot access _name due to closing.

But if I do this:

 var paul = new Person('Paul'); var bran = new Person('Bran'); paul.kill(); bran.kill(); 

Then 'Bran has been shot' will be recorded, twice. There is no Paul. That way, _name is actually shared by all instances of my Person object. This is what I would call a "static variable", although it was also not accessible from the outside.

So, is there a way to create a real private member variable with a module template? One that is not static.

Something that happens a lot also defines this._name inside the constructor function, but it kills the private part, now it is accessible from the outside:

 function Person(name) { this._name = name; } var bran = new Person(); console.log(bran._name); // yep, accessible 

Question:

So. Private is not very private, just static. How to create a real private member variable with module template? A variable that belongs to an instance that is not static, and a variable that is not accessible from the outside.

+6
source share
5 answers

You're right; _name is more of a static variable. It is stored in a closure containing the constructor, so every use of the constructor will use the same variable. And remember that this has nothing to do with classes, and everything related to closure and functions. It can be very convenient, but you are not making private members.

Unsurprisingly, Douglas Crockford has a private members page in Javascript .

To make private members, you need to go "one level deeper." Do not use closure outside the constructor; use the constructor as a closure. Any variables or methods defined inside the constructor, obviously, cannot be used by the outside world. In fact, they are also inaccessible to the object, so they are rather unusual 'private'.

We want to use our private members. :) So what to do?

Well, in the constructor do the following:

 var Klass = function () { var private = 3; this.privileged = function () { return private; }; }; 

and then:

 var k = Klass(); console.log(k.privileged()); // 3 

See how using constructor as a closure? this.privileged lives, attaches to the object, and thus private lives, inside this.privileged closure.

Unfortunately, there is one problem with private and privileged methods in Javascript. Each time they must be created from scratch. No code exchange. It is obvious that we want with private members, but it is not ideal for methods. Using them slows down the creation of objects and uses more memory. This is something to keep in mind when / if you run into performance problems.

+6
source

"Real private member variables" and prototypes based on methods do not play together. The only way to achieve what you want is to create all the methods in the constructor.

 var Person = (function() { function Person(name) { this.kill = function() { console.log(name + ' has been shot'); }; } return Person; })(); var paul = new Person('Paul'); var bran = new Person('Bran'); paul.kill(); // Paul has been shot bran.kill(); // Bran has been shot 

But this will use more memory and be slower as each instance has a unique version of the kill function.

Typically, the underscore prefix is ​​used for the properties of a semi-private instance if the data is not at risk. Most users of your javascript code know that they do not spoil the prefix properties of the underscore.

You can find a more detailed reading here.

+2
source

The problem is that your variable _name is outside the scope of Person and is shared between all instances of Person. Instead, do the following:

 (function() { var Person = function(name) { var _name = name; // so called 'private variable' this.getName = function() { return _name; } this.kill = function() { console.log(this.getName() + ' has been shot'); } } /*Alternative Person.prototype.kill = function() { console.log(this.getName() + ' has been shot'); };*/ window.Person = Person; })(); var paul = new Person('Paul'); var bran = new Person('Bran'); paul.kill(); bran.kill(); 
+2
source

A variable that must be private in an instance scope must be in that scope, for example:

 function Person(name) { var _name = name; this.kill = function() { console.log( _name + ' has been shot' ); } } 

The disadvantage of this is that kill must be defined in an area that also has access to the private variable.

0
source

To create a private var, you have to put it inside the constructor, so your code will look like this:

 var Person = (function() { function Person(name) { // since name is a param, you don't even have to create a _name var // and assign name to it this.getName = function () { return name; }; } Person.prototype.kill = function() { console.log(this.getName() + ' has been shot'); }; return Person; })(); var paul = new Person('Paul'); paul.kill(); 

You can also declare .kill inside the constructor:

 var Person = (function() { function Person(name) { this.kill = function() { console.log(name + ' has been shot'); }; } return Person; })(); var paul = new Person('Paul'); paul.kill(); 
0
source

All Articles