I am creating a custom object to be used in some internal applications where I work. I researched some ways to go about doing this - and this is what I came out with.
function ISGrader(text)
{
this.text = text;
this.printInfo = function(){
alert("Object working " + text);
}
this.putGrade = function(score)
{
alert(score);
}
}
I believe this shows constructor-type functionality, as well as some simple starter methods that I will build on.
Is the above good practice or is there another way that is more standard?
I prefer a pattern similar to the one below. You can think of it as a 4-step approach:
(function(parent) {
// 1. Declare private variables and functions that will be
// accessible by everybody within the scope of this
// function, but not outside of it.
var doSomethingAwesome = function() { .. }; // private function
var coolInteger = 42; // private variable
// 2. Create the constructor function
function ISGrader() {
..
}
// 3. Create shared public methods on the prototype object.
// These will be created only once, and shared between all objects
// which is more efficient that re-creating each method for each object.
ISGrader.prototype.printInfo = function() { .. };
ISGrader.prototype.putGrade = function(score) { .. };
// 4. Expose the constructor to the outside world.
parent.ISGrader = ISGrader;
})(window);
The reason why everything is enclosed inside a self-executing anonymous function is to ensure the private variables we create inside don't leak outside to the enclosing scope, and to basically keep things clean.
Another benefit of declaring the constructor like this is that you can change the parent object easily from say window to a further namespaced object by changing a single word.
I prefer this pattern (IIFE), but it is purely opinion:
var ISGrader = (function (text) {
// anything declared here is "private"
var printInfo = function() {
alert("Object working " + text);
};
var putGrade = function (score) {
alert(score);
};
// put "publicly" accesible things in the returned object
return {
text: text,
printInfo: printInfo,
putGrade: putGrade
};
})(text);
It is always recommended to do it using `prototype'. This way you can also inherit it's properties and create new one.
var ISGrader = function(text) {
this.text = text;
var _privateVar = text;
this.updatePrivateVar = function(newText) {
_privateVar = newText;
alert("private variable updated");
}
}
ISGrader.prototype.text = "";
ISGrader.prototype.printInfo = function() {
alert("Object working " + this.text);
}
ISGrader.prototype.putGrade = function(score) {
alert(score);
}
var isGrader = new ISGrader("hello");
isGrader.printInfo();
// Inherit and create a new definition
var ISGrader2 = function() {}
ISGrader2.prototype = new ISGrader();
var isGrader2 = new ISGrader("hello2");
isGrader2.printInfo();
isGrader2.updatePrivateVar("hello3");
demo : http://jsfiddle.net/rkspP/3/
While not really an answer, I recommend Douglas Crockford's book JavaScript: The Good Parts as it does a good job of introducing you to the "good parts" of the language and discusses the pros and cons of the different ways to create objects in JavaScript.
You can also review this resource if you're just looking for an explanation of member visibility in JavaScript objects: http://javascript.crockford.com/private.html
If you are planning on creating multiple ISGrader objects on a single page, it's more memory efficient to stick the functions in a prototype object assigned to ISGrader like this:
function ISGrader(text) {
this.text = text;
}
ISGrader.prototype = {
printInfo: function() {
alert("Object working " + this.text);
},
putGrade: function(score) {
alert(score);
}
}
Related
I am using module pattern in javascript.
Is it a way to create instances of a "class" ?
I am using it in a right way ?
var moduleClass = (function () {
var a =5;
return {
getA: function () {
console.log(a);
}
};
})();
var instance = moduleClass;
instance.getA();
http://jsfiddle.net/PzLKy/
How can I pass parameters on new instances ?
You don't really need new here, Below is the right way to code to achieve what you are trying to achieve.
Also, be really careful while using new, if used unwisely it can start clobbering your Global variable, If you want to use new, John Resig has a really nice explaination for how to do it the right way, for more read this article by John Resig
http://ejohn.org/blog/simple-class-instantiation/
http://jsfiddle.net/PzLKy/2/
var moduleClass = (function () {
var a =5;
return {
setA: function (inA) {
a=inA;
} ,
getA: function () {
alert(a);
}
};
})();
var instance = moduleClass;
instance.setA(8);
instance.getA();
Edit:
contactmatt is right, definitely dont be afraid of using constructor, but here is some thing you need to be aware of
Taken from John Resig's article mentioned in the first paragraph,
suppose this is your code
function User(first, last){
this.name = first + " " + last;
}
var user = new User("John", "Resig");
user.name // John Resig
var user2 = User ("first","last");
user2.name //undefined, also this would pollute your current scope
if you call the constructor, you would not get any kind of indication and can be a debugging nightmare.
a way to solve this is
function User(first, last){
if ( this instanceof User ) {
this.name = first + " " + last;
} else
return new User(first, last);
}
To Conclude,
So if you feel that constructor is the best way for your problem, use it. But be aware, also the simple class instantiation by John is a really useful pattern, try to go through it,he also explains generic constructor.
Use constructor functions. Don't be afraid of "new", just use it wisely.
Note: Standard naming convention is to name functions that will be used as function constructors with a capital letter. (i.e. ModuleClass instead of moduleClass)
function ModuleClass() {
var a =5;
return {
getA: function () {
console.log(a);
}
};
};
or if you're brave enough to learn about the 'this' keyword in JavaScript.
function ModuleClass() {
var a =5;
this.getA = function () {
console.log(a);
};
};
var instance = new moduleClass();
instance.getA();
For creating instances you have to use the key word new with any function.
This function aka Constructor can help you create multiple instances
var moduleClass = (function () {
var a =5;
return {
getA: function () {
console.log(a);
}
};
})();
var instance = new moduleClass;
instance.getA();
Constructor:Constructor functions are used with the new keyword, and they're one of the ways you give an object a prototype.
REFER-->
Javascript Prototypes,objects,constructor??i am confused
Constructors in JavaScript objects
I'm having a bit of confusion over which (if any) of these javascript initializes to use, as from what I can tel, they all do the same thing. Are there cases in which I should use one or he other? Mt project requires me to encapsulate several functions and namespaces in a single object so that we don't clutter te global scope with variable names, put I'm especially unclear as to the difference between +function(){}(); and (function())();
Any help would be greatly appreciated. Keep in mind the end goal is for all of our function to be encapsulated in a single namespace. IE MyCompany.function, MyCompany.Namepsace.Function ...
<script>
var Ford = {};
+function() {
Ford.start = function() {
console.log("Ford just started");
};
}();
Ford.start();
</script>
<script>
var Honda = {};
(function() {
Honda.start = function() {
console.log("Honda just srtarted");
};
})();
Honda.start();
</script>
<script>
var Toyota = function() {
return {
start: function() {
console.log("Toyota just strted");
}
};
}
var car = new Toyota();
car.start();
</script>
Javascript functions are only invoked as constructors when the new keyword is used. new creates a new object instance, inherits from the constructor's prototype, and makes the context of the this keyword the newly created object instance. So if you're not using the prototype to inherit properties or the keyword this to create new properties in the constructor--you don't really need to use a constructor.
I think what you're looking for is the module pattern which is implemented using immediately invoked functions. Both of your first two examples use immediately invoked functions. I believe the style (function(){}()); is preferred to +function(){}();. Both the surrounding () and the + cause the javascript parser to expect a function expression rather than a function declaration and this allows the trailing () to invoke the function. Besides being somewhat less readable + may also alter the return value of the function.
I think you want some variation on this (copied from link):
var MODULE = (function () {
var module = {};
var privateVariable = 1;
function privateMethod() {
// ...
}
module.moduleProperty = 1;
module.moduleMethod = function () {
// ...
};
return module;
}());
While all of that is valid JS, you're making assumptions that lead me to believe you may not understand how JS works. The first two example are not constructors in the usual sense at all...they're sort of module pattern, but not even. you could condense it to
var Honda = {};
Honda.start = function() { console.log("Honda just started"); }
and forget the self-executing function. What is shown above is similar to what you'd think of as a static function in other languages:
public class Honda {
public static void start() { Console.WriteLine("Honda Just Started"); }
}
If you wanted an instance function, you need to either attach to the prototype, or to the this keyword in the constructor:
Prototype:
var Honda = function() {}
Honda.prototype.start = function() { console.log("Honda just started"); }
This:
var Honda = function() {
this.start = function(){
console.log("Honda just started");
}
}
Your final example, with Toyota indicates you have a fundamental misunderstanding of how function constructors work. Your object has been discarded, and in return you get some object literal which could have been written:
var Toyota = {
start: function(){
console.log("Toyota just started");
}
}
What you (probably) intend is the "this" pattern I explained on the Honda example above:
var Toyota = function() {
this.start = function() {
console.log("Toyota just started");
}
}
Finally, when writing "namespaced" libraries of functions, the module pattern may be your best friend. This lets you maintain private state without the need for a formal constructor/prototypes, etc:
var MyCompany = {};
//car module
(function(ns){
var module,
_isStarted;
function start() { console.log('start'); _isStarted = true; }
function stop() { console.log('stop'); _isStarted = false; }
function isStarted() { return _isStarted; }
module = {
start: start,
stop: stop,
isStarted: isStarted
}
ns.CarModule = module;
}(MyCompany));
//use:
MyCompany.CarModule.start();
if(MyCompany.CarModule.isStarted()) { MyCompany.CarModule.stop(); }
wish to extend define and/or execute new methods against an object using its private methods - exactly as if I were to define the method within the original declaration - except these new methods apply only to this object to be executed one time, not to the Klass itself.
for example:
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
}
var k = new Klass();
console.log( k.publicFn1() ); // prints 16
suppose I wish to create and/or execute a new method on Klass, sum2(), that will add 2 to the privateFn.
have tried the brain-dead
k.publicFn2 = function() { return privateFn()+2 }
console.log( k.publicFn2() );
and it makes perfect sense that it does not work, but what does?
as a note, since functions are very long, attempting to maintain the syntax of privateFn() rather than self.privateFn() - this might be asking too much, but one hopes.
There is no such thing as private in ECMAScript
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
}
privateFn is a local variable which publicFn1 has access to due to scoping rules (and closures).
You cannot access privateFn outside the scope of function Klass
If you want to access privateFn outside the scope of function Klass then you have to expose it through a proxy or inject it further up the scope chain.
A proxy would be something like
this._private = function() {
return privateFn;
}
Injecting further up the scope chain would be something like
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
this.uid = Klass.uid++;
Klass.instances[this.uid] = {
privateFn: privateFn
};
}
Klass.uid = 0;
Klass.instances = [];
k.publicFn2 = function() { return Klass.instances[this.uid].privateFn()+2 }
Both are ugly.
The reason they are ugly is because you are emulating classical OO
Please use prototypical OO instead.
Shameless prototypical OO plug
Javascript is a prototype-based object-oriented language. That means if you wish to user instance-specific variables, you can do it by extending the prototype object of that object. Using it any other way is unnatural and leads to problems such as yours that require an extreme hack to overcome. Why not just use the language as it was intended?
The correct structure of your code would be more like the following:
function Klass(nr) {
this.nr = nr;
};
Klass.prototype.publicFn = function() {
alert(this.nr);
};
var inst = new Klass(13);
inst.publicFn();
There are no private functions in JS and there won't be. You can "hack" the similar effect, but at the cost of either hacking something on your own or using other libraries.
It makes little sense to try to bend the language to suit you. Instead you should learn the language as it is.
Just for the kicks i am trying to create a simple data object in javascript. Here is the code.
var roverObject = function(){
var newRover = {};
var name;
var xCord;
var ycord;
var direction;
newRover.setName = function(newName) {
name = newName;
};
newRover.getName = function() {
return name;
};
newRover.setDirection = function(newDirection) {
direction = newDirection;
};
newRover.getDirection = function() {
return direction;
};
newRover.setXCord = function(newXCord) {
xCord = newXCord;
};
newRover.getXCord = function() {
return xCord;
};
newRover.setYCord = function(newYCord) {
yCord = newYCord;
};
newRover.getYCord = function() {
return yCord;
};
newRover.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
};
return newRover;
};
rover1 = new roverObject();
rover2 = new roverObject();
rover1.setName("Mars Rover");
rover1.setDirection("NORTH");
rover1.setXCord(2);
rover1.setYCord(2);
console.log(rover1.where());
console.log(rover1);
rover2.setName("Moon Rover");
rover2.setDirection("SOUTH");
rover2.setXCord(1);
rover2.setYCord(1);
console.log(rover2.where());
console.log(rover2);
There are few questions that I have around this creation.
I want to create an object where the properties/attributes of object are private and not visible to world. Am I successful in doing that? Can I really not access the object attributes?
Is there a better way to create this kind of object?
If I want to inherit this object, I should do a newObject.prototype = roverObjectwill that work? And will that make sense most of all.
Finally I have a wierd problem. Notice the last method of objet "where" which returns a concatenated string. Here I tried following code instead.
newRover.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
}();
and then did a following console.log
console.log(rover1.where);
console.log(rover2.where);
It threw following error for me:
cannot access optimized closure
Why would it say that? What am I doing wrong?
Thanks for all the help. Any review comments would be appreciated too!
Cheers
Am I successful in doing that? Can I really not access the object attributes?
Indeed. You don't have object attributes, you have local variables in the roverObject function. Local variables can't be accessed from outside, only from the functions inside the roverObject function that have a closure over them.
That you are calling roverObject as a constructor, with new roverObject, is irrelevant, as you are returning a different object from the function. Saying var rover1= roverObject() without the new would do exactly the same thing. Notably the object returned by [new] roverObject is a plain Object as you created it from {}; rover1 instanceof roverObject is false.
If you wanted instanceof to work, you would have to call with new, and use this instead of newRover in the constructor function.
If I want to inherit this object, I should do a newObject.prototype = roverObject will that work? And will that make sense most of all.
No. You currently have no allowance for prototyping. You are using a separate copy of each method for each instance of the roverObject. You can do certainly objects this way but it's a different approach than prototyping. If you wanted to make something like a subclass of roverObject in the arrangement you have now, you'd say something like:
function AdvancedRover() {
var rover= new roverObject();
rover.doResearch= function() {
return rover.where()+' and is doing advanced research';
};
return rover;
}
Note since the ‘private’ local variables in the base class constructor really are private, even the subclass cannot get at them. There's no ‘protected’.
newRover.where = function(){ ... }();
What's that trying to do? I can't get the error you do; all the above does is assigns the string with the location to where (before the setter methods have been called, so it's full of undefineds).
Is there a better way to create this kind of object?
Maybe. see this question for a discussion of class/instance strategies in JavaScript.
Q1: you can create 'private' members in javascript 'classes'. In javascript, privacy is not determined by any access specifier. Instead, access needs to be specifically instrumented. Example:
function MyClass() {
this.val = 100; // public;
var privateVal = 200;
function getVal() { return this.val; } // private method;
this.getPrivateVal = function() { // public method, accessor to private variable
return privateVal;
}
}
Object scope in javascript is governed by a queer concept called closures. AFAIK, there is no parallel concept in any other popular launguage like C+/Java etc.
While I understand what closures are, I cannot put it in words. Perhaps a demonstration will help you:
function closureDemo() {
var done=false;
function setDone() { done=true; }
doLater(setDone);
}
function doLater(func) { setTimeout(func,1000); }
closureDemo();
now, while setDone is called from within doLater, it can still access done in closureDemo, even though done is not in scope (in the conventional procedural sense).
I think you will understand more when you read this.
Q2: I can only say what I do; I don't know if it is better or not. If I wrote your code, it would look like this:
function RoverObject() {
var newRover = {}; // privates
var name;
var xCord;
var ycord;
var direction;
this.setName = function(newName) {
name = newName;
};
this.getName = function() {
return name;
};
this.setDirection = function(newDirection) {
direction = newDirection;
};
// and so on...
this.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
};
}
var rover1 = new RoverObject();
Points to note:
capitalization of "class name"'s first letter
use of this instead of roverObject
this function is a pure constructor. it returns nothing.
Q3: if you want to do inheritance, then my method (use of this) will not work. Instead, the public methods should be a part of the prototype of RoverObject. Read this. Excellent material.
Hope that helps.
EDIT: There is a problem with the way your code is doing work. Problems:
your function does not do what its name suggests. Its name had better be createRoverObject, because that's exactly what it is doing. It is not working like a class constructor
the methods supported by your class are part of the object, but the data members are not. While this may work (and it is not, as your console.log() problem suggests), it is not a good way to implement a class in javascript. The problem here is of closures. Again, i'm unable to articulate what the problem specifically is, but I can smell it.
With regards to 4. - you are trying to log the function, not the result of calling the function. Should be console.log(rover1.where()); My guess firebug(I assume it's firebug's console.log) does not like to log function definitions.
EDIT Oh I get it, you are actually executing the where funcion when you assign rover.where. Are you trying to get what looks like a property to actually be a function? If that's the case it won't work. It will have to be a function if you want it to be evaluated when it's called.
What happens in you case where gets executed in the constructor function. At that point you are still creating the roverObject closure and hence it's too early to access it's private variables.
This is just addressing point 1 of your post.
Here's a good article on javascript private members and more:
Private Members in JavaScript
Defining your object like this gives you private members.
function RolloverObject() {
var name;
var xCord;
var ycord;
var direction;
this.setName = function(newName) { name = newName; };
this.getName = function() { return name; };
this.setDirection = function(newDirection) { direction = newDirection; };
this.getDirection = function() { return direction; };
this.setXCord = function(newXCord) { xCord = newXCord; };
this.getXCord = function() { return xCord; };
this.setYCord = function(newYCord) { yCord = newYCord; };
this.getYCord = function() { return yCord; };
this.where = function() {
return "Rover :: " + name + " is at Location(" + xCord + "," + yCord + ") pointing to " + direction;
};
}
var rolloverObject = new RolloverObject();
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