I am quite new to javascript an trying to make sense of the basics. Coming from Python I am a bit overwhelmed by the different ways to get stuff done.
I came up with the pattern below to make constructors. I hope this is sound practice: is it? Some specific questions remain:
I jump to doing _this = this right away and only use _this. Is there any harm in that?
I allow the constructor to take an object as the first argument. The object properties become 'named parameters' and overwrite defaults. Any disadvantages to this?
Sorry that my questions aren't very specific, but I need a bit of confirmation/criticism at this stage.
var Omelette = function () {
var _this = this;
_this.publicName = 'Dexter';
_this.publicEggs = 6;
// Override property values with custom supplied values
// This comes after the default values and before they are used
for (var p in arguments[0]) {
_this[p] = arguments[0][p];
}
var privateGreeting = 'Hello, ';
_this.publicSayHi = function () {
console.log(privateGreeting + _this.publicName );
};
var privateBreakEggs = function (brokenEggs) {
_this.publicEggs = _this.publicEggs - brokenEggs;
};
// initializing the prototype breaks two eggs
privateBreakEggs(2);
console.log(_this.publicEggs);
};
var myOmelette = new Omelette({
publicName: 'Roy'
});
// 4
var hisOmelette = new Omelette({
publicEggs: 12
});
// 10
hisOmelette.publicSayHi();
// Hello Dexter
hisOmelette.publicEggs = 12;
// No more eggs are broken
console.log(myOmelette.publicEggs);
// These are unchanged
hisOmelette.breakEggs();
// not publicly accessible. error 'undefined is not a function'
Take a look at the following code:
var Omelette = function (overrideObject) {
this.publicName = 'Dexter';
this.publicEggs = 6;
// Override property values with custom supplied values
if (overrideObject)
{
var keys = Object.keys(overrideObject); //get all the keys from the override object.
//We use Object.keys for this. -> puts all the keys of an object into an array.
for (var i = 0; i < keys.length; ++i)
{
this[keys[i]] = overrideObject[keys[i]]; //loop over every key and overwrite/set the value a public variable.
}
}
var privateGreeting = 'Hello, ';
this.publicSayHi = function () {
console.log(privateGreeting + this.publicName ); //this refers to the instance created and the owner of function publicSayHi.
};
var privateBreakEggs = function (brokenEggs) {
this.publicEggs = this.publicEggs - brokenEggs;
};
this.breakEggs = privateBreakEggs; //reference to privateBreakEggs, making it publically available.
//this won't work since the this in privateBreakEggs refers to its own scope.
privateBreakEggs(2);
//this will work since it's called via `this`.
this.breakEggs(2);
};
var myOmelette = new Omelette({
publicName: 'Roy'
});
myOmelette.publicSayHi(); //should say Roy.
var hisOmelette = new Omelette({
publicEggs: 12
});
hisOmelette.publicSayHi(); //should say Dexter
console.log(hisOmelette.publicEggs); //10
console.log(myOmelette.publicEggs); //4
// These are unchanged
hisOmelette.breakEggs(2); //eggs now 8
console.log(hisOmelette.publicEggs)
hisOmelette.privateBreakEggs
// not publicly accessible. 'undefined'
I've made several changes to your code and commented. Compare it with your own code and learn from the differences. I'm no longer introducing the _this variable, since it's unnecessary.
There are no real disadvantages to override the default properties of an instance using an argument. The could be added to the instance after it's created, now they are added during creation. Your method (improved by me) allows for easy creation of properties on the creation of the instance. Bear in mind that the properties are only set on that instance. If you want them to be shared with all the instances use a prototype.
Related
I've been investigating multiple leveles of inheritance with "private" variable in each "class" in JavaScript, but run into this peculiar singularity:
function Ammo() {
var a = 0;
this.get_ammo = function() {
return a;
};
this.add_to_ammo = function() {
a = a+1
return a;
};
this.clean_ammo = function() {
return a=0;
}
}
function Weapon() {
var a =0;
}
function Gun() {
var a = 0;
this.fire = function(){
console.log("Bang");
}
}
Weapon.prototype = new Ammo();
Weapon.prototype.constructor = Weapon();
Gun.prototype = new Weapon();
Gun.prototype.constructor = Gun();
var a = new Ammo();
var w = new Weapon();
var g = new Gun();
a.add_to_ammo()
a.add_to_ammo()
a.add_to_ammo()
console.log(w.get_ammo())
// At this point I get 0, as expected. But after
w.add_to_ammo()
w.add_to_ammo()
w.add_to_ammo()
console.log(g.get_ammo())
// But here I get 3!
Can somebody explain why I get 3 after
console.log(g.get_ammo())
I thought that objects a, w, g are independent, so are their fields.
Also I found out that if I change
var a = 0;
to
this.a = 0;
I get expected result. fields of the object are unbound to their parents fields.
var a is defined in Ammo, but var a in the other constructors does absolutely nothing. The a that's being modified when you call the method no matter which instance is always the same a that was captured in the closure in Ammo.
You can't have private variables like you want in JavaScript, and that's ok. The most common way to do it is to make the variable public, and prefix it with an underscore, to mark it as "internal":
function Ammo() {
this._ammo = 0;
}
Then add the methods to the prototype and use this._ammo to reference that variable:
Ammo.prototype.getAmmo = function() {
return this._ammo
}
Then you can inherit with Object.create:
Weapon.prototype = Object.create(Ammo.prototype);
And in the constructor "call super":
function Weapon() {
Ammo.call(this) // gets own "_ammo"
}
Also, you are not setting up the constructor function properly. You should assign a function, not call it:
Weapon.prototype.constructor = Weapon;
Gun.prototype.constructor = Gun;
I don't have enough rep points to comment on #elclanrs answer, so forgive me.
His answer is all correct, but the most pertinent piece of information is the last
Also, you are not setting up the constructor function properly. You should assign a function, not call it:
Weapon.prototype.constructor = Weapon;
Gun.prototype.constructor = Gun;
your variables that are declared inside the scope of the function closure ARE IN FACT PRIVATE! however, you never properly instantiated you subclass objects, so you had a frankenstein thing going on: one object, lots of body parts.
Other than that there is nothing inherently wrong with your code, it's just not the way people usually write "Classes" and I won't explain why in the context of this question.
I want to implement setter and getter on local
javascript variable. Here is an example function:
function someThing() {
var someLocalvariable = '';
}
// with this function I want to
// return value of someLocalvariable
// also if it is possible to implement
// setter in this way.
someThing.prototype.getLocalVar = function() {
}
I want variable to be 'realy' private. I don't wont
to use something like this:
someThing.prototype.someLocalvariable =
or
function someThing() {
this.someLocalvariable = '';
}
or attaching function inside someThing() like this:
function someThing() {
var someLocalvariable = '';
this.getLocalvariable = function() {
return someLocalvariable;
}
}
I would be very grateful for any guidance and assistance.
Your last example of what you don't want to do won't work (it has syntax errors), (it's been fixed) but I think you may have meant the usual way of doing this, which is to make the getter and setter closures within the constructor function (below).
Unfortunately, if you want truly private variables, this is just about your only option. There is no other way to get truly private, instance-specific variables. However, see "hack" below.
Here's the correct version of the usual way of doing this (which I think you said you don't want, but for completeness):
function SomeThing() {
var privateVar;
this.setPrivateVar = function(val) {
privateVar = val;
};
this.getPrivateVar = function() {
return privateVar;
};
}
// use:
var t = new Something();
t.setPrivateVar("foo");
console.log(t.getPrivateVar()); // "foo"
Like most, I first read of this pattern on Douglas Crockford's site.
This option does carry a downside: Every instance created via the SomeThing constructor function gets its own two functions. They cannot be shared between instances. So if there are going to be hundreds or thousands of SomeThing instances in your app, that's something to be considered from a memory perspective. If there are going to be a couple of hundred or fewer, it probably doesn't matter. (Those numbers are pulled out of a hat and you should not trust them, you'll have to review your code's memory use when/if there's some kind of issue; but you get the idea.)
The hack: If your instances will already have some kind of unique identifier on them as public data (or you're willing to add one, again it will be public), and if you're willing to add a fair bit of complication into the use of the instances, you can have a private cache that holds the data for all of your instances that only your code can access, and key into that cache via the unique identifier of the object. Like this (in this example, I'm allocating the id values, but you can use existing unique IDs if you have them):
var SomeThing = (function() {
var cache = {}, idAllocator = 0;
function SomeThing() {
this.id = ++idAllocator; // The unique identifier, can be a string if desired
cache[this.id] = {};
}
SomeThing.prototype.getPrivateVar = function() {
var data = cache[this.id];
return data && data.privateVar;
};
SomeThing.prototype.setPrivateVar = function(value) {
cache[this.id].privateVar = value;
};
SomeThing.prototype.destroy = function() {
delete cache[this.id];
};
return SomeThing;
})();
Here's how that works: All of the functions are closures over the cache local variable in the outer scoping function. We index into that using the unique ID of the object, which gives us an object on which we put our private data members. When the code using the instance is done using it, that code must call destroy (which is a major downside to this pattern) so we remove the private data object from cache by deleting the property for our id.
Caveats and costs:
You still have a public piece of data that is the key to your private data (id in the above)
Users of the instances created by SomeThing must call destroy on those instances when they're done with them. This is anathema to the way JavaScript's garbage handling works, but it's a requirement of the pattern above because otherwise you end up with cruft building up in the cache object.
(I wouldn't worry about this one) Eventually, if you're using the automatic id values above, you'll run out of them, if your app creates and destroys a lot of these instances. But JavaScript numbers go very high up indeed, and if that's an issue just find a different way to allocate IDs rather than the simplistic always-increasing system above.
I haven't had to use the pattern above in my work yet, but I expect there are use-cases for it involving thousands of SomeThing instances and thus the desire not to have per-instance functions.
Side note: In the above, I changed someThing to SomeThing. In JavaScript, the standard practice is for the names of normal functions to start with a lower-case letter, and for the names of constructor functions (ones you use with new) to start with a capital letter. Since SomeThing is meant to be used with new, I capped it. This is only convention, but it's an overwhelmingly popular one and, of course, it's used within the language definition itself (Date is a constructor, setHours is a function).
Use Object.defineProperty() in the function constructor in order to define your getter and setter more info here..
To make truly private (not visible to the outside) some values use a Closure,
more info can be found here.
In the following example we define a getter and setter for property temperature, where the inner "private" value is stored in a variable var temperature.
var temperature will never be visible/accessibly from the outside of Archiver() has it is a Closure.
Please note that this pattern works on ES5 as Object.defineProperty() it is not supported on ES3.
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function () {
console.log('get!');
return temperature;
},
set: function (value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function () {
return archive;
};
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
Something like this:
function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
Check ref: http://ejohn.org/blog/javascript-getters-and-setters/
Douglas Crockford has written this on implementing private members in JavaScript
That's not possible. If you have a local variable in someThing(), the function you attach to the prototype can't read its value (it's private, remember?). Your last example is the normal solution to this problem, why isn't this good enough for you?
Try these two ways to achieve setter and getter
var address = {
street : "No street",
city : "No city",
state : "No state",
get getAddress()
{
return (this.street+","+this.city+","+this.state);
},
set setAddress(theAddress)
{
var part = theAddress.toString().split(", ");
this.street = part[0] || "";
this.city = part[1] || "";
this.state = part[2] || "";
}
};
address.setAddress = "27 Sus Road, Pune, MH";
console.log(address.getAddress);
//Other setter and getter
function Square(side)
{
this._side = side;
};
Square.prototype = {
set setSide(side){
this._side = side;
},
get getSide(){
return this._side;
},
get getArea(){
return (this._side * this._side);
}
};
var mySquare = new Square(10);
mySquare.setSide = 15;
console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);
First method
var address = {
street : "No street",
city : "No city",
state : "No state",
get getAddress()
{
return (this.street+","+this.city+","+this.state);
},
set setAddress(theAddress)
{
var part = theAddress.toString().split(", ");
this.street = part[0] || "";
this.city = part[1] || "";
this.state = part[2] || "";
}
};
address.setAddress = "27 Sus Road, Pune, MH";
console.log(address.getAddress);
Second method
function Square(side)
{
this._side = side;
};
Square.prototype = {
set setSide(side){
this._side = side;
},
get getSide(){
return this._side;
},
get getArea(){
return (this._side * this._side);
}
};
var mySquare = new Square(10);
mySquare.setSide = 15;
console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);
I'm not entirely sure how to implement OOP concepts in JS.
I have a class which is entirely declared in its constructor:
function AjaxList(settings)
{
// all these vars are of dubious necessity... could probably just use `settings` directly
var _jq_choice_selector = settings['choice_selector'];
var _jq_chosen_list = settings['chosen_list'];
var _cb_onRefresh = settings['on_refresh'];
var _url_all_choices = settings['url_choices'];
var _url_chosen = settings['url_chosen'];
var _url_delete_format = settings['url_delete_format'];
var jq_choice_selector_form = _jq_choice_selector.closest("form");
if (DEBUG && jq_choice_selector_form.length != 1)
{
throw("There was an error selecting the form for the choice selector.");
}
function refresh()
{
_updateChoicesSelector();
_updateChosenList();
_cb_onRefresh();
};
AjaxList.prototype.refresh = refresh; // will this be called on all AjaxLists, or just the instance used to call it?
// AjaxList.refresh = refresh; // will this be called on all AjaxLists, or just the instance used to call it?
// ...
}
There are multiple instances of AjaxList. When I call refresh() on one of them, I want only that one list to refresh itself. In the following instance:
term_list = AjaxList(settings);
term_list.refresh();
The refresh() call seems to make all the AjaxLists refresh themselves. What is the correct way to do this?
I'm using jQuery, if it makes any difference.
You should not redefine the prototype function in the constructor.
If you want to create a privileged function use this.methodname = ... from the constructor.
function AjaxList() {
var privateVar = 0;
function privateFunction() {
//...
}
//create a refresh function just for this instance of the AjaxList
this.refresh = function() {
//privileged function, it can access the 'privateVar & privateFunction'
privateVar++;
}
}
//public functions that don't need access to the private variables/functions
AjaxList.prototype.publicFunction=function() {
};
Also if you want to create a proper object, you need to change
term_list = AjaxList(settings);
to
term_list = new AjaxList(settings);
AjaxList = function(settings) {
this._jq_choice_selector = settings["choice_selector"];
this._jq_chosen_list = settings["chosen_list"];
this._cb_onRefresh = settings["on_refresh"];
this._url_all_choices = settings["url_choices"];
this._url_chosen = settings["url_chosen"];
this._url_delete_format = settings["url_delete_format"];
this.jq_choice_selector_form = _jq_choice_selector.closest("form");
if (DEBUG && jq_choice_selector_form.length != 1) {
throw "There was an error selecting the form for the choice selector.";
}
};
AjaxList.prototype = {
_updateChoicesSelector: function() { },
_updateChosenList: function() { },
_cb_onRefresh: function() { },
refresh: function() {
this._updateChoicesSelector();
this._updateChosenList();
this._cb_onRefresh();
}
};
Given that structure, you should be able to call:
var ajaxList = new AjaxList(settings);
ajaxList.refresh(); // etc.
I'm using jQuery, if it makes any
difference.
No it doesn't. See my answer here: What's the difference between Javascript, Jquery and Ajax?
I have a class which is entirely
declared in its constructor
There are no classes in Javascript. Forget them. You really need to learn some of the basics of this language in order to use them. It's not Java, even though it looks similar.
If you have a Constructor Function it will create an instance. The shared methods will be in the prototype chain, and only instance specific data goes right into the function with the this keyword.
So the basic concept of an object would look like this:
// constructor of an instance
function MyObject( param1, param2 ) {
this.param1 = param1;
this.param2 = param2;
this.param3 = 32;
return this; // [optional]
}
// Public methods can be called by any instance.
// Instances share their prototype object.
// The this keyword always points to the current
// instance that calls the method.
MyObject.prototype.sum = function() {
return this.param1 + this.param2 + this.param3;
}
// refresh should be a shared method, since it
// does the same thing on every instance
MyObject.prototype.refresh = function() {
// do the refresh
// ...
}
The power of this concept is that there is only one refresh function in memory. And it can deal with any instance. In addition, if another object inherits from MyObject the refresh function will be inherited. But in the memory there will be still one shared refresh function. And it can deal with any of the parent or child instances.
I need some simple objects that could become more complex later, with many different properties, so i thought to decorator pattern.
I made this looking at Crockford's power constructor and object augmentation:
//add property to object
Object.prototype.addProperty = function(name, func){
for(propertyName in this){
if(propertyName == name){
throw new Error(propertyName + " is already defined");
}
}
this[name] = func;
};
//constructor of base object
var BasicConstructor = function(param){
var _privateVar = param;
return{
getPrivateVar: function(){
return _privateVar;
}
};
};
//a simple decorator, adds one private attribute and one privileged method
var simpleDecorator = function(obj, param){
var _privateVar = param;
var privilegedMethod1 = function(){
return "privateVar of decorator is: " + _privateVar;
};
obj.addProperty("privilegedMethod1", privilegedMethod1);
return obj;
}
//a more complex decorator, adds public and private properties
var complexDecorator = function(obj, param1, param2){
//private properties
var _privateVar = param1;
var _privateMethod = function(x){
for(var i=0; i<x; i++){
_privateVar += x;
}
return _privateVar;
};
//public properties
var publicVar = "I'm public";
obj.addProperty("publicVar", publicVar);
var privilegedMethod2 = function(){
return _privateMethod(param2);
};
obj.addProperty("privilegedMethod2", privilegedMethod2);
var publicMethod = function(){
var temp = this.privilegedMethod2();
return "do something: " + temp + " - publicVar is: " + this.publicVar;
};
obj.addProperty("publicMethod", publicMethod);
return obj;
}
//new basic object
var myObj = new BasicConstructor("obj1");
//the basic object will be decorated
var myObj = simpleDecorator(obj, "aParam");
//the basic object will be decorated with other properties
var myObj = complexDecorator(obj, 2, 3);
Is this a good way to have Decorator Pattern in javascript?
Are there other better ways to do this?
There are various implementations of the Decorator pattern in Javascript on Wikipedia and other sites - (1), (2), (3). The pattern is defined as:
the decorator pattern is a design pattern that allows new/additional behaviour to be added to an existing object dynamically.
Object extension is already build into the language itself. Objects can be easily extended, and properties can be added anytime. So why should you have to jump through hoops to achieve this? Shouldn't something like this suffice:
var person = { name: "Jack Bauer" };
// Decorated the object with ability to say a given phrase
person.say = function(phrase) {
alert(phrase);
}
// Using the decorated functionality
person.say("Damn it!");
If you want a method to apply to all objects that were created using this function, then add that method/properties to the function's prototype.
Update: If you have clearly defined pieces of functionality which can be mixed and matched as needed into certain types of objects, then the MooTools approach of extending and mixing in behavior into objects is nicely done. To give an example, consider a UI component that can be resized, dragged around with a handle, and deleted by clicking a tick mark at the top-right corner. You may not want to create each component with these behaviors but define all these behaviors separately each into their own object. And later mix in these behaviors into each type of component as needed.
var Resizable = {
...
};
var Draggable = {
...
};
var Deletable = {
...
};
var someLabel = new Label("Hello World");
// one way to do it
someLabel.implement([Resizable, Draggable, Deletable]);
// another way to do it
someLabel.implement(Resizable);
someLabel.implement(Draggable);
someLabel.implement(Deletable);
It looks better and more intuitive (to me) than doing something like
var awesomeLabel = new Resizable(new Draggable(new Deletable(someLabel)));
because we are still dealing with a label, and not some resizable, or some draggable, or some deletable object. Another small point, but still worth mentioning is that the parentheses start getting unmanageable after 3 or 4 decorators, especially without good IDE support.
I have a Javascript class that contains a few functions and member objects:
function MyUtils()
{
// Member Variables (Constructor)
var x = getComplexData();
var y = doSomeInitialization();
// Objects
this.ParamHash = function()
{
// Member variables
this.length = 0;
this.items = new Array();
// Constructor
for (var i = 0; i < arguments.length; i += 2)
{
// Fill the items array.
this.items[arguments[i]] = arguments[i+1];
this.length++;
}
}
// Functions
this.doSomething = function()
{
// Do something.
// Uses the items in the ParamHash object.
for (var i in this.ParamHash.items)
{
// Really do something!
}
// Clear the ParamHash object -- How??
}
}
This is invoked in the following manner:
// First call - works fine.
var utils = new MyUtils();
utils.paramHash = new utils.ParamHash("a", 1, "b", 2);
utils.doSomething();
// Don't want to re-initialize.
// utils = new MyUtils();
// Consequent call - crashes ["Object doesn't support this action."].
utils.paramHash = new utils.ParamHash("c", 3);
utils.doSomething();
The problem arises from the restriction that I want to reuse the same utils object throughout the code without having to re-initialize it. Also, I want the ParamHash object to be recreated from scratch everytime I call it. However, consequent calls to the ParamHash constructor throw an error "Object doesn't support this action." At this stage, I can see that the utils.paramHash object still contains the old values ("a", "b").
I have tried various ways to clear the ParamHash object such as setting it's items and length to null, popping items from the array. Nothing seemed to work until I used the following way (in the doSomething() function):
this.paramHash.items = new Array();
this.paramHash.length = 0;
This seems wrong because what if I had a lot of member variables... would I have to reset each of them individually?
So, the question is: What is the best way to reset the ParamHash object to the initial state? I'm sure hoping that there is a cleaner/more direct way. Something like :
// Doesn't work! :-(
this.paramHash = new function() {};
EDIT: I'm looking for a cross-browser solution - One that works atleast in IE6+ and FF 2+.
Solution: Thanks to Cristoph, I was able to do it by creating a separate variable/property within MyUtils which only holds the instance of the ParamHash function.
function MyUtils()
{
// Same ol' stuff.
var myParamHash;
}
// First call - works fine.
var utils = new MyUtils();
utils.myParamHash = new utils.ParamHash("a", 1, "b", 2);
utils.doSomething();
// Consequent call - works fine now.
utils.myParamHash = new utils.ParamHash("c", 3);
utils.doSomething();
This
utils.ParamHash = new utils.ParamHash("a", 1, "b", 2);
overwrites the the property which holds the ParamHash() constructor function with an instance object. You could get the constructor back via
utils.ParamHash.constructor
but the cleaner way would be to not overwrite it in the first place and use a seperate property to hold the instance.
I don't know the exact problem Cerebrus is trying to solve, so there might be valid reasons for what he's doing. But in my opinion, his solution is overly complicated. I'd do something like this:
function MyUtils() {
this.x = getComplexData();
this.y = doSomeInitialization();
this.params = {};
}
MyUtils.prototype.doSomething = function() {
for(var prop in this.params) {
if(this.params.hasOwnProperty(prop)) {
// do stuff
}
}
};
var utils = new MyUtils;
utils.params = { a : 1, b : 2 };
utils.doSomething();
The check for hasOwnProperty() is unnecessary if you can be sure that no one messed with Object.prototype.
Some additional comments:
in JavaScript, normally only the names of constructor functions are capitalized
items shouldn't be an array, but a plain object, ie this.items = {};
when you did this
utils.ParamHash = new utils.ParamHash("a", 1, "b", 2);
you replaced the ParamHash constructor function with an object instance. Subsequent new ParamHash() fails because utils.ParamHash is no longer a constructor function.
Try this:
var utils = new MyUtils();
utils.paramHashInstance = new utils.ParamHash("a", 1, "b", 2);
utils.DoSomething();
Have you tried omitting the new keyword?
utils.ParamHash = utils.ParamHash("c", 3);