Javascript from Module to Class - javascript

I have a javascript module which looks like this:
var myModule = {
settings: {
myage: 25
},
init: function() {
//init code here
},
someFunction1: function(param1) {
//function code here
},
someFunction2: function() {
myModule.someFunction1(myparam);
}
}
I like the structure of modules because it can keep related functions together.
My question is...
Is it bad coding practice to use modules and not classes?
How can I convert the code above to a class? Would it be very hard?

Is is bad coding practice to use modules and not classes?
No!
At least if your module is immutable. If you are dynamically modifying it, you essentially have introduced global state, and that is a bad practise. Also I'm not sure whether these "settings" are supposed to be global or not - if there is any reason (and be it for testing only) to have multiple module instances with different settings, then a class would be appropriate.
How can I convert the code above to a class? Would it be very hard?
Don't when you don't need to. But no, it wouldn't be very hard:
class MyModule {
constructor() {
this.settings: {
myage: 25
};
//init code here
}
someFunction1(param1) {
//function code here
}
someFunction2() {
this.someFunction1(myparam);
}
}
Instead of doing myModule.init(), you'd call var myModule = new MyModule();.

Related

How to handle inheritance with public and private functions within factory functions in JavaScript?

I am the team lead of a group of ~8 developers. We look after a large website which is split into many 'components' (a component could be a gallery for example - with libraries aside, these 'components' are standalone). We are in the process of splitting things up and part of that task is creating Gulp code to handle the various stages of processing for each of these components (SCSS processing, concatenation, image optimisation etc).
So, I need to come up with a pattern that the team can follow when creating Gulp code for a new 'component'. I need to keep this as simple as possible as many of the developers are new to Gulp. The general idea I want to get to is that we have a base Gulp 'component', which will have all code required to process a standard 'component', but I expect there will be some 'components' that need special gulp code. So, I would like to be able to extend the base Gulp 'component' compilation code in these cases.
In an attempt to learn and to set up a strong foundation for the team have been doing some reading on best approaches to inheritance in JavaScript. I have come across quite a rift in the way people feel about this. What approaches I have considered and what I've gathered:
There are classes in ES6 which I can use in node.js. These classes are shunned by a lot of the big names in the JavaScript world as well as big names from the past (when using classical style languages) for reasons such as it encourages brittle code. Also, you cant do classic style public and private properties/functions, so I struggle to see any real reason why I should go with this.
If I did go this route, I feel I would end up with something like this (code is untested / probably not correct, i'm just dumping my thoughts):
class Component {
constructor(options) {
},
build() {
},
dev() {
}
test() {
},
// Should be private, but wont be
_processStyles() {
},
_processScripts() {
}
}
Factory functions. We're used to using these with the revealing module pattern, and generally I like them. I also believe that Douglas Crockford is a fan of factory functions, so I feel I'm on good ground with this. Now, if I create public and private methods (by returning an object with references only to my public functions) and then I want to extend 'component', in the new factory I would create an instance of 'component' and then extend that. The problem is that I can't override (or even call) the private functions of my 'component' instance, because they are in a different scope that I have no access to. I did read that one way to get around this is to use an object to create a reference to all of the private methods, but then they're not private anymore, so it defeats the object (no pun intended).
var component = function(options) {
var init = function() {
};
var build = function() {
};
var dev = function() {
};
var test = function() {
};
var _processStyles = function() {
};
var _processScripts = function() {
};
return {
init: init,
build: build,
dev: dev,
test: test
};
};
var specialComponent = function(options) {
// Create instance of component
var cmp = component(options);
// Extend it
cmp.extraFunction = function() {
// This will throw an error as this function is not in scope
_processStyles();
}
// Private functions are available if I need them
var _extraPrivateFunction = function() {
}
return cmp;
}
So, I feel like I've missed something somewhere, like I need someone to point me in the right direction. Am I getting too hung up about private functions (feels like it)? Are there better approaches? How would something like this, which seems to lend itself to classical inheritance be best tackled in a DRY (don't repeat yourself) manner?
Thanks in advance,
Alex.

Mixing object construction with application logic

I've started refactoring my code to make it testable. One area I've found a problem is where I've mixed object construction with application logic. If I have a constructor called SomeClass which performs application logic but also instantiates another class I run in to problems when I try to test:
function SomeClass() {
//does lots of application type work
//but then also instantiates a different object
new AnotherClass();
}
Testing becomes difficult because now I need to find a way to create AnotherClass in the test environment.
I've dealt with this problem using dependency injection. So SomeClass takes an instance of AnotherClass as a parameter:
function SomeClass(anotherObj) {
}
Problem with this is as far as I can see is all this does is defer the problem to somewhere else in my application. I still have to create the anotherObj from AnotherClass somewhere else in my code.
This google testing article http://googletesting.blogspot.co.uk/2008/08/by-miko-hevery-so-you-decided-to.html suggests:
In order to have a testable code-base your application should have two
kinds of classes. The factories, these are full of the "new" operators
and are responsible for building the object graph of your application,
but don't do anything.And the application logic classes which are devoid of the "new" operator and are responsible for doing work.
This sounds exactly like my problem and the factory type pattern is what I need. So I tried something like:
function anotherClassFactory() {
return new AnotherClass();
}
function SomeClass() {
anotherClassFactory();
}
But then SomeClass still has a dependency on the factory. How do I get around this correctly?
(I'm making this a community wiki answer because I frankly think it only answers part of the question, while leaving too much unsaid. Hopefully others with more knowledge can improve it.)
But then SomeClass still has a dependency on the factory. How do I get around this correctly?
According to this article linked by the one you linked, you do it like this:
anotherclass.js:
function AnotherClass() {
}
AnotherClass.prototype.foo = function() { /* ... */ };
AnotherClass.prototype.bar = function() { /* ... */ };
AnotherClass.prototype.baz = function() { /* ... */ };
someclass.js:
function SomeClass(a) {
// ...app logic...
// Use AnotherClass instance `a`; let's say you're going to call `foo`,
// but have no use for `bar` or `baz`
a.foo();
// ...app logic...
}
someclass-test.js:
function someClass_testSomething() {
var sc = new SomeClass({
foo: function() { /* ...appropriate `foo` code for this test... */}
});
// ...test `sc`...
}
function someClass_testSomethingElse() {
// ...
}
app.js:
function buildApp() {
return {
// ...lots of various things, including:
sc: new SomeClass(new AnotherClass())
};
}
So the real app is built using buildApp, which gives SomeClass its AnotherClass instance. Your tests for SomeClass would use someClass_testSomething and such, which uses the real SomeClass but a mocked-up instance rather than a real AnotherClass containing just enough of it for the purposes of the test.
My dependency-injection-fu is weak, though, and I frankly don't see how buildApp scales to the real world, nor do I see what you're supposed to do if a method has to create an object to do its job, e.g.:
SomeClass.prototype.doSomething = function() {
// Here, I need an instance of AnotherClass; maybe I even need to
// create a variable number of them, depending on logic internal
// to the method.
};
You're not going to pass everything the method needs as arguments, it would be a spaghetti nightmare. This is probably why for more static languages, there are usually tools rather than just coding patterns involved.
In JavaScript, of course, we have another option: Just go ahead and use new AnotherClass in the code:
anotherclass.js:
function AnotherClass() {
}
AnotherClass.prototype.foo = function() { /* ... */ };
AnotherClass.prototype.bar = function() { /* ... */ };
AnotherClass.prototype.baz = function() { /* ... */ };
someclass.js:
function SomeClass() {
// ...app logic...
// Use AnotherClass instance `a`; let's say you're going to call `foo`,
// but have no use for `bar` or `baz`
(new AnotherClass()).foo();
// ...app logic...
}
someclass-test.js:
var AnotherClass;
function someClass_testSomething() {
// Just enough AnotherClass for this specific test; there might be others
// for other tests
AnotherClass = function() {
};
AnotherClass.prototype.foo = function() { /* ...appropriate `foo` code for this test... */};
var sc = new SomeClass();
// ...test `sc`...
}
function someClass_testSomethingElse() {
// ...
}
You use anotherclass.js and someclass.js in your real app, and you use someclass.js and someclass-test.js when testing SomeClass.
That's a rough sketch, of course; I'm assuming your real-world app probably doesn't have globals (SomeClass, AnotherClass) all over the place, but however it is you're containing SomeClass and AnotherClass can presumably also be used to contain SomeClass, and to contain the tests for it and their various fake AnotherClasss.

About Revealing module pattern in JavaScript

I'm currently building a mobile web application with jQM, Highcharts and HTML5.
To maintain the JavaScript code, I decided to apply Revealing module pattern to the code.
Here is my code.
var MobileWebV1 = function () {
function _buildPanelMenu(pageId, isNormalMenu) {
}
function _buildHeaderBar(pageId, isNormalMenu) {
}
return {
buildPanelMenu: _buildPanelMenu,
buildHeaderBar: _buildHeaderBar
};
}();
I'm wondering if I can add another hierarchy to categorize methods in the object.
I want to add 'UserInterface' and 'Util.' In that case, I can call the method like this: MobileWebV1.UserInterface.buildPanelMenu('pageHome', false);
I tried to modify my objecy, but I'm still stuck with the current issue.
If you know the answer, then please share your knowledge.
Just nest the object literals:
return {
Util: {
…
},
UserInterface: {
buildPanelMenu: _buildPanelMenu,
buildHeaderBar: _buildHeaderBar
}
};

Node.js Module plugins

I was hoping to find out what the best practices are for writing Node.js modules, specifically for the type of javascript pattern to follow for code separation.
One style I've been using, is this:
var Something;
Something = (function() {
function Something() {
}
Something.prototype.some = function() {
}
return Something;
})();
module.exports = Something;
Another style would be :
module.exports = {
item: "one",
some: function() {
},
another: function() {
}
}
Is there any reason why the second method would not be advised, in node.js? or is there another format that would be preferred and what would the advantages be?
Thank you!
You run into issues using the 'this' keyword. Which you have to use instead of 'Something'. So Something.some() you can run... But if you wanted to run that on the bottom, you'd have to run this.run(). The scope of this changes within other functions and can get messy.
There are several variants including assigning properties directly to exports, assigning a new object literal to module.exports and a few others. For the most part they are just syntax sugar or syntax alternatives that accomplish exactly the same thing. My personal preference is to leave as much of my code as possible unpolluted pure JS, and keep the CommonJS idioms separate. So I do:
function myFunction() {
}
var MY_STRING = "Forty-two";
module.exports = {
myFunction: myFunction,
MY_STRING: MY_STRING
};
It's a bit boilerplate-y and prone to maintenance mistakes, but I prefer it to the alternatives as I really dislike putting the CommonJS module level names (module, exports) sprinkled throughout my code. CoffeeScript makes the last part easier since you can just do:
module.exports = {
myFunction
MY_STRING
}

What is meant by “leaking” into global scope?

A while ago, I offered-up a JavaScript design pattern (the Module Pattern - see below) that I got from a John Resig example as part of a solution to someone’s question and I received the following comment:
“…that pattern is a bit over
engineered and not that good. Still
leaking into global-scope. and your
not opening yourself to async loaders.
But it is better then just ad-hoc
coding !”
So…
If “leaking” into global scope means “your object gets appended to the browsers window (object)”…then everything already gets appended (globally):
This “leaks” into global scope:
window.jQuery
…just call: window.jQuery and it resolves as a function();
This “leaks” into global scope:
function HelloWorld() { alert(‘Howdy’); }
…just call: window.HelloWorld() and you will get ‘Howdy’.
This “leaks” into global scope:
var myVariable = 10;
…just call: window.myVariable and you will get 10
If the commenter is correct, then all the above “leak” into global-scope. So, personally, I don’t see a way NOT to “leak” into global-scope as even your form controls exists there (as well).
As such, here are my questions…
What is meant by “leaking” into
global-scope?
Why is that bad?
How do you avoid it?
When wanting to create persistent
custom-objects, why is the Module
Pattern (below) bad?
Design patterns let you encapsulate
complex logic, is encapsulation
suddenly bad simply because we’re
writing in JavaScript?
Or...is this commenter simply wrong?
Here is the Module Pattern I Mentioned Above:
<script type="text/javascript">
var myNamespace = (function($) {
var publicInstances = {};
// ***********************
// myObject
publicInstances.myObject = myObject;
function myObject() {
/// <summary>A pointer to this</summary>
var self = this;
this.someProperty = new String();
this.initialize = function() {
/// your code here
}
this.someMethod = function() {
/// your code here
}
self.initialize();
}
return publicInstances;
})(jQuery);
jQuery(document).ready(function() {
// Use would look like
var myInstance = new myNamespace.myObject();
});
</script>
UPDATED:
I’m satisfied with the answers below and want to thank everyone for taking the time to comment.
TO RECAP THE ANSWERS BELOW:
"Leaking" into global-scope occurs when something used in local-scope is unintentionally made available to the global-scope (e.g. the window object). This is bad because it opens the page to potential naming collisions which could result in variables resolving to unexpected values or types.
Intentionally making a variable global is not considered a "leak". However, properly namespacing the object is required to reduce potential for said naming collisions.
You cannot avoid globally-scoped variables, but you can reduce the above risks by using asynchronous-loaders and defining-modules made available in plug-ins like RequireJS or Curl.
"Leaking" into global scope is when something used in a local scope is unintentionally made available to the global scope. That means assigning to a variable not already defined in the current scope:
function myFunction() {
a=1;
}
myFunction();
alert(a);
//-> 1
It's bad because there could be naming collisions resulting in variables with different values/types than expected. It can also lead to a bug in older Internet Explorers when you forget to use the var keyword for a variable used in a for statement.
I wouldn't class intentionally making a variable global as "leaking", because it's more like you're "pouring" it into the global scope. However, this is still often considered bad practice by some (although I think that's a little melodramatic) because there are still potential naming collisions with current properties of the window object, or variables set by other scripts and libraries.
[[Short story]]
Don't make global variables ever and use an async module loader like requirejs or curl
[[Long story]]
That comment was poorly structured.
There is nothing wrong with the module system. I was complaining about using global variables at all. (I still think the full generic module pattern is bloated).
Whether you should avoid all global variables is a different question and I think a matter of style. You can either use an async loader to pass modules around or using window to pass modules around.
What is meant by “leaking” into global-scope?
What I meant was your creating global variables. Minimising the use of global variables is a pattern. In functional style programming it's possible to have zero global variables but this is a different pattern from using global modules.
Why is that bad?
Having any state globally can cause that state to be corrupted.
How do you avoid it?
You can't. You can minimize the amount of global variables though. To avoid having global state completely you can use asynchronous loaders. These define a few global variables for you that you can then use.
When wanting to create persistent custom-objects, why is the Module Pattern (below) bad?
There is nothing wrong with the module pattern. The problem is storing your module globally. The issue is having global namespaces.
Design patterns let you encapsulate complex logic, is encapsulation suddenly bad simply because we’re writing in JavaScript?
Now that I've cleared up the intent of the comment this question isn't really relevant
Or...is this commenter simply wrong?
The comment was poorly phrased at best. I objected to global namespaces rather than modules, but did not state this properly.
The alternative is using asynchronous loaders and defining modules. These can be narrowed down to two global variables. define and require.
require = function(moduleName, callback)
This will get a module and then return it to you.
define = function(obj)
this defines a module.
The concept here is that you multi file code as follows:
// main.js
require([
"foo.js",
"bar.js",
...,
], function(foo, bar, ...) {
// do stuff
});
//foo.js
(function() {
var namespace = modulePatternCode;
...
define(namespace):
})();
//bar.js
(function() {
var namespace = modulePatternCode;
...
define(namespace):
})();
Your module only "leaks" it's namespace holder so it's pretty acceptable.
Loader example using RequireJS:
Define a utilities module in utils.js:
define(function () {
return {
each: function (iterable, callback) {
// ...
},
map: function (iterable, mapper) {
// ...
}
};
});
Use the above module in another module, say math.js:
define([ "utils" ], function (utils) {
return {
sum: function (numbers) {
var sum = 0;
utils.each(numbers, function (n) {
sum += n;
});
return sum;
},
average: function (numbers) {
return this.sum(numbers) / numbers.length;
}
};
});
And you can use math.js in another file, say main.js:
console.log("About to add 1-3");
require([ "math" ], function (math) {
console.log(math.sum([ 1, 2, 3 ]));
});
You can still have namespaces, and still keep them warm and cozy inside modules:
namespace.js:
define([ "foo", "bar", "moo" ] function (foo, bar, moo) {
return {
foo: foo,
bar: bar,
moo: moo
};
});
Then the rest of the modules can use this namespace during definition:
define([ "namespace" ], function (namespace) {
namespace.foo(42);
});
Or at runtime, in some other module:
define(function () {
return {
initialize: function () {
require([ "namespace" ], function (namespace) {
namespace.foo(42);
});
}
};
});
In the usages above, nothing but define and require are global. Of course, these are just illustrative examples, as there are many different flavors of defining/using modules in RequireJS.

Categories

Resources