Comparable questions have surely been asked before but I'd like to hear some words about my specific way of implementing Javascript classes.
Let me first start with a Javascript example taken from a real-life application I've been working on recently.
Example
PageControl= new function() {
var self= this;
// example additional control bound to page control
var grid= new GridControl();
self.initialise= function() {
// initialise form fields, controls etc.
};
// example function
self.load= function(id) {
// reloads form with new data
};
$(document).ready(function() {
self.initialise();
});
};
Each page has its own PageControl instance with specific tasks solely relevant for the given page.
Question:
I'm not looking for alternative ways of how to implement it, I'd just want to know if the above example is bad or wrong code. The above structure has worked great so far, even if I work with sub controls like PageControl.grid.reload();
but I don't want to stick to error-prone code.
3 Answers 3
I'm not sure if it's bad or wrong, but it is confusing.
Your PageControl is not a class, it's an instance of an anonymous class. In javascript a class is a function object intended to be used with the new keyword to create instances of that class.
Your code uses the new keyword on an anonymous function.
What you're trying to accomplish, I think, is usually done using the IIFE (Immediately-invoked function expression) pattern.
PageControl= (function() {
// you can create private variables and functions for use between your
// functions, or add them to the self object to make them available.
// example additional control bound to page control
var grid= new GridControl();
// Create your singleton w/ its member functions and possibly other properties
// these functions can use 'this' to reference other members of the self object.
// do it here so it can be referenced in the function closure used by
// $(document).ready
var self = {
initialise: function() {
// initialise form fields, controls etc.
},
load: function(id) {
// reloads form with new data
},
// example additional control bound to page control
grid: grid
};
$(document).ready(function() {
self.initialise();
});
return self;
})();
// your page can call those methods on the PageControl
PageControl.load("myId");
PageControl.grid.reload();
The key to the IIFE pattern is that you define a function expression that returns an object and then immediately call (execute) that function (function() {})();
.
-
The IIFE pattern is itself confusing. :-). I prefer OPs, or, even better IMHO, using
Foo.prototype.functionName = function(){}
etc...user949300– user9493002014年06月28日 22:06:23 +00:00Commented Jun 28, 2014 at 22:06 -
1I would rather create a real class, and use
Foo.prototype.methodName
for the methods myself, but IIFE is a very common js pattern that is how I think most js programmers today would do what @SaschaM78 describes.Mike Lippert– Mike Lippert2014年06月29日 01:59:41 +00:00Commented Jun 29, 2014 at 1:59 -
1Thanks for the followup. I'm fairly new to JavaScript and learning some of the strange idioms.user949300– user9493002014年06月29日 23:34:56 +00:00Commented Jun 29, 2014 at 23:34
-
2I personally don't like the
prototype
way because methods and attributes are defined outside of the class/object instead of being wrapped inside the class' body. Perhaps I should simply accept the fact that it's very common and a defacto standard.SaschaM78– SaschaM782014年06月30日 12:37:42 +00:00Commented Jun 30, 2014 at 12:37 -
@SaschaM78 I don't like it either, but more because AFAIK you have to access everything with foo.variable, while defining the methods inside the main function creates closures allowing for private variables and no prefix necessaryIzkata– Izkata2014年07月01日 00:38:53 +00:00Commented Jul 1, 2014 at 0:38
There is no "right way" to write objects in javascript. There are multiple different techniques each with pros and cons, or just different flavors.
I personally like the style that you have declare "public" functions in your example because by my experience it helps lowering the learning curve for people with OOP background.
But it penalizes because you are re-creating every function on each instantiation and that as a cost. It also makes your objects unstubbable through tools like Sinon.js, because there isn't a prototype for it to mess with.
-
2I flagged my question to be moved to the Code Review forum. Thanks for your comment, in the way I use it there is no second instance of the same class, it's more like a Singleton-approach to have exactly one instance for one page.SaschaM78– SaschaM782014年06月28日 11:36:04 +00:00Commented Jun 28, 2014 at 11:36
-
As a singleton I prefer an object literal.Grim– Grim2022年05月13日 16:04:38 +00:00Commented May 13, 2022 at 16:04
I used IIFE for years to define classes and found it to work well. It makes it simple to create singletons and keep variables and functions private. Until I came to a place where a coworker completely flipped out on me because of it and started working against me. Biggest mistake was to stay in that place for a couple more years - really toxic work place.
self.initialise();
should likely bePageControl.initialise();
in the onloadself.initialise();
. Perhaps that's because it is executed in the context of PageControl?PageControl.initialise()
is going to call the wrong function for PageControl instances made later, if the class function was reusable.self.initialise()
(defined at the top of the constructor function) is correct and is going to be the current instance in every case.