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
Related
Consider the following code:
var Tree = function() {
// private variables in closure
var fruits = 5;
var smallBranches = 10;
// public variables
this.bigBranches = 11;
this.countFruits = function() {
console.log(fruits);
};
};
Tree.prototype.countBranches = function() {
console.log(this.smallBranches);
console.log(this.bigBranches);
};
var tree = new Tree();
tree.countFruits();
tree.countBranches();
The output is:
5
undefined
11
To keep the code reading simple, I prefer to add methods to prototype like countBranches() instead of inside construction functions like countFruits(). However, the disadvantage is that the prototype functions can not access Tree's private variables. Is there a way to do that?
However, the disadvantage is that the prototype functions can not access Tree's private variables. Is there a way to do that?
So you want a private variable which is not private. No, there is no way to do that. No more than any function can access some other function's internal state.
However, if your objective in making smallBranches private is to prevent it from being overwritten, you can keep it private while adding an accessor:
var Tree = function() {
// private variables in closure
var smallBranches = 10;
...
this.getSmallBranches = function() { return smallBranches; };
};
Tree.prototype.countBranches = function() {
console.log(this.getSmallBranches());
};
Or, if you prefer to be able to say this.smallBranches directly, make it an instance property with only a getter:
var Tree = function() {
// private variables in closure
var smallBranches = 10;
Object.defineProperty(this, 'smallBranches', {
get() { return smallBranches; }
});
}
Tree.prototype.countBranches = function() {
console.log(this.smallBranches);
this.smallBranches = 42; // will fail
};
Actually the approach of associating member functions through prototype, outside constructor is the standard approach for adding member function to a type in javascript. You are getting undefined, due to not associating smallBranches variables with current object. Thus, it ends up as a local variable and not accessible outside constructor function. You have to make it as a member variable.
Change you code, as given below :-
var Tree = function() {
// private variables in closure
var fruits = 5;
this.smallBranches = 10;
// public variables
this.bigBranches = 11;
this.countFruits = function() {
console.log(fruits);
};
};
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.
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";
I'm currently looking into different patterns for building classes in JavaScript. But no matther what pattern I see, there are still some things I am not really sure about.
var ItemManager = (function()
{
var p = function()
{
this.items= [];
};
p.prototype.addItem = function(item)
{
var self = this;
self.items.push(item);
};
return p;
}());
I create the simple class ItemManager, this class got the function addItem for adding any item to the collection. Now I don't really want the variable items, which represents the collection, to be public, this variable should be private, but I don't see any possible way to use a prototyped method to access private variables.
So what's the best practice in this case? Simply don't use private variables?
var ItemManager = function() {
var items = [];
return {
addItem : function(item) {
items.push(item);
},
removeItem : function() {
return items.pop();
}
}
};
var myItemManager = new ItemManager();
items variable becomes hidden after the execution of ItemManager function, but addItem and removeItem still share the access to items. See the Douglas Crockford's article on private variables in JavaScript for further investigation.
There are several ways to have private variables:
Closures, as in aga's example, which uses the Revealing Module Pattern. If you're using ES6 classes, you can hide private data in the constructor, though it looks pretty ugly to me.
[ES6] Symbols
[ES6] WeakMap
I favor Symbols, though they can still be found using reflection (i.e. not completely private). Example:
var Person = (function() {
var nameSymbol = Symbol('name');
function Person(name) {
this[nameSymbol] = name;
}
Person.prototype.getName = function() {
return this[nameSymbol];
};
return Person;
}());
So it's possible to have (reasonably) private variables, but unfortunately none of the solutions are as elegant as you'd like.
as GoldenerAal mentioned, they are not called classes, but functions
you have
var ItemManager = function (){
..
...
...
};
you could have:
function ItemManager(){
this.items = [];
function addItem(item){
...
};
};
you can then create an instance of ItemManager, only when you need to :
var itemManager = new ItemManager();
itemManager.addItem(<something here>);
http://javascript.crockford.com/private.html
variables inside a function only have the scope of that function, that variable is not a global variable (static variable).
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