What's the difference between declaring internal variables inside a JavaScript class with this vs var?
Example:
function Foo( ) {
var tool = 'hammer';
}
function Foo2( ) {
this.tool = 'hammer';
}
One difference we're aware of is Foo2.tool will yield "hammer" whereas Foo.tool will yield undefined.
Are there other differences? Recommendations for one vs. the other?
Thanks!
there is no "one or the other" here since the purpose of the two are different.
consider this:
var Melee = function(){
//private property
var tool = 'hammer';
//private method
var attack = function(){
alert('attack!');
};
//public property
this.weapon = 'sword';
//public methods
this.getTool = function(){
return tool; //can get private property tool
};
this.setTool = function(name){
tool = name; //can set private property tool
};
};
var handitem = new Melee();
var decoration = new Melee();
//public
handitem.weapon; //sword
handitem.getTool(); //hammer
handitem.setTool('screwdriver'); //set tool to screwdriver
handitem.getTool(); //is now screwdriver
//private. will yield undefined
handitem.tool;
handitem.attack();
//decoration is totally different from handitem
decoration.getTool(); //hammer
handitem.weapon in OOP is a "public property", accessible from the outside. if i created this instance of Melee, i can access and modify weapon since it's open to the public.
handitem.tool is a "private property". it's only accessible from inside the object. it is not visible, not accessible, and not modifiable (at least directly) from the outside. trying to access it will return undefined
handitem.getTool is a "public method". since it's on the inside of the object, it has access the private property tool and get it for you from the outside. sort of bridge to the private world.
handitem.attack is a private method. like all private stuff, it can only be accessed from the inside. in this example, there is no way to call attack() (so we are safe from attack :D )
Related
I would like to set a design standard for class- as well as class-instance-creation. Combining lots of intel from multiple websites (e.g. from stackoverflow), there finally is a way to have a relative maximum of flexibility. My goal is exactly that in terms of having code-structures that behave similar to more defined classes of Java and the like.
Here is working codesnippet of what I have so far (including explanations):
var MyClass = function (prop1)
{
var _class = MyClass;
var _proto = _class.prototype;
// public member of constructed class-instance
this.prop1 = prop1;
// private static property as well as private member of class-instances
// (see getter below!)
var prop2 = this.prop1 * 10;
// need to use this. instead of _proto because the property prop2 of
// the class itself would be returned otherwise
this.getProp2 = function ()
{
return prop2;
}
// 1 function for all instances of the class
// reached by a fallback to the prototype
_proto.protoAlert = function ()
{
// must call this.getProp2() instead of using prop2 directly
// because it would use the private static member of the class
// itself instead the one of the class-instance
alert(this.prop1 + " " + this.getProp2());
}
};
var c1 = new MyClass(1);
c1.protoAlert();
var c2 = new MyClass(2);
c2.protoAlert();
c1.protoAlert();
This works well so far. However, there are some hurdles to take to not provoke errors and uncatched misbehavior of the script. The private property prop2 exists in both class and class-instances. It's a likely unintended double identity. Furthermore, the private property of class-instances are only properly reachable through setter- and getter-function. This is not the worst thing as it enforces a common way to access private variables. The downside is: Setters and getters have to be called with this. to actually reference to the prop2 of the class-instance then returning it. As for class inheritance - I didn't look into this topic with my current standard yet. Hopefully, it will work out as well.
Is there a more elegant solution or at least one that is less prone to possible errors?
Thank you in advance!
JavaScript does not really provide practical pattern for private properties. The pattern you're using does work only as long as you define all methods in constructor. You should keep in mind that this means every time you create the class, you create all the methods.
If you think about it, private variables are not serving any function in the program, they serve the programmer to keep in mind, that he should and what he should not be changing. As such, you can simply use some naming pattern. I've seen this a lot along other people's code:
function MyClass() {
// Private property
this._helloWord = "Hello word.";
}
// From outside, accessed as `helloWord`, without underscore
Object.defineProperty(MyClass.prototype, "helloWord", {
get: function() {console.log("helloWord getter");return this._helloWord;},
set: function(value) {console.log("helloWord setter");return this._helloWord = value;},
};
MyClass.prototype.alertProp = function() {
alert(this._helloWord);
}
// Accessing from the outside:
var instance = new MyClass();
alert(instance.helloWord); // will activate the getter function
Most people will instantly understand there is something special about _underscored variables. You can also make variable constant this way:
Object.defineProperty(MyClass.prototype, "helloWord", {
value: "Hello world",
writable: false // <----
};
Learn more about Object.defineProperty. You should also get to understand that the structure of Javascript is a little bit different than in OOP languages. If you try to push other languages' patterns on it, it will cause performance and structural problems.
The way I figured, when creating a new function (that represents a class), it is considered a good practice to define additional functions with the help of the prototype. If functions are declared through this within an existing function, they get created for each instance, which we don't necessarily want.
So, my question is - if I want to have a property that is completely private and can be access only through getters and setters, is it even possible to achieve this by using the prototype?
Here's an example:
function Item() {
var title = '';
this.setTitle = function(_title) {
title = _title;
};
this.getTitle = function() {
return title;
};
}
var car = new Item();
car.setTitle('car');
console.log(car.getTitle()); //car
console.log(car.title); // undefined
/*
Alternative
*/
function _Item() {
this.title = '';
}
_Item.prototype.setTitle = function(_title){
this.title = _title;
};
_Item.prototype.getTitle = function() {
return this.title;
};
var _car = new _Item();
_car.setTitle('car 2');
console.log(_car.getTitle()); // car
console.log(_car.title); // car
as can be seen from the example above, in the case of Item, I declared getters and setters within a function - not a good practice. But in this way, I managed to keep the title property private. However, in case of _Item, I'm using the prototype approach, which is preferred, but my title property is not private at all.
So, what's the best approach at creating private properties of "classes" in JavaScript?
No, if you want a private property, which by definition is a variable local to the constructor, then obviously methods which access it must also be defined within the constructor.
Many people worry about the efficiency implications of defining a method once on a prototype, versus defining it once on every instance. This might have been a valid concern ten years ago, or today in applications that are creating thousands or millions of objects. Otherwise, realistically it's not something you need to worry about.
If I'm using some private functions in a class do certain naming conventions yield better performance or offer different functionality...or is it simply a matter of preference?
var MyClass = function() {
var private1 = function(msg){
// Do stuff.
console.log(msg);
};
this.private2 = function(msg) {
// Do stuff.
console.log(msg);
};
};
Your two variables have very different access so which one to use depends upon which type of access you want to offer, not just a coding style preference.
In your example, private1 is a local variable to your constructor and is ONLY available to code inside the constructor. It is NOT available to any code outside the constructor. It is actually private.
var yourObj = new MyClass();
yourObj.private1(); // undefined, will not work
private2 is an instance variable of a MyClass object you create with the new operator and is reachable by any code as yourObj.private2(). It is not private in any way - it is a publicly reachable method. Example:
var yourObj = new MyClass();
yourObj.private2(); // works
So private1 is private and private2 is public. One should select the implementation method that matches the desired goal of the code. This is not just a coding style preference.
private1 is a function inside constructor MyClass and private2 is function of MyClass instance:
var cl = new MyClass();
console.log(cl.private1); // undefined
console.log(cl.private2); // function
In Javascript there are several ways to create a class. But I have some doubts between these two ways:
function MyClass(){
this.myFun = function(){
// do stuff
}
}
and
var MyClass = {
myFun: function(){
// do stuff
}
}
The only difference is that the second way I can't to use a new operator? So the Json notation allows me to create a static class or singleton class, right?
The code you showed doesn't create classes. The notion of class is unknown to javascript, it uses prototypal inheritance. Now as to your code. The first piece of code represents a constructor function. From it, you can derive instances - javascript objects with shared properties -, using the keyword new.
function MyConstructor(name){
this.name = name || 'no name yet';
this.myFun = function(){
alert(this.name);
}
}
var instanceA = new MyConstructor('Webman')
,instanceB = new MyConstructor;
instanceA.myFun(); //=> 'Webman'
instanceB.myFun(); //=> 'no name yet'
The second piece of code creates a single javascript object. It uses an object literal notation.
var mySingleObject = {
myFun: function(){
alert('I am single');
}
};
mySingleObject.myFun(); //=> 'I am single'
The Mozilla Developer Network has a nice page, where things are explained in more detail.
Creating an object using an object literal, everything is public. Using a constructor, it is possible to have private variables, using javascripts closure mechanism:
function MyConstructor(name){
var namestring = 'the name property of this instance is: '+
(name || 'not set');
this.myFun = function(){
alert(namestring);
}
}
A few minor corrections. In JS these is only class simulation - the language lacks a formalised notion of actual classes. And your JSON notation is actually a JS object - that would be invalid JSON as you currently have it.
You do not have to use an object to simulate the singleton pattern. You can do this with constructors like so:
function Animal() {
if (Animal.instance) return Animal.instance;
Animal.instance = this;
/* constructor code here */
}
var animal_a = new Animal(); //constructor runs
var animal_b = new Animal(); //singleton instance returns
console.log(animal_a === animal_b); //true
Also, with your first approach, note it is better to put reusable, inheritable code on the prototype rather than declaring separately for each instance. This is faster, and also more sensible - the prototype is the place for this.
function Animal() {}
Animal.prototype.method = function() {}
This also avoids the problem of distinguishing between own and inherited properties, which, in your code, could not be done because you're declaring methods separately on each instance.
[EDIT - in response to the OP's question about private members]
Private members are implemented as local variables/functions, which means they are inaccessible outside the current closure.
function Animal() {
var private_var = 'foo';
function private_method = function() { alert('bar'); };
}
Public methods may (if you choose) be able to get or set them - but in order that they themselves have access to these private members, they would have to be declared inside the constructor, not separately, outside it.
function Animal() {
var private_var = 'foo';
function private_method = function() { alert('bar'); };
if (!Animal.prototype.public_method)
Animal.prototype.public_method = function() {
alert(private_var);
};
}
var dog = new Animal();
dog.public_method(); //'foo'
There are no classes in javascript, javascript is a prototypal language.
There is no way to explain this faster than watching: Crockford on JavaScript - Chapter 2: And Then There Was JavaScript for a simple CORRECT explanation by the father of json (amongst other things).
Good Luck!!
// base function
function Man(name) {
// private property
var lover = "simron";
// public property
this.wife = "rocy";
// privileged method
this.getLover = function(){return lover};
// public method
Man.prototype.getWife = function(){return this.wife;};
}
// child function
function Indian(){
var lover = "jothika";
this.wife = "kamala";
}
Indian.prototype = aMan;
var aMan = new Man("raja");
oneIndian = new Indian();
oneIndian.getLover();
I got answer as "simron" but I expect "jothika".
How my understanding is wrong?
Thanks for any help.
First of all your code doesn't work at all and it's wrong.
Here's the code that works:
// base function
function Man(name) {
// private property
var lover = "simron";
// public property
this.wife = "rocy";
// privileged method
this.getLover = function(){return lover};
// public method
Man.prototype.getWife = function(){return this.wife;};
}
// child function
function Indian(){
var lover = "jothika";
this.wife = "kamala";
this.getLover = function(){return lover};
}
Indian.prototype = new Man();
Indian.prototype.constructor = Indian;
var oneIndian = new Indian();
document.write(oneIndian.getLover());
aMan didn't exist until you declared it.
Also you should have set the ctor to Indian.
And at last, getLover is a closure that refers to Man and not to Indian.
Declaring it again refers it to the right scope.
See here and here for further details and improvements of your code.
The getLover property on the instance refers to the closure you defined within the Man constructor. The lover local variable inside Man is the one in-scope for that function. The lover variable you declared inside Indian has nothing whatsoever to do with the one declared inside Man, no more than local variables declared inside other functions do.
For Indian to manipulate the private lover variable inside Man, you would have to give Indian some access to it via an accessor function -- but then everything would be able to change it via that same accessor function.
My advice: get rid of this whole priviledged method crap and don't try to shoehorn concepts from one language into another.
For performance reasons, methods should reside in the prototype. Otherwise, a new function object (which forms a closure over the constructor's local vaiables) has to be created for each instance, which is highly inefficient.
If you want to hide properties (ie 'private' fields), add a prefix like _private_ to their name and tell the programmer not to do stupid things.