This is a JS newbie questions, I am working with a parent namespace Base and I include all my code within this namespace.
file model.js
Base = {}
Base.Observer = {
method1 : function(){//...},
method2 : function(){//...}
};
Base.Bot = function(name){
this.name = name;
this.somefunc = function(){};
}
file presenter.js
Base.Presenter = {
}
file helper.js
Base.Helper = { };
Now my problem is I would like to keep this module private. Without allowing any user access through any browser tools like firebug. So I could only think of wrapping them within a self executing anonymous function and making Base into a local variable which would lead to the presenter.js and helper.js not being able to access the Base namespace.
I would like to keep the files separate as it helps in keeping code organizated but I can't seem to figure what is the correct way to do this. Would appreciate any help on this.
Thank you
So I could only think of wrapping them within a self executing anonymous function and making Base into a local variable
That is the usual approach
which would lead to the presenter.js and helper.js not being able to access the Base namespace.
The function should return Base; which you then assign to a global.
See the module pattern
Related
I am new to JavaScript and trying to make a simple node server. Here is my code:
var activeGames = {}
exports.initialize = function(){
var gameID = "game12345"
activeGames.gameID = new Game(gameID, "player1", "player2")
}
I call the initialize function from another module, and I get an error stating that activeGames is undefined. activeGames is at the outermost scope of the file. I tried adding 'this' before activeGames.gameID but that did not fix it. Why is activeGames undefined? Thanks in advance.
EDIT: Here's how I'm calling this code.
In my base index file I have
const handler = require("./request-handler.js")
handler.initialize()
In request-handler.js, I have
var gameManager = require('./game-manager')
exports.initialize = function(){
gameManager.initialize()
}
JavaScript has lexical scope, not dynamic scope.
ref: https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping
Lexical scope means that whether a variable is accessible or not depends on where they appear in the source text, it doesn't depend on runtime information.
example:
function foo() {
var bar = 42;
baz();
}
function baz() {
console.log(bar); // error because bar is not in the scope of baz
}
the same problem happens in your code,
var activeGames
is not in scope.
try this variation:
exports.initialize = function(){
var activeGames = {}
var gameID = "game12345"
activeGames.gameID = new Game(gameID, "player1", "player2")
}
A good solution could be to use a class and export it:
--THIS CODE IS NOT TESTED--
class gamesManager {
var activeGames = {}
initialize() {
var gameID = "game12345"
activeGames.gameID = new Game(gameID, "player1", "player2")
}
}
exports.gamesManager = gamesManager
USE:
const activeGames = require('./game-manager');
const activeGamesInstance = new activeGames.gamesManager();
activeGamesInstance.initialize();
Need a code sample for this one. I ran this locally and it worked fine, although your code has a big issue which may be a part of your problem. It looks like you want to keep track of multiple games in activeGames. You need to use this syntax instead:
activeGames[gameID] = new Game(gameID, "player1", "player2")
Here's my working code:
index.js:
const handler = require("./request-handler");
handler.initialize('game-1234');
handler.initialize('game-5678');
request-handler.js:
var gameManager = require('./game-manager');
exports.initialize = function(gameID) {
gameManager.initialize(gameID);
}
game-manager.js:
var activeGames = {};
class Game {
constructor(id, player1, player2) {
this.id = id;
this.player1 = player1;
this.player2 = player2;
}
}
exports.initialize = function(gameID) {
activeGames[gameID] = new Game(gameID, "player1", "player2");
console.log(`game initialized! ${ Object.keys(activeGames).length } active games`);
}
Running node index results in this:
game initialized! 1 active games
game initialized! 2 active games
When you require a script file in Node.js, it is compiled as part of a function called with named parameters require, module, exports and other exposed variables as arguments1. Variables declared at file level within the required script become function level variables in the enclosing module wrapper and retained inside its closure.
Hence your "global variable" is no such thing: it's a variable defined inside a closure...
An important question then is does the module loader make variables declared in a parent module available to scripts required inside the parent. A quick test shows that the answer is general: no, modules do not have automatic access to variables declared in other modules - those variables are inside closures.
This indicates that to pass variable values to scripts that have been required, generally pass them as argument values to exported functions.
It is also possible to export any javascript value as a property of module.exports from within a required script, or add properties to an exports object after it has been returned from requiring a script. Hence it is technically feasible to pass information up and down between modules by adding properties to exports objects.
Redesigned code has multiple options to
define activeGames at the application level and pass it down as a parameter to modules needing access to it, or
export activeGames from game-manager.js by adding
exports.activeGames = activeGames
to the end of the file. This will not take care of exporting activeGames out of the parent module request-manager.js for use elsewhere, but it could be a start. Or
define activeGames as a global variable (in node) using
global.activeGames = {} // define a global object
Defining global variables is not encouraged as it can lead to collisions (and consequent program failure) between names used by applications, code libraries, future library updates and future versions of ECMAScript. Or,
Define an application namespace object for data global to the application. Require it wherever access to application data is needed:
create appdata.js as an empty file.
Optionally include a comment:
// this files exports module.exports without modification
require appdata.js wherever needed.
var appData = require('./appdata.js')
appData.gameData = {}; // for example
This relies on node.js maintaining a cache of previously required modules and does not recompile modules simply because they have been required a second time. Instead it returns the exports object of the previous require.
Happy festive season.
References
1The Node.js Way - How require() Actually Works
If I want to span my JavaScript project across multiple source files, but have each file have access to the same private variable, how would one do that?
For example, if I have the following code:
APP = (function () {
var _secret = {},
app = {};
// Application part 01:
app.part01 = (function () { /* function that uses _secret */ }());
// Application part 02:
app.part02 = (function () { /* function that uses _secret */ }());
//
return app;
}());
How do I put app.part01 and app.part02 in seperate files, but still have access to _secret?
I don't want to pass it as an argument. That's just giving the secret away, as app.part01() could be replaced by any other function.
Maybe I am asking the impossible, but your suggestions might lead me in the right way.
I want to work with multiple files, but I don't know how. Copying and pasting everything inside a single function each time before testing is not something I want to do.
How do I put app.part01 and app.part02 in seperate files, but still have access to _secret?
That's impossible indeed. Script files are executed in the global scope, and don't have any special privileges. All variables that they will be able to access are just as accessible to all other scripts.
Copying and pasting everything inside a single function each time before testing is not something I want to do
What you are looking for is an automated build script. You will be able to configure it so that it bundles your files together, and wraps them in an IEFE in whose scope they will be able to share their private state. The most simple example:
#!/bin/sh
echo "APP = (function () {
var _secret = {},
app = {};" > app.js
cat app.part01.js >> app.js
cat app.part02.js >> app.js
echo " return app;
}());" >> app.js
The only way that you can share _secret is attaching it to the application object and then application object to the window object. Here is an example.
// FIRST JS FILE...
var application; // will be attached to window
(function(app) {
app.secret = "blah!"; // will be attached to application
})(application || (application = {}));
// ANOTHER JS FILE
var application;
(function(app) {
app.method1 = function(){ console.log(app.secret); }; // will be attached to application;
})(application || (application = {}));
console.log(application.method1()); // will display 'blah!' on the console
Working example on jsbin
One way I was able to accomplish this was to create a JS file that contained the global object.
// Define a global object to contain all environment and security variables
var envGlobalObj = {
appDatabase: process.env.YCAPPDATABASEURL,
sessionDatabase: process.env.YCSESSIONDATABASEURL,
secretPhrase: process.env.YCSECRETPHRASE,
appEmailAddress: process.env.YCAPPEMAILADDRESS,
appEmailPassword: process.env.YCAPPEMAILPASSWORD
}
module.exports = envGlobalObj
Then in the files I wish to reference this object, I added a require statement.
var envGlobalObj = require("./envGlobalObj.js");
This allowed me to centralize the environment and secrect variables.
I have been working on React/Flux and am confused over the declaration of variable outside the component as in below code.
CounterComponent.js
var count;
function getCount (){
}
var CounterComponent = React.createClass({
getInitialState: function(){
return getCount();
},
render:function(){
}
})
module.exports = CounterComponent;
As in the above code, the doubt is that the variable count and function getCount seem to be global here. Is it okay to have variables and functions declared here, outside the component or need to placed inside. This looks like global pollution.
Also, if we consider a store, have seen very examples as below, here also, the variable CHANGE_EVENT seem to be global, is that okay.
CounterStore.js
var CHANGE_EVENT = 'change';
var MainStore = assign({},EventEmitter.prototype, {
AppDispatcher.register(function(payload){
var action = payload.action;
switch(action.actionType){
}
});
});
module.exports = MainStore;
I have searched for this answer, but couldnt get the right answer. From javascript perspective it looks like its polluting global, but what about in React?
It depends on the build system you use, if you use a system like browserify or webpack, then no variables would be global.
So if you do not use a bundler library, I suggest you to wrap your source code with a anonymous function, so that you wont pollute global namespace.
But I strongly suggest you to take a look with a modern approach using webpack which seems to be more popular within React and Flux community.
I understand that using closures (IIFE) is the best practice as it prevents polluting the global namespace. However, when I added the closures to my files, it prevented my 2nd file (controllers.js) from reading the first file (models.js). To give you an idea, here's what they look like:
models.js
;(function() {
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
})();
controllers.js
;(function() {
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
})();
Now that I've added closures on them, I'm getting an error that searchResult is undefined in controllers.js -- because it can't see that it exists in the models.js. How do I get it to understand that it exists in the other file?
P.S. Yes, models.js is added in the HTML file before the controllers.js file.
For them to interact, they have to have some common symbol. You have a couple of choices:
Do it yourself (using a single global variable)
Use some kind of library that does it for you (using [ideally] just a single global symbol)
Do it yourself a different way that requires no global common symbol at all
Do it yourself
The DIY version is, typically, that you have a single global, for your entire app, which your various modules add properties to.
So for instance:
models.js:
;(function(globals) {
var MyApp = globals.MyApp = globals.MyApp || {};
MyApp.searchResult = searchResult;
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
})(this);
That works because in loose mode, this at global scope is the global object (window on browsers). We pass it into the IIFE as the argument globals, and then either use or create a property on it called MyApp, and add searchResult to it as a property.
controllers.js:
;(function(globals) {
var MyApp = globals.MyApp = globals.MyApp || {};
function storeSearchResults(jsonObj) {
var instance = new MyApp.searchResult(jsonObj.data[i]);
/* Do more */
}
})(this);
We do the same thing, except that controllers.js is expecting that models.js has already been run. Although we still do the var MyApp = globals.MyApp = globals.MyApp || {}; bit, the new MyApp.searchResult would of course fail if models.js hadn't been run.
There are probably a dozen syntactic variations on this theme, this is just one of them.
Use some kind of library that does it for you
Your other option is to use a library like RequireJS (the one global symbol there is require, and it's a function) or any other asynchronous module definition lib.
Do it yourself another way
Another DIY option gets rid of globals entirely, you don't even need a single global.
To do that, your individual files don't have the IIFE (although they can use ones for things they don't want to share with other files):
;
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
controllers.js:
;
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
Then you use a minifier to combine your scripts and wrap them in one big IIFE. You might have pre.js:
(function() {
and post.js:
})();
Then the minifier creates app.js by combining pre.js + models.js + controllers.js + post.js. The end result (un-minified and formatted here for readability) is:
(function() {
;
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
;
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
})();
I called this DIY, but I wouldn't be surprised if there were tools to help with it.
Events and listeners passing and receiving data.
I don't use globals.
However I don't know how to use events in raw javascript or if data passing can be done. I use jquery/node which allow for passing data and just works beautifully.
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); }
});
})();