Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Global function in express.js?

How can I define a global function in express.js, that without require I can call it

like image 353
nfpyfzyf Avatar asked May 28 '13 09:05

nfpyfzyf


People also ask

What is global function in JavaScript?

The global object in JavaScript is an always defined object that provides variables and functions, and is available anywhere. In a web browser, the global object is the window object, while it is named global in Node. js. The global object can be accessed using the this operator in the global scope.

What is global in node JS?

Node. js Global Objects are the objects that are available in all modules. Global Objects are built-in objects that are part of the JavaScript and can be used directly in the application without importing any particular module.

How do I use global variables in node JS?

To set up a global variable, we need to create it on the global object. The global object is what gives us the scope of the entire project, rather than just the file (module) the variable was created in. In the code block below, we create a global variable called globalString and we give it a value.


1 Answers

"How" is simple enough:

    global.fnName = function(){ return "hi"; }; // Andreas Hultgren's answer 

But you don't need the global prefix; the thing about the global object is ...

    fnName = function(){ return "hi"; }; // i.e. don't do: var name = function(){ ... };     console.log(fnName());         // this prints "hi"     console.log(global.fnName());  // this also prints "hi" - it was assigned to global. 

"Without require" is a separate consideration: if you don't use require there is no guarantee your "globals" will have been declared by the time you need them. It enforces loading order of dependencies, among other things.

"Why am I" and "Is it correct to" are now hidden questions you should consider. It is accepted in javascript that Global Variables ...

... should be reserved for objects that have system-wide relevance and they should be named to avoid ambiguity and minimize the risk of naming collisions - Angus Croll, Namespacing in Javascript

i.e. global truly is Global: it is used by every author of every plugin or library you pull in to your application, not just you. Naming collisions between global variables break your application. This applies equally in node.js.

Global variables are also thought of as a code smell. In the detail sections below here you will see you can quickly get into trouble by using global variables, and they should really be treated as something that pushes you towards dependency injection and/or namespaces and modules.

Node.js and express - global vars and functions

Here's a good rule: if you upload it to a web server, or share it with other people, don't use global variables.

global is permissible in tiny "Saturday afternoon" apps in node.js with express.js, but tend to cause problems later if they get adopted into production. Therefore:

  • Modules and exports is best practice.
  • Injection should also be used to reduce coupling between javascript files. But in all cases you will usually need require to ensure they exist by the time you need them:
  • You should really consider app.locals data, and/or middleware functions, for anything that is view data related.

    // call this as a function with an input object to merge  //  the new properties with any existing ones in app.locals app.locals.({   sayHello: function() { return "hi"; } });      // now you can also use this in a template, like a jade template =sayHello() 

If you are creating global vars/functions for configuration settings purposes the below comments about namespaces still apply, and there are conventions emerging such as config.json files (still using require) for settings that are globally accessed.

Global variables - simple case

It is simple enough to declare a global variable in javascript, and for a function the process is no different. Simply omit the var keyword which would normally force a local scope on the declaration:

// app.js blah = "boo"; sayHello = function(string toWho) { return "hello " + toWho; } getVersion = function() { return "0.0.0.1"; }  // routes/main.js console.log(blah);                     // logs: "boo" console.log(global.blah);              // logs: "boo" console.log(sayHello("World"));        // logs: "hello World" console.log(global.sayHello("World")); // logs: "hello World" console.log(getVersion());             // logs: "0.0.0.1" 

But what if two separate plugins in your project use a global getVersion function - how do you get the right version number? Also, how do you ensure that getVersion exists before you need it, or exists at all?

Why do we need require?

To quote the nodejitsu docs the built in require function ...

... is the easiest way to include modules that exist in separate files. The basic functionality of require is that it reads a javascript file, executes the file, and then proceeds to return the exports object

"So", you may ask, "require just makes sure that a module from another file is included? Why bother?" It's better than that: you can make a whole folder a module, making your code easier to organise and test test test, it will recognise various extensions for file modules, not just .js, and it will look in various folders as well. Of course, it caches as well.

So, now that require has found your module, it ensures the code inside it is executed, and puts the objects your created into a "namespace":

// module file ./myModule.js exports.blah = "boo"; exports.sayHello = function(string toWho) { return "hello " + toWho; }  // routes/main.js var demoModuleReference = require('./myModule.js'); console.log(demoModuleReference.blah);           // logs: "boo" console.log(demoModuleReference.sayHello("World"));   // logs: "hello World" 

In that sample, demoModuleReference is an object that looks like:

{   blah: "foo",   sayHello: [Function] } 

Why modules and not global variables (a.k.a namespacing and "Global is the new private")?

Seems complicated now? Surely global variables are easier? requires ensures the following:

  • It ensures ordered loading of dependencies
  • It prevents variable name conflicts within global through the exports object.

This application at mankz.com (chrome or firefox only) is fascinating. Depending on how you use your js code, you are very likely to have variable name conflicts within the global scope. Name conflicts come from everywhere. In a browser, for instance, they can come from extensions. node.js is slightly different, but it is becoming more and more extended by compatible plugins as time goes on (you can load jquery in right now, for example). As the versions go on frameworks will get added, and name collisions in global will become more likely. My last run of that app in chrome showed over 1200 global namespace variables.

Namespaces - why?

This global namespace pollution was publicised early on by Douglas Crockford through Eric Miraglia in the article "A JavaScript Module Pattern". In summary:

  • All objects that need to be used between js files are really global
  • So, create a namespace object that will be unique
  • Assign the return value an anonymous function
  • Add private methods and variables inside that function
  • Do something useful with the pattern

Example:

ANDYBROWNSONICSUITE.BoomBox.SoundModule = function () {   var privateField = "can't touch this";   return {     play: function() {       console.log(privateField);     }   } } 

Why is this good?

  • Now you have only increased the global namespace members in the world by one, but this member contains as many items as you like.
  • Your application is far less likely to clash with other namespaces
  • It's a pattern, other frameworks expect you to use it to interact with them properly. In that reference, jQuery is a browser plugin, but you can use it with node and therefore your app, so the library interactivity policy statement is a perfect example.
  • It's a pattern, if we all follow it we our programs are all more likely to get along

When you read the Crockford reference along with the Croll reference (Direct Assignment section) I mentioned at the start, you see why it looks this complicated rather than just doing: sound.play = function() { ... } - ease of maintenance, refactoring the namespace etc. being just one reason.

Summary

In summary:

  • Can I create globals? Yes, it's simple, omit the var keyword before the declaration.
  • Should I create globals? You should use the module pattern, which is implicitly supported by node, and by express
  • Why am I creating globals? If it's for configuration, use a config namespace (e.g. How to store Node.js deployment settings/configuration files?)
like image 190
Andy Brown Avatar answered Oct 13 '22 22:10

Andy Brown