How do I define a class I can instatiate later?
I wrote myself a rotator class using jquery which looks like:
var Rotator =
{
Loop: null,
init: function(identifierName)
{
........
}
}
If i want to have one rotator on my page it's good. I just call Rotator.init() and it's ready.
However when I want to have 3 rotators i got to define 3 times the whole class code changing its name.
Way easier it would be if I could just do
Instance1 = new rotator;
Instance2 = new rotator;
Instance3 = new rotator;
The following is what your object literal might look like as a re-usable Named Function that can be instantiated multiple times:
var Rotator = function(name) {
this.Name = name;
this.Loop = null;
this.init = function(identifierName)
{
this.Name = identifierName;
};
};
// usage:
var foorotator = new Rotator('foo');
var barrotator = new Rotator('bar');
alert(foorotator.Name);
alert(barrotator.Name);
http://jsfiddle.net/JzWCL/
After Edit:
http://jsfiddle.net/mPzsq/
Xander's solution looks like an acceptable form for a class-like object used only once. If you plan to subclass or multiply instantiate it, however, you should apply methods to the prototype rather than defining them within the main class (constructor) function. For example:
var Rotator = function(name) {
//run your initialization logic inside this constructor function
this.Name = name;
this.Loop = null;
}
Rotator.prototype.someMethod = function() {
//method code
}
var rotator1 = new Rotator('foo');
var rotator2 = new Rotator('bar');
The reason to use this structure is to prevent the methods from being reconstructed every time the class is instantiated. By applying the methods to the prototype, they will be shared between all instances of the class.
I've found this to be a helpful reference for some basics of JavaScript class definition:
3 Ways to Define a JavaScript Class
Related
While I am writing a constructors' methods like the "runGame" method of the "Game" constructor, if I need to reference a property of the "GameBoard" constructor should I use the name of the constructor, like this:
function Game(){
this.runGame(){
var someProp = GameBoard.otherProp;
}
}
or do I have to create an instance of the constructor object first and then refer to the instance like this.
var newGameBoard = new GameBoard();
function Game(){
this.runGame(){
var someProp = newGameBoard.otherProp;
}
}
If I've understood your question in the right way, what you need is composition and you need to inject associated instances during construction time:
function Game(gameBoard) {
this.gameBoard = gameBoard;
}
Game.prototype = {
runGame: function() {
// You access injected GameBoard through the
// own Game object's property "this.gameBoard"
var someProperty = this.gameBoard.someProperty;
}
};
var gameBoard = new GameBoard();
var game = new Game(gameBoard);
Further reading:
Dependency injection (Wikipedia)
Object composition (Wikipedia)
If every Game has a GameBoard, it should be a property:
function Game(){
this.board=new Board();
}
Game.prototype.runGame=function(){//real inheritance
var someProp = this.board.otherProp;
};
If the GameBoard(s) belong to the Game in your logic, here's how I'd do it
var Game = function(params) {
this.options = params.options; // it could prove useful to instanciate a game using a set of rules
this.gameBoards = params.gameBoards; // Already instanciated gameBoard(s)
this.activeGameBoard = null; // if there are many gameboards it might be a good idea to keep track of the one that's currently active
this.prop = '';
// ... Initialize all the properties you need for your Game object
}
Game.prototype = {
runGame: function(gameBoardIndex) {
this.activeGameBoard = this.gameBoards[index];
this.someProp = this.activeGameBoard.someProp;
}
}
I know I'm assuming a lot of things but I can't help it, it reminds me the only project I worked on that involved games and gameboards :p
I have built a large application using JavaScript prototype and inheritance.
But I am having a hard time organizing my code.
For example I have a class carousel which has many functions like this:
Carousel.prototype.next = function () {...}
Carousel.prototype.prev = function () {..}
Carousel.prototype.bindControls = function () {..}
I would like to organize my code like this :
Carousel.prototype.controls = {
next: function () { ... } ,
prev: function() { ... },
bindControls: function () { .. }
}
But this will cause the value of "this" being lost. I can keep track of it using a global instance but this will cause problems when the class is inherited for example In another file I have something like this to override parent class
BigCarousel.prototype.next = function () {...}
My inheritance is done like this:
Function.prototype.inheritsFrom = function (parentClass) {
if (parentClass.constructor === Function) {
//Normal Inheritance
this.prototype = $.extend(this.prototype , new parentClass);
this.prototype.constructor = this;
this.prototype.parent = parentClass.prototype;
}
else {
//Pure Virtual Inheritance
this.prototype = $.extend(this.prototype, parentClass);
this.prototype.constructor = this;
this.prototype.parent = parentClass;
}
return this;
};
So I can do:
BigCarousel.inheritsFrom(Carousel)
Does anyone know how can I work around the "this" value ?
You could make Controls a class of it's own:
var Controls = function (controllable_object) {
this.ref = controllable_object;
};
Controls.prototype.next = function () {
this.ref.foo();
}
// ..
var Carousel = function () {
this.controls = new Controls(this);
};
// ..
This doesn't allow you to override the implementation of Controls though. With more dependency injection you'd get something like:
var Controls = function (controllable_object) {
this.ref = controllable_object;
};
Controls.prototype.next = function () {
this.ref.foo();
}
// ..
var Carousel = function () {
this.controllers = [];
};
Carousel.prototype.addController = function (controller) {
this.controllers.push(controller);
};
// ..
var carousel = new Carousel();
carousel.addController(new Controls(carousel));
My inheritance is done like this:
$.extend(this.prototype , new parentClass);
Ouch. This is not inheritance (with new BigCarousel instanceof Carousel), but just copying properties. Maybe this is enough for you, but then you should call it mixin. Also, you should avoid using new for inheritance.
But this will cause the value of "this" being lost. How can I work around that?
It's impossible to have this point to the parent object with nested properties (as long as you don't want to explicitly set it every time). You have only two choices:
Forget it, and organize your methods by prefixing them (controlNext, controlBind, …)
Give each of your carousels its own controls object. For inheritance, make them CarouselControls instances for example. This especially fits well if those controls are quite independent from the carousel, and don't need to access the carousel they're attached to everywhere. If they are not, you still can pass a reference to the parent carousel into their constructor for example:
this.controls = new CarouselControls(this);
Also, for customizing the controls in different carousels, you might have to subclass the CarouselControls as well - or you prepare your Controls object to serve for different carousels in general, so that from BigCarousel you can
Carousel.call(this); // make this a carousel
this.controls.activate({big: true, fast: false}); // or something
You can use the .bind method of Function.
In Javascript Functions inherit from Object, so they have their own methods. One of those methods is .bind:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
Also you are doing inheritance wrong, the right way with raw Javascript is:
ChildClass= function() {
ParentClass.apply(this, arguments); //calling parent constructor
//constructor
};
ChildClass.prototype= new ParentClass();
Then you can simply do this on your constructor:
Courossel= function() {
ParentClass.apply(this, arguments); //calling parent constructor
this.controls.next.bind(this);
this.controls.prev.bind(this);
this.controls.bindControls.bind(this);
}
But I have to say that Frits suggestion is better, make the controls their own class and instantiate it on Carousel constructor passing a reference to your Carousel instance (the this keyword). Just don't call it ".ref", it's confusing.
I have built a large application using JavaScript prototype and inheritance.
But I am having a hard time organizing my code.
For example I have a class carousel which has many functions like this:
Carousel.prototype.next = function () {...}
Carousel.prototype.prev = function () {..}
Carousel.prototype.bindControls = function () {..}
I would like to organize my code like this :
Carousel.prototype.controls = {
next: function () { ... } ,
prev: function() { ... },
bindControls: function () { .. }
}
But this will cause the value of "this" being lost. I can keep track of it using a global instance but this will cause problems when the class is inherited for example In another file I have something like this to override parent class
BigCarousel.prototype.next = function () {...}
My inheritance is done like this:
Function.prototype.inheritsFrom = function (parentClass) {
if (parentClass.constructor === Function) {
//Normal Inheritance
this.prototype = $.extend(this.prototype , new parentClass);
this.prototype.constructor = this;
this.prototype.parent = parentClass.prototype;
}
else {
//Pure Virtual Inheritance
this.prototype = $.extend(this.prototype, parentClass);
this.prototype.constructor = this;
this.prototype.parent = parentClass;
}
return this;
};
So I can do:
BigCarousel.inheritsFrom(Carousel)
Does anyone know how can I work around the "this" value ?
You could make Controls a class of it's own:
var Controls = function (controllable_object) {
this.ref = controllable_object;
};
Controls.prototype.next = function () {
this.ref.foo();
}
// ..
var Carousel = function () {
this.controls = new Controls(this);
};
// ..
This doesn't allow you to override the implementation of Controls though. With more dependency injection you'd get something like:
var Controls = function (controllable_object) {
this.ref = controllable_object;
};
Controls.prototype.next = function () {
this.ref.foo();
}
// ..
var Carousel = function () {
this.controllers = [];
};
Carousel.prototype.addController = function (controller) {
this.controllers.push(controller);
};
// ..
var carousel = new Carousel();
carousel.addController(new Controls(carousel));
My inheritance is done like this:
$.extend(this.prototype , new parentClass);
Ouch. This is not inheritance (with new BigCarousel instanceof Carousel), but just copying properties. Maybe this is enough for you, but then you should call it mixin. Also, you should avoid using new for inheritance.
But this will cause the value of "this" being lost. How can I work around that?
It's impossible to have this point to the parent object with nested properties (as long as you don't want to explicitly set it every time). You have only two choices:
Forget it, and organize your methods by prefixing them (controlNext, controlBind, …)
Give each of your carousels its own controls object. For inheritance, make them CarouselControls instances for example. This especially fits well if those controls are quite independent from the carousel, and don't need to access the carousel they're attached to everywhere. If they are not, you still can pass a reference to the parent carousel into their constructor for example:
this.controls = new CarouselControls(this);
Also, for customizing the controls in different carousels, you might have to subclass the CarouselControls as well - or you prepare your Controls object to serve for different carousels in general, so that from BigCarousel you can
Carousel.call(this); // make this a carousel
this.controls.activate({big: true, fast: false}); // or something
You can use the .bind method of Function.
In Javascript Functions inherit from Object, so they have their own methods. One of those methods is .bind:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
Also you are doing inheritance wrong, the right way with raw Javascript is:
ChildClass= function() {
ParentClass.apply(this, arguments); //calling parent constructor
//constructor
};
ChildClass.prototype= new ParentClass();
Then you can simply do this on your constructor:
Courossel= function() {
ParentClass.apply(this, arguments); //calling parent constructor
this.controls.next.bind(this);
this.controls.prev.bind(this);
this.controls.bindControls.bind(this);
}
But I have to say that Frits suggestion is better, make the controls their own class and instantiate it on Carousel constructor passing a reference to your Carousel instance (the this keyword). Just don't call it ".ref", it's confusing.
I have code like this:
function Food(type) {
this.type = type;
this.timesEaten = 0;
}
Food.prototype.eat = function() { // Dependent function
this.timesEaten++;
}
Food.prototype.pasta = function() { // In-dependent function
return new Food("pasta")
}
So, I want to be able to use the pasta function without defining a new food, like this:
var pasta = Food.pasta()
Buut, that doesn't work, you have to do like this:
var pasta = new Food().pasta()
Well "Food.pasta()" does work if you set up Food like this:
var Food = {
pasta: function() {
return {type: pasta};
}
}
But then new Food won't work, which means I'll have to use "return {type: pasta}".
I wonder, is there any way to create a Food that can be both dependent and independent?
A method like your .pasta() method that does not operate on any instance data is called a static method. You don't want it on the prototype because the prototype will only be in the lookup chain on an instantiated object (after creating an actual Food object by doing new Food()).
Instead, for a static method you can put it on the constructor function itself like this:
Food.pasta = function() {
return new Food("pasta");
}
The, you can call it like this:
var pasta = Food.pasta();
It's useful to remember that in javascript, Functions are objects too so they can have properties/methods and when you're looking for a place to put static functions or data that don't belong to a particular instantiated object or need to be called on a particular instantiated object, the Constructor object is often a good place to put them.
function Food(type) {
this.type = type;
this.timesEaten = 0;
}
Food.prototype.eat = function() { // Dependent function
this.timesEaten++;
}
Food.pasta = function() { // In-dependent function
return new Food("pasta")
}
Food.prototype functions are only available for objects of Food, while for Food.pasta Food is only a namespace object.
Usage:
Food.pasta();
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.