Im reading this article from Crockford:
http://www.crockford.com/javascript/private.html
And in the section where he talks about Private, he says:
Private members are made by the constructor. Ordinary vars and parameters of the constructor becomes the private members.
Now if I do this in my script:
"use strict"
function car(brand) {
this.brand = brand;
var year = 2012;
var color = "Red";
}
var bmw = new car("BMW");
console.log(bmw.brand); // BMW -> VISIBLE ?!?
I can easily access property that was passed through constructor!
Can someone explain this better, shouldn't these variables passed through constructor be private?
Thanks!
I think you've mis-interpreted that bit of information. It doesnt say that private methods are those that are "passed through" the constructor, it says its those that are "made by" the constructor.
To be clear, look at this:
function car(brand) {
var year = 2012;
var color = "Red";
}
That has 3 private variables. brand,year and color. By adding this line
this.brand = brand
You are creating a public property and assigning it the value from your private variable. That you've named the public property and the private variable the same thing is neither here nor there, if it makes it clearer think of it as
this.publicBrand = brand
It's not that you can access values passed into the constructor. What you've done is set this.brand equal to the value passed in the constructor. Therefore, the publicly available brand now has the same value that was passed in. The local brand inside the constructor != this.brand until you set it.
Everything you assign to the context (this inside function) is public available. Be aware that the context is the window object if you call the function without new
"use strict"
function car(brand) {
this.brand = brand; //Public (can be accessed from outside because it is attached to the context/this)
var year = 2012; //Private (inside function only)
var color = "Red"; //Private (inside function only)
}
var bmw = new car("BMW");
console.log(bmw.brand); // BMW -> VISIBLE -> this.brand = brans
Solution: Using closures to create a inaccessable "private" scope.
"use strict";
(function (parent) {
(function (parent) {
var instances = {};
parent.getPrivateInstance = function (c) {
return instances[c];
};
parent.setPrivateInstance = function (c, value) {
instances[c] = value;
};
} (this));
parent.Class = function (name) {
setPrivateInstance(this, {
name: name
});
};
parent.Class.prototype.logName = function () {
console.log(getPrivateInstance(this).name);
};
})(window);
var c = new Class("test");
c.logName(); // "test"
console.log(c.name); // undefined
Caution: Memory leak
This will create a situation wherein the garbage collector will no longer clear the memory associated with the instances of Class because it they will always be referenced, which results in a memory leak.
To combat this we'll have to manually remove the reference made to the instances of Class. This can be done by adding one piece of code after the parent.setPrivateInstance section and one piece of code after the parent.Class.prototype.logName section. Those pieces of code would look like this:
parent.deleteFromMemory = function (c) {
delete instances[c];
};
parent.Class.prototype.deleteFromMemory = function () {
deleteFromMemory(c);
};
Usage
c = c.deleteFromMemory();
For a example of all the pieces working together: https://jsfiddle.net/gjtc7ea3/
Disclaimer
As this solution causes a memory leak I would personally advice against using it unless you know what you are doing, as it is very easy to make mistakes here.
Related
I'm beginning to learn more about writing JS using the Prototype object, but I want to make sure I don't pick up any bad habits from other developers. My understanding of using Prototype is to create public methods for your instance. For example:
var module = new Module();
module.method();
But I see a lot of developers creating all their code inside the Prototype object, things that I would consider "private". Is this bad practice or considered okay? It just means I can then do:
module.privateFn();
Do they know this? Is that okay? Any help appreciated. I've been looking through the source code on GitHub to try establish the best way forward, here's a script that uses Prototypes for everything (for instance attachEvent which they clearly want privately kept):
https://github.com/WickyNilliams/headroom.js/blob/master/dist/headroom.js
Much appreciated, I want to make sure I develop using the correct implementations.
First of all you don't need to write modules using prototype. Think like if you writing something like a class you should use prototypes. And also it's important to where define your methods. Defining methods on prototype object and defining them in constructor function is totally different things!
Let's see a sample class definition with using methods defined in constructor:
var Dog = (function () {
var Dog = function (age, name) {
var that = this;
this.age = age;
this.name = name;
this.sayHi = function () {
console.log('Warf! Im ' + that.name); // meaning of "this" changed!!!
};
this.anotherMethod = function () {};
};
return Dog;
}());
var puppy = new Dog(1, 'puppy'); // sayHi and anotherMethod created
var sirius = new Dog(1, 'sirius'); // sayHi and anotherMethod recreated
sirius.sayHi = function () { console.log('Yohalolop!'); };
puppy.sayHi(); // -> 'Warf! Im puppy'
sirius.sayHi(); // -> 'Yohalolop!'
So there is some problems with the above example, firstly methods are defined like any other instance variables. Actually yeah you define them as instance variable and this means this functions are recreated for every instance object you create. I guess you have mentioned you can't use this keyword in your method definitions. This is error prone and there is a chance to forget that and use this keyword by mistaken. There are some times you can use methods as instance variables of course like variable callbacks.
Let's see a sample class definition with prototype object:
var Dog = (function () {
var Dog = function (age, name) {
this.age = age;
this.name = name;
};
// sayHi method defined only once in prototype
Dog.prototype.sayHi = function () {
console.log('Warf! Im ' + this.name; // we can use this keyword
};
// anotherMethod defined only once in protoype
Dog.prototype.anotherMethod() {
};
return Dog;
}());
var puppy = new Dog(1, 'puppy');
var sirius = new Dog(1, 'sirius'); // sirius and puppy sharing same prototype object
puppy.sayHi(); // -> 'Warf! Im puppy'
sirius.sayHi(); // -> 'Warf! Im sirius'
// remember puppy and sirius sharing same prototype object
Dog.prototype.sayHi = function () {
console.log('Yohalolop');
};
puppy.sayHi(); // -> 'Yohalolop'
sirius.sayHi(); // -> 'Yohalolop'
As an answer to your question about private functions, it is more complicated. Yes you can use private functions even you define your methods on prototype, but there are some concerns about testing. Usage of them is up to you. I prefer to don't use. Let me show some examples.
var Calculator = (function () {
var Calculator = function () {
this.importantNumber = 2;
};
// There is unfortunately no native implementation
// for private methods but you can mimic them with
// unaccessible functions and binding.
var someExtremeComputations = function () {
return 40 + this.importantNumber; // this keyword points to instance because of binding
};
Calculator.prototype.getMeaningOfLife = function () {
var result = someExtremeComputations.call(this); // we bind function to instance
return result;
};
return Calculator;
}());
This is the one of the examples how you can define private methods in javascript. The problem with private functions, they can't be tested. There is no way to test someExtremeComputations method.
Some people (includes me) use prefixed underscore naming convention for private methods. So they are actually public methods but if someone calling them or overriding they were warned by prefixed underscore. After all we can test private methods since they are public in real.
var Calculator = (function () {
var Calculator = function () {
this.importantNumber = 2;
};
// private method's name prefixed by an underscore to warn
// other developers to be careful about that or not to use.
Calculator.prototype._someExtremeComputations = function () {
return 40 + this.importantNumber;
};
Calculator.prototype.getMeaningOfLife = function () {
var result = this.someExtremeComputations(); // no need to bind
return result;
};
return Calculator;
}());
Explaining this with a few words is impossible. A generally good pattern is to construct methods through prototypes when you want to optimize your code. A good guideline is to only put the most essential data in the memory, using prototypes is critical for this since the prototyped variables and methods isn't injected into the memory until you request them.
When it comes yo your example there are no prototypes.
Simple example
// new object
var Dog = function() {
var that = this;
// add a property
that.name = "Fido";
// add a method
that.getName = function() {
return that.name;
};
};
// ... all the above is stored in memory directly
// Requires to be constructed
var dogObj = new Dog();
console.log(dogObj.getName()); // Fido
delete Dog.name // false
typeof Dog.name // "string"
delete dogObj.name // true
typeof dogObj.name // "undefined"
typeof Dog.name // "string" (still there)
// Will be available in the dogObj (after you call it)
dog.prototype.first = "first";
// Will be available in the dogObj (after you call it)
dog.prototype.second = function() {
return "second";
}
// Will not be available in dogObj
dog.third = "third";
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use of ‘prototype’ vs. ‘this’ in Javascript?
Object Oriented questions in Javascript
Can you please recommend which of the following is the best or their pros and cons?
Method 1
function User() {
this.name = "my name";
this.save = function() {
};
}
Method 2
function User() {
this.name = "my name";
}
User.prototype.save = function() {
}
Coming from a background in Java and PHP, I had initially struggled with the whole 'class' concept in JavaScript. Here are a few things to think about.
Construction
First, since you're likely going to be defining your classes as..
Customer = function () {}
Customer.prototype = new Person();
You will end up running into all sorts of nightmares of code if you are defining properties and methods during construction. The reason being is that a piece of code like Customer.prototype = new Person(); requires that the Person be called in the Customer constructor for true inheritance.. otherwise you'll end up having to know what the original one sets at all times. Take the following example:
Person = function (name) {
this.name = name;
this.getName = function () {return this.name}
}
Customer = function (name) {
this.name = name;
}
Customer.prototype = new Person();
Now we're going to update Person to also set whether they are 'new':
Person = function (name, isNew) {
this.name = name;
this.isNew = isNew;
this.getName = function () {return (this.isNew ? "New " : "") + this.name; }
}
Now on any 'class' that is inheriting from the Person, you must update the constructor to follow form. You can get around that by doing something like:
Customer = function () {
Person.apply(this, arguments);
}
That will call 'Person' in the scope of the new 'Customer', allowing you to not have to know about the Person construction.
Speed
Take a look at these benchmarks: http://jsperf.com/inherited-vs-assigned.
Basically, what I am attempting to prove here is that if you're creating these objects en masse, your best route is to create them on the prototype. Creating them like:
Person = function (name) {
this.name = name;
this.getName = function () {return this.name}
}
is very slow, because for every object creation, it creates a new function - it doesn't simply look up the prototype chain for the already existing one. Conversely, if you've got only a few objects that the methods are called extremely frequently on, defining them locally helps with the speed lost by looking up the prototype chain.
Shared properties
This always gets me. Let's say you've got something like the following:
Person = function () {
this.jobs = {};
this.setJob = function (jobTitle, active) {this.jobs[jobTitle] = active; }
}
Employee = function () {}
Employee.prototype = new Person();
var bob = new Employee();
bob.setJob('janitor', true);
var jane = new Employee();
console.log(jane.jobs);
Guess what? Jane's a janitor! No joke! Here's why. Since you didn't define this.jobs as being a new object on instantiation of the Employee, it's now just looking up the prototype chain until it finds 'jobs' and is using it as is. Fun, right?
So, this is useful if you want to keep track of instances, but for the most part you're going to find it incredibly frustrating. You can get around that by doing the following:
Employee = function () { Person.apply(this); }
This forces 'Person' to create a new 'this.jobs'.
Private variables
Since there's nothing that's really "private" in JavaScript, the only way you can get private variables is to create them in the constructor, and then make anything that relies on them initialize in the constructor.
Person = function () {
var jobs = {};
this.setJob = function (jobTitle, active) {jobs[jobTitle] = active; }
this.getJob = function (jobTitle) { return jobs[jobTitle]; }
}
However, this also means that you must call that constructor on every instantiation of an inherited class.
Suggestion
http://ejohn.org/blog/simple-javascript-inheritance/
This is a super basic class setup. It's easy. It works. And it'll do what you need it to do 90% of the time without having to deal with all the insanity JavaScript has to offer :)
</rant>
Best is a very subjective term.
Method 1 gives the possibility of truly private variables. e.g :
function User() {
var name = "fred";
this.getName = function () { return name;};
}
Method 2 will use less memory, as a single save function is shared by all User objects.
'Best' will be determined by your specific requirements.
JavaScript is an "Object Based" language, not a "Class Based" language. Shared behaviours, which is the class concept, are implemented by linking prototypes.
Method 1 does NOT create a class. Every time you invoke it, you create attributes and functions as defined and they are NOT shared with other "instances". If you replace this.save then only the one instance will have altered behaviour.
Method 2 implements shared behaviours. Therefore it is what people associate with classes and instances. If you replace this.save withe a different function, then all derived instances will immediately have the new behaviour.
If "best" means no memory consuming redefinitions of functions and sharing common behaviours (which is what class based programming tends to equate to) the Method 2 is the way to go.
As others have mentioned, there are two main differences:
Method 1 will create a new function for every instance of User
Method 1 will be able to access local variables in the constructor's scope
Here's an example to demonstrate these:
function User() {
var name = "my name";
this.foo = function() {
// one function per User instance
// can access 'name' variable
};
}
User.prototype.bar = function() {
// one function shared by all User instances
// cannot access 'name' variable
};
var a = new User();
var b = new User();
console.log(a.foo === b.foo); // false; each instance has its own foo()
console.log(a.bar === b.bar); // true; both instances use the same bar()
I'm trying to create a class like architecture on javascript but stuck on a point.
Here is the code:
var make = function(args) {
var priv = args.priv,
cons = args.cons,
pub = args.pub;
return function(consParams) {
var priv = priv,
cons = args.cons;
cons.prototype.constructor = cons;
cons.prototype = $.extend({}, pub);
if (!$.isFunction(cons)) {
throw new Hata(100001);
}
return new cons(consParams);
}
};
I'm trying to add the priv variable on the returned function objects's scope and object scope of the cons.prototype but I could not make it;
Here is the usage of the make object:
var myClass = make({
cons: function() {
alert(this.acik);
alert(priv.gizli);
},
pub: {
acik: 'acik'
},
priv: {
gizli: 'gizli'
}
})
myObj = myClass();
PS: Well I have used the outer vars for just to demonstrate what I want to do. I know the private variable syntax of javascript function structure. But I need a solutution for changing (adding private vars) the scope of a function which is going to be used by a "new" (i forgot the pattern name) instantiation pattern.
PS: Please forgive my english...
If you're after the class structure you really should follow the pattern of:
function MyClass(arg){};
Important Note: When ever you set your var names of the inner closure to the same name as it's containing outer closure you no longer have access to the original outer closures vars with the same name.
On the other hand, if you need to access the outer closures vars there is no need to set the inner closures vars with the same name. Just work with the vars as if they're with-in the inner closure.
var make = function(args) {
var priv = args.priv,
cons = args.cons,
pub = args.pub;
return function(consParams) {
var someThing = priv,
sElse = args.cons;
}
};
//
If you need to add a var or private variable to a function object with the name cons: as you've got it below just add it like any other function object.
var myClass = make({
cons: function() {
var myPrivateVariable = 'private';
alert(this.acik);
alert(priv.gizli);
},
pub: {
acik: 'acik'
},
priv: {
gizli: 'gizli'
}
})
myObj = myClass();
If your trying to replicate a class like structure the common approach in Javascript is as follows:
//Constructor
function MyClass(myParam){
this.myParam = myParam
}
MyClass.prototype.myMethod = function(){
alert(this.myParam); //retreives the "class" instance variable myParam
}
//Instantiation
var firstMyClass = new MyClass(7);
firstMyClass.myMethod(); //alerts 7
Note that within the functions you add to the prototype this will be a reference to the MyClass instance. If you would like to make private variables you can checkout this link from Javascript Expert Douglas Crockford: http://javascript.crockford.com/private.html
I currently use this style to create a js class like structure:
var JSClass = (function(){
console.log('JSClass Init');
//-- Set up private var and fnc here
var opt = {
width: 0,
height: 60
}
function _PrivateSum(g){
return (g * opt.width);
}
//-- Set up public access here
function JSClass(){ //the class constructor
//-- class attributes
}
//-- class methods
JSClass.prototype = {
getWidth : function(){
return _PrivateSum(opt.width);
},
setWidth : function(w){
console.log('JSClass setWidth: ' + w);
opt.width = w;
},
getHeight : function(){
console.log('JSClass getHeight');
return opt.height;
},
setHeight : function(h){
opt.height = h;
}
};
return JSClass;
}());
init by calling the following in another page:
var jc = new JSClass();
This is all good etc but if I then need to create a class that I would like to use several times on the same page:
var jc = new JSClass();
var jc2 = new JSClass();
At present if I change anything within the first "jc" then it also controls what is in the second "jc2".
So my question is how would I go about creating a fresh instance of my JSClass() class so that i can manipulate each one individually with out effecting the current one, similar to php classes etc
I believe I would need to somehow create a clone of the original but am not sure, or if there is a better way than above please feel free to inform me
much appreciated
I like to use a construction like this:
note: no new-statement.
//definition
var myClass = function() {
var abc = 1; //private properties
function f1() {...}; //private methods
return {
bar: function() {} //public function *with* access to private members and functions
};
};
//usage:
var myInstance1 = myClass();
var myInstance2 = myClass();
All Your class instances will use the same opt object, so changing it in one instance will change it for all other instances, too.
You'll have to move opt into the constructor function. The prototype functions than loose access to opt, of course.
If you want to use the functional approach for classes with private members, you have to give up the beauty of the prototype, and inheritance will be complicated. But you'll get real private members.
Crockford's "The Good Parts" is a reading I would recommend for these things.
Your variables ("opt") are STATIC (class variables - i.e. shared across all instances of the class) not instance variables. Instance variables are properties on the "this" object, which you create in the constructor and/or the two set(ter) functions you have. In setWidth,setHeight replace opt.width (or height) with this.width (or height) and remove the static var "opt".
Also, move _PrivateSum into the prototype object or you willo have trouble accessing the new instance variable just introduced - unless you call it using _PrivateSum.call(this, this.width), because when calling it as you do now "this" will be wrong, but if it's an instance method and you call it with this._PrivateSum(...) inside it "this" will point to the correct object.
After reading a bit on Javascript's prototypical inheritance model, I change my style of constructing a class from
var Some_Class = function() {
this.public_method = function() {
};
(function() {
// constructor
}).call(this)
}
to
var Some_Class = function() {
(function() {
// constructor
}).call(this)
}
Some_Class.prototype.public_method = function() {
};
Although I understand that this is a good practice, but I am not allowed to access private methods from the public method anymore
var Some_Class = function() {
var private_member = 'whatever';
(function() {
// constructor
}).call(this)
}
Some_Class.prototype.public_method = function() {
return private_member; // not possible
};
After reading through an article here (Closure-created constructor), then I came out with this
var Some_Class = function() {
var private_member = 'whatever',
private_method = function(_some_value) {
// private method implementation
};
if(!arguments.callee.prototype.public_method) {
arguments.callee.prototype.public_method = function() {
private_method.call(this, private_method);
};
}
(function() {
// constructor
}).call(this)
}
However, what are the drawbacks of doing this?! or is there a better way of doing this if I want to access private member in the public method?
My answer is a non-answer: there's no built-in private access in JavaScript but that's okay because YAGNI. Here's how I make private members in my code:
function Some_Class() {
this._private_member = 'whatever';
}
Some_Class.prototype._private_method = function() {
};
That's good enough. It's not really worth it to jump through hoops when the only real purpose of private is to protect yourself from... yourself.
(I say this having spent many hours myself playing around with every permutation of closures and prototyping, just as you are, and finally saying "screw it, it's not worth it".)
The use of function scope variables and closures to simulate private variables/functions is a well established idiom in the javascript community. If the variable is truly intended to be private, I see no drawback to this approach (although some claim that performant code on certain browsers/hosts has to pay attention to how many closures get created).
In your example, the private_method (and its environment) is shared across all objects - since your public_method closure is created only the first time the object is constructed (and bound to the constructor's prototype property that sets the created object's internal prototype chain) - so the private_method that is used is only the one that was created the first time.
Here is some sample code that will help illustrate what is going on:
var global = 1;
var Some_Class = function() {
var private_method = 'whatever';
var now = ++global;
print("outer now: " + now );
private_method = function(_some_value) {
// private method implementation
print("inner now: " + now);
};
if(!arguments.callee.prototype.public_method) {
arguments.callee.prototype.public_method = function() {
private_method.call(this, private_method);
};
}
(function() {
// constructor
}).call(this)
}
new Some_Class().public_method(); // outer now: 2, inner now: 2
new Some_Class().public_method(); // outer now: 3, inner now: 2
new Some_Class().public_method(); // outer now: 4, inner now: 2
Are you sure that is what you want?
If your private_method does not need to refer to the enclosing object's state, then I see little benefit in doing things the way you are doing.
What I usually do (if i have to use 'new' to create my object) is the following:
function MyClass() {
var private_var = 1;
function private_func()
{
}
this.public_func = function()
{
// do something
private_func();
}
this.public_var = 10;
}
var myObj = new MyClass();
The downside to this approach is that each time you construct the object via 'new' you re-create all the closures. But unless my profiler tells me that this design choice needs to be optimized, i prefer its simplicity and clarity.
Also I don't see the benefit in your code of doing the following either:
(function() { }).call(this); // call the constructor
Why are you creating a separate scope in your constructor?
If you have not done so already have a look at this JavaScript Module Pattern, which allows you to access private methods and variables from within the public functions, etc.
Echoing John Kugelman: It's impossible to create private members in javascript. Live with it. Even if you create a enclosure like this:
function SomeClass() {
var _private = 0;
this.public_acessor = function() {return _private};
}
Any user can still write:
SomeClass._not_private_anymore = 1;
SomeClass.public_acessor = function () {return this._not_private_anymore};
In the end, you can't trust any public member to be the same you declared. If someone is up to break your code, he will! Another user won't break your code only because it's useful.
Works with prototype, not just singleton. Problem is, when it's time to subclass, my subclass has no access to the privates