I'm learning JavaScript, and I can't understand why you'd make methods that aren't 'privileged,' that is, that aren't defined in the constructor but rather the class' prototype.
I understand the idea of encapsulation and all, but you never encapsulate parts of a class from the rest of it in most of the OO world.
When a function is defined in a constructor, a new instance of that function is created each time the constructor is called. It also has access to private variables.
var myClass = function() {
// private variable
var mySecret = Math.random();
// public member
this.name = "Fred";
// privileged function (created each time)
this.sayHello = function() {
return 'Hello my name is ' + this.name;
// function also has access to mySecret variable
};
}
When a function is defined on the prototype, the function is created only once and the single instance of that function is shared.
var myClass = function() {
// private variable
var mySecret = Math.random();
// public member
this.name = "Fred";
}
// public function (created once)
myClass.prototype.sayHello = function() {
return 'Hello my name is ' + this.name;
// function has NO access to mySecret variable
};
So defining a function on the prototype produces less objects which can give you better performance. On the other hand, public methods do not have access to private variables. Further examples and reasoning are available here: http://www.crockford.com/javascript/private.html
Related
I am reading a tutorial on public/private methods and can't make sense of the difference.
For a private method it says, "Private members are made by the constructor. Ordinary vars and parameters of the constructor becomes the private members."
function Container(param) {
this.member = param;
var secret = 3;
var that = this;
}
And for public methods, "this technique is usually used to initialize public instance variables. The constructor's this variable is used to add members to the object."
function Container(param) {
this.member = param;
}
As you can see both functions have a params paramater and a this.member = param;. Yet one is a private instance variable and the other is a public instance variable?
Understanding closures
Opening a new function body creates a new scope. This kind of scope is called a closure in JS. Variables created within that scope are accessible in all its sub-scopes. This means any var-created variable will be made visible to sub-functions. In this example, myTemporaryVar is accessible within subScope.
function myParentScope() {
var myTemporaryVar = "sample";
function subScope() {
console.log(myTemporaryVar);
}
return subScope();
}
When you use a function with the new keyword, a new closure is created for the current instance. Any function created within that constructor will keep access to the scope variables. In the next example, the function sayHi can access the temporary variable myName.
function Person(name) {
var myName = name;
this.sayHi = function() {
console.log("Hi, my name is " + myName + ".");
};
}
p = new Person("Bob");
p.sayHi(); // Hi, my name is Bob.
Actually, passed parameters are the same as var-created variables. The constructor's parameters are accessible within any sub-function. So the previous example can be reduced to:
function Person(name) {
this.sayHi = function() {
console.log("Hi, my name is " + name + ".");
};
}
p = new Person("Bob");
p.sayHi(); // Hi, my name is Bob.
This is a very unique feature of JavaScript because it means var-created variables still exist after the end of the function as long as there still is a way to access them.
Simulating Class-based OOP privacy
Closures can be "abused" to create private members with getter and setter functions.
function Person(name) {
this.getName = function() {
return name;
};
this.setName = function(newname) {
name = newname;
};
}
p = new Person("Bob");
console.log(p.getName()); // "Bob"
p.setName("Alice");
console.log(p.getName()); // "Alice"
p.name; // undefined
Why this is not true privacy
The getter and setter have to be created within the constructor in order to access the var-variable. Methods added in the common prototype-extension way can't access them. Prototype-methods have to use the setters and getters too, which makes the privacy of such variables quite useless.
Person.prototype.sayGoodMorning = function() {
console.log("Good morning, my name is " + this.getName() + ".");
}
The only way to directly access the variable within a method is to actually create it in the constructor. But putting all methods inside the constructor is extremely inefficient as a new copy of the methods will be created for each instance. This is why many people prefer simply using custom notation to identify would-be private members. The Google JavaScript Style Guide recommends placing an underscore at the end of the variable name.
function Person(name) {
this.name_ = name;
}
Person.prototype.getName = function() {
return this.name_;
}
Person.prototype.setName = function(name) {
this.name_ = name;
}
Person.prototype.sayGoodMorning = function() {
console.log("Good morning, my name is " + this.name_ + ".");
}
It is the responsibility of the programmer to not be stupid and access the would-be private members. Note that this goes in total contradiction with Crockford's opinion, but to each is own. I learned JS after Python, so the underscore privacy is like a second nature to me.
No one of this variable is trully private because if you instanciate Container you can access to secret variable :
function Container(param) {
this.member = param;
var secret = 3;
var that = this;
}
var container = new Container();
console.log(container.secret);
container.secret = "toto";
console.log(container.secret);
console.log(container);
Here the result :
As you can see you can access to secret without any "Getter/Setter".
If you want to do object javascript with truly private variable, look at this tutorial :
http://blog.stchur.com/2011/09/26/true-private-variables-in-javascript-with-prototype/
Refer to https://stackoverflow.com/a/387733/418439,
// Define a class like this
function Person(name, gender){
// Add object properties like this
this.name = name;
this.gender = gender;
}
// Add methods like this. All Person objects will be able to invoke this
Person.prototype.speak = function(){
alert("Howdy, my name is" + this.name);
}
// Instantiate new objects with 'new'
var person = new Person("Bob", "M");
// Invoke methods like this
person.speak(); // alerts "Howdy, my name is Bob"
How to define namespace as well?
You can just create a new object that contains all your classes/functions:
var myNamespace = {};
myNamespace.Person = function (name, gender) {
// Add object properties like this
this.name = name;
this.gender = gender;
}
myNamespace.Person.prototype.speak = function() {
alert("Howdy, my name is" + this.name);
}
// Instantiate new objects with 'new'
var person = new myNamespace.Person("Bob", "M");
// Invoke methods like this
person.speak(); // alerts "Howdy, my name is Bob"
MDN has an article explaining JavaScript namespacing.
How about
var namespace = {};
namespace.Person = function(name, gender) { ... };
var myPerson = new namespace.Person();
Check this ref:- here
var yourNamespace = {
foo: function() {
},
bar: function() {
}
};
...
yourNamespace.foo();
var MYNamespace = MYNamespace|| {};
MYNamespace.MyFirstClass = function (val) {
this.value = val;
this.getValue = function(){
return this.value;
};
}
var myFirstInstance = new MYNamespace.MyFirstClass(46);
alert(myFirstInstance.getValue());
jsfiddle: http://jsfiddle.net/rpaul/4dngxwb3/1/
I once made an example file (for my own use), so I'll share that here, maybe you will find it useful (warning: it contains more than just namespaces):
//http://www.crockford.com/javascript/private.html
//http://www.dustindiaz.com/namespace-your-javascript/
//http://appendto.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/
//adding the whole shabang to a namespace
var NameSpace = (function (params)
{
//initialising constructor with parameter
//call as "var testObject = new MyConstructor("test");"
//then accessing the public members: "testObject.publicMember = 123;"
function MyConstructor(param, param2)
{
//initialising public instance member variables
//these could also be added by calling "testObject.[newMemberName] = [value];" to create a new property
//can be accessed by private and public methods
this.publicMember = param;
this.secondPublicMember;
//initialising private instance member variables
//private variables can only be added at creation time
//can be accessed by private methods, but not by the object's own public methods.
var privateMember = param2;
var secondPrivateMember;
//creates a private function, NOT accessible by public functions (ONLY by internal private and privileged ones)
//has access to all private/public functions and variables?
function PrivateFunction(params)
{
//place code here
//note this notation is short for "var PrivateFunction = function PrivateFunction(params) {};"
}
//creates a privileged function, accessible by all public (and private?) functions
//has access to all private/public functions and variables
this.PrivilegedFunction = function (params)
{
//place code here
};
}
//creating a public function, accessible by calling "testObject.PublicFunction(params)"
//can also be done by calling "testObject.[newFunctionName] = function (params) {};"
//has access to all public members and functions
MyConstructor.prototype.PublicFunction = function (params)
{
//place function code here
};
};
Again, this was just a mockup I made for myself using the links mentioned at the top.
So this is an example of the famous JavaScript Module Pattern:
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 right? This logs '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, which is not accessible for the outside world. The last part works, I can not access _name from outside the closure.
But if I do this:
var paul = new Person('Paul');
var bran = new Person('Bran');
paul.kill();
bran.kill();
This will then log 'Bran has been shot', twice. No Paul there. So _name is actually shared with all instances of my Person object. That's what I would define as a 'static variable', although it's also not accessible from outside.
So is there any way to create a real private member variable with the module pattern? One that is not static.
Something that also happens a lot is defining this._name inside the constructor function, but that kills the private part, it's now accessible from outside:
function Person(name) {
this._name = name;
}
var bran = new Person();
console.log(bran._name); // yep, accessible
Question:
So. Private is not really private, just static. How do we create a real private member variable with the module pattern? A variable which belongs to an instance, which is not static, and a variable which is not accessible from the outside.
You're right; _name is more of a static variable. It is kept in the closure that contains the constructor, so every use of the constructor will use that same variable. And remember, this has nothing to do with classes, and everything to do with closures and functions. It can be pretty handy, but it isn't how you do private members.
Unsurprisingly, Douglas Crockford has a page devoted to private members in Javascript.
In order to make private members, you have to go 'one level deeper'. Don't use a closure outside of the constructor; use the constructor as the closure. Any variables or methods defined inside the constructor are obviously not usable by the outside world. In fact, they aren't accessible by the object, either, so they are rather extremely 'private'.
We want to use our private members though. :) So what to do?
Well, in the constructor, do this:
var Klass = function () {
var private = 3;
this.privileged = function () { return private; };
};
and then:
var k = Klass();
console.log(k.privileged()); // 3
See how that's using the constructor as a closure? this.privileged lives on, attached to the object, and thus private lives on, inside this.privileged's closure.
Unfortunately, there's one problem with private and privileged methods in Javascript. They must be instantiated from scratch each time. There is no code sharing. That's obviously what we want with private members, but it isn't ideal for methods. Using them slows down object instantiation and uses more memory. It's something to keep in mind when/if you run into efficiency problems.
"Real private member variables" and prototype based methods do not play nice together. The only way achieve what you want is to create all 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 since each instance has a unique version of the kill function.
Conventionally, the underscore prefix is used for semi-private instance properties, as long as the data exposed is not a security risk. Most consumers of your javascript code know not to mess with underscore prefixed properties.
Some more reading you may find useful is here.
The problem is that your _name variable is outside the Person scope and shared between all Person instances. Do something like the following instead :
(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();
A variable that needs to be private in instance scope has to be in such scope, for example:
function Person(name) {
var _name = name;
this.kill = function() {
console.log( _name + ' has been shot' );
}
}
A drawback of this is that kill has to be defined in a scope that also has access to the private variable.
In order to create a private var, you should put it inside the constructor, so your code would be 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();
Assuming this code javascript code
(function(){
NameSpace = new function(){} //global namespace
NameSpace.Apple = function(p_color){
var AppleInstance = this; //clarity..
AppleInstance.color = p_color;
return {
/**************
/ Public method
/**************/
//Here, we only return an access to the Method Eat
Eat : NameSpace.Apple.prototype.Eat
}
}
//Will be public
NameSpace.Apple.prototype.Eat = function(){
var AppleInstance = this; //clarity..
console.log("I'm eating a " + AppleInstance.color + " apple !")
}
//Will be private
NameSpace.Apple.prototype.PrivateMethod = function(){
var AppleInstance = this; //clarity..
console.log("This is a private method");
}
})()
new NameSpace.Apple("blue").Eat();
//I'm eating a undefined apple !
As you can see, I have a class in a Namespace that contains 1 private variable, 1 private method and 1 public method. BUT when accessing to my public method, this one don't have access to the variable of the class.
I know that this is because of the :
return {
/*...*/
}
But is there a way that my public prototype method will access to my private variable (in my original code I want a Constant..) without giving access to it with the return.
If i return the properties in the return, the prototype methods will have access to it but not otherwise.
Thanks.
Nope. The two strategies are somewhat incompatible. Which is why private properties are usually public, but prefixed with an underscore, when using prototypes.
Namespace.Apple = function(p_color){
this._color = p_color;
};
Namespace.Apple.prototype.eat = function(){
console.log("I'm eating a " + this._color + " apple !")
};
This tells JS developers using this code that they should not mess with the _color property, as it's for internal use.
That said, you have other big problems here...
Namespace.Apple = function(p_color){
var AppleInstance = this; //clarity..
AppleInstance.color = p_color;
return {
/**************
/ Public method
/**************/
//Here, we only return an access to the Method Eat
Eat : NameSpace.Apple.prototype.Eat
}
}
This doesn't do what you think. When a constructor returns an object, the instance created with new is discarded. So you will not end up with an instance of Apple. Instead you get a plain object that looks like this:
{ Eat: Namespace.Apple.prototype.Eat }
So the object you assigned a color to? It's gone.
This method is not private.
//Will NOT be private
Namespace.Apple.prototype.PrivateMethod = function(){
var AppleInstance = this; //clarity..
console.log("This is a private method");
}
Everything on the prototype is public. Everything.
And a note about conventions.
var AppleInstance = this; //clarity..
I don't think is clear at all. this is used in instance methods to mean this instance. Any obfuscation of that hurts readability.
And please, save capital letter variable names for constructors (Eat bad!, Apple good!, AppleInstance bad!), also for readability. As calling a constructor without the new keyword can have some bizarre consequences.
To avoid this, and still have private variables and methods, you don't use the prototype at all. You set up all variables and methods as functions from within the constructor, building the instance piece by piece.
var Namespace = {};
Namespace.Apple = function(color){
// color form the arguments is a local variable, bound to the methods created below
var somePrivateVar = 'privateData!'; // private instance variable
// public method, with access to private instance vars
this.eat = function(){
console.log("I'm eating a " + color + " apple!");
};
// public method, which calls private method
this.doSomethingPrivate = function() {
console.log('calling private method for you');
privateMethod()
}
// private method
var privateMethod = function(){
console.log("This is a private method for a " + color + " apple!");
};
// instance is auto-returned, no return needed.
}
var apple = new Namespace.Apple('red');
apple.eat(); // I'm eating a red apple!
apple.doSomethingPrivate(); // calling private method for you
// This is a private method for a red apple!
apple.privateMethod() // <exception> apple.privateMethod is undefined
Only thing to note about this approach is that it can be much slower, and use more memory, than when you use prototypes. Functions on the prototype are shared between all instances, so you only need to create and store a single function for a method, and every instance will execute that function object.
With the above approach every single instance creates and stores a new copy of each method function. And each function has privileged access to the scope of that instances constructor, allowing you private variables and methods. If you only plan on having a few instances, this difference may not make a lot of difference. But if you plan on have a very large number of instances, the performance difference may become very important.
To achieve the encapsulation you're after the following structure would be advised:
(function(){
NameSpace = new function(){} //global namespace
NameSpace.Apple = function(p_color){
var AppleInstance = this; //clarity..
var color;
AppleInstance.color = p_color;
this.Eat = function(){
/**************
/ Public method
/**************/
//Here, we only return an access to the Method Eat
alert("I'm eating a " + AppleInstance.color + " apple !")
}
//Will be private
var private = function(){
var AppleInstance = this; //clarity..
alert("This is a private method");
}
function constructor(p_color){
AppleInstance.color = p_color;
}
constructor(p_color)
}
})()
new NameSpace.Apple("blue").Eat();
//I'm eating a blue apple !
new NameSpace.Apple("blue").private();
// Exception raised
I'm never in favor of disregarding the this variable for a local copy, it has important implications for scope within the calling structure of JS objcects and gives a clue to developers as to where these might have changed.
As an aside: Namespace.Apple.prototype.PrivateMethod will not be a private method as everything exposed through a prototype is public.
I've read that using Object.prototype to attach functions to custom JavaScript objects is more efficient than the "traditional" method of this.foo = function(). The problem I've run into is scope. I want these public methods to be able to access private variables of the object. What I ended up doing was this:
function Foo(){
var id = 5;
Foo.prototype.bar = function(){
alert(id);
};
}
var x = new Foo();
x.bar();
I nested the prototype declaration inside the object definition. This works and seems to solve the problem. Is there any reason to NOT do this? Is there a better or more standard way to accomplish this?
UPDATE
Based on some of the responses I've received I guess I need to mention that I'm fully aware that there is no concept of a private variable in JavaScript. I use the term private here meaning not accessible outside the current scope because it's easier to say and write and I assume that anyone trying to answer this question would know what was meant by me using the term private.
While your idea works, it may not be working as you expect. I believe your overwrites the prototype each time a new Foo is instantiated. It would potentially change the bar() method for all instances of Foo each time you create a new Foo. Oops.
Here's an example of using fake private variables for someone to "lie" about their real age.
Here is the standard way to do this:
function Person(name, age) {
this._age = age; // this is private by convention only
this.name = name; // this is supposed to be public
}
Person.prototype.sayHiTo = function(person) {
console.log("Hi " + person.name + ", my name is " + this.name);
}
Person.prototype.age = function() {
return this._age - 3;
}
var j = new Person("Jay", 33);
var k = new Person("Kari", 26);
j.sayHiTo(k) // Hi Kari, my name is Jamund
k.age(); // 23
You can use privileged methods to access the private members.
More info here: http://javascript.crockford.com/private.html
However, IMO it's really not worth it. It's cumbersome and it cripples classical inheritance.
And for what? To "shield" users from accessing your private members directly?
It's JS, they have the source and the means to access them anyway, it's really not worth the effort. Underscoring pseudo private members is enough.
There is no private in JavaScript, just do things properly
var Foo = {
bar: function () {
console.log(this._id)
},
constructor: function () {
this._id = 5
return this
}
}
var x = Object.create(Foo).constructor()
x.bar()
here how you can fake it. This is Animal class
(function(window){
//public variable
Animal.prototype.speed = 3;
//public method
Animal.prototype.run = function(){
//running
}
//private method
//private method
function runFaster(){
//run faster
}
//private var
//private var
var legCount = 4;
}(window));