I have been using JS Modular pattern throughout the application. The modules look like the following:
var moduleName = {
prop1 : 'value1',
prop2 : 'value2',
fun1Name : function () {
// body of funName
moduleName.fun2Name(); // notice the way I am calling the function using moduleName
// Didn't use this.fun2Name()
},
fun2Name : function () {
// body of functName
}
};
And inside the modules, I have been accessing the functions using moduleName.functionName() which may also be accessed (as we all know) using this.functionName(). Now I am refactoring the code and I was just curious to know that:
Is there any reason that I should change moduleName.functionName() to this.functionName() wherever possible?
Are there any performance issues associated with both the ways of calling the module functions?
What's the best way to call the module functions inside the module itself?
It makes your code reusable between different but similar objects (typically instances of the same constructor function)
No
That's subjective
Related
Here's a basic example of what I'm trying to do:
ModuleA.js
module.exports = {
doX () {
console.log(data['a']);
}
}
ModuleB.js
module.exports = {
doX () {
console.log(data['b']);
}
}
server.js
let data = { a:'foo', b:'bar' };
let doX = {};
doX['a'] = require('./ModuleA.js').doX;
doX['b'] = require('./ModuleB.js').doX;
doX['a'](); // Should print 'foo'
doX['b'](); // Should print 'bar'
In the actual implementation there would be many more variables to pass in than just data, so passing that to the functions isn't a viable solution.
This almost works, but the functions in the modules need access to functions and variables at the top level of the server file. I know I could global.variable all of my variables and functions but I'd rather not, as I've only seen people recommend against that. Of course I could pass every single variable and function in each function call, but that would look ridiculous and brings up way too many potential problems. I was hoping I could pass a reference to the server's namespace, by passing this or something, but that didn't work. I could register every function and variable on some object and pass that around, but that's inconvenient and I'm trying to refactor for convenience and organization. I think I could read in the module files and eval them, as seen here, but I would much rather use the standard module.exports system if possible.
I'll summarize my comments into an answer.
Your data variable is local to server.js and is not accessible to your other two modules. I'd suggest you pass it to them when you load those modules as a means of sharing it with them. That design pattern is typically called a "module constructor" if you want to read more about it.
Passing data from one module to another is how you achieve shared data with separate modules without using globals. That's how you do it. Since you've now rejected the usual design pattern, there's not much else we can do without understanding a lot more about the real problem so we can go further outside your box and suggest a better design than the path you're down.
Abstracting hardware to have a common set of methods sounds like a perfect fit for subclasses where each piece of hardware has its own subclass, all with the same interface. Shared data could be in the base class.
You can pass a lot of variables at once if you make them properties of an object and pass just the object. Then, both places can reference the same properties on the same object and you can pass an infinite number of properties by passing one object. There is no way to pass a modules namespace. You have to create your own object with properties on it and pass that. You can create such an object and then set that object into the base class and then all your derived classes can have access to that object.
In short:
module.exports = {
doX () {
console.log(data['a']);
^^^^ this variable is not available here. You should pass it as argument to make it available.
}
}
I am using Node.js. I defined a custom method to the String obj like this:
if (!String.prototype.myMethod) {
String.prototype.myMethod= function () {
//do something
return this;
};
}
I found that myMethod maybe used in many different files, so that I have to require the file where this piece of code in. Is there any way that does the many 'requires' ?
Don't do that.
Node is intentionally designed in a module pattern, where each module gets it's own scope to run in and without polluting the global variables. This very intentional and very important.
https://nodejs.org/api/modules.html#modules_the_module_wrapper
I am working on a web project where in the UI jsp pages. All the jquery/javascript methods are called via this pattern
A.b.c.d.methodName()
There are many .js files imported in the jsp page. So I have to search in Eclipse IDE
to track the method js file.
In the js file which has an entirely different name not "A.b.c.d", the method is declared as
methodName: function()
{ // logic }
Can anyone tell me what is this style/pattern of using jquery.
JavaScript never looks for file names, the "namespacing" you see there is achieved by objects nested in each other as properties.
For example if you create an object like:
var A = {
b: {
c: {
d: {
methodName: function () {
console.log('What a nice method!');
}
}
}
}
};
You can call it like this:
A.b.c.d.methodName();
Or you can add methods later in your code:
var irrelevantName = function () {
console.log('This method is even nicer');
};
A.b.c.method2 = irrelevantName;
And call it by:
A.b.c.method2();
There is a much used extend method which has surfaced in lot of JavaScript frameworks, like jQuery or MooTools. This provides a way for safely extending an object while preserving original values if present.
You can use the jQuery one like:
$.extend(A.b.c.d, {
method3: function () {
console.log('An other nice method');
}
});
And as you expect, it can be called as:
A.b.c.d.method3();
JavaScript libraries usually use namespacing: they create some kind of an object and populate it with all their methods. This way they don't pollute the global namespace with their methods.
There are a lot of ways to add new properties to an object in JS, so it is not always obvious how a method is added to an object, but it is safe to say that file names have nothing to do with it.
For further reading on the subject, I would recommend this google search. Basically any of the top 20 results should explain how namespaces are created and used in JavaScript.
On a footnote: I'm not sure how does the Eclipse tooling support JS, but as it is not a trivial problem (object structure can be modified on the fly) I would not be surprised if Eclipse had no understanding of JavaScript namespacing.
Looks like it has some sort of namespacing. The code could be using could be the AMD pattern? But again, if it's JSP it might be old....
I am wondering where to add global variables for an ExtJS Application. I already looked at some suggestions in stackoverflow that mention that you can add them inside app.js. But, can anyone be more specific? My app.js looks something like this:
Ext.application({
launch: function() {..}
});
So, where exactly do the variables go? In the launch function? Outside Ext.application?
Better approach would be to create a separate class to hold such global constants. Then you should just put that constants class as requires in app.js.
Ext.define("App.Constants", {
singleton : true,
BASE_URL : "http://localhost:8080/",
LABLE_HEADER : "geekrai.blogspot",
TIMEOUT : 6000
});
This will ensure that class is loaded and now you can access any property/global value.
I have mentioned the same in detail on my blog : link
Declare your own object namespace and add them there:
Ext.ns('My.Application.Globals');
My.Application.Globals.SomeValue = 5;
My.Application.Globals.SomeText = 'Hello World!';
However globals are usually frowned upon unless absolutely needed, so try and get around using them if you can.
I know you already accepted an answer which is fine. I just wanted to add an MVC way to include namespaced variables available to the app. There is one caveat to these 'globals' - you can not use them in your class definitions. Meaning you can not reference your app in Ext.define({}) methods. They have to be use in initComponent method or later.
So here is what I do:
Ext.application({
name:'MyApp',
appFolder:'js/app',
controllers:[ 'Main' ],
autoCreateViewport : true,
launch:function () {
console.log("App Launched!");
MyApp.app = this; //added this to get reference to app instance. IMPORTANT!
},
//variables used throughout the app
globals:{
myURL:'http://example.com',
magicNum:5
}
});
To use these application wide variables you reference your app namespace and so do not pollute the global space. Like this:
MyApp.app.gloabals.magicNum
Aside from whatever features may be built into Ext, you can always use an immediate function to create a closure:
(function(){
var globalVariable = 'foo';
Ext.application({
launch: function() { alert(globalVariable); }
});
})();
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.