I have a site that uses a javascript object to hold various functions and variable data.
var Site = {
Page: {
...some functions...
},
Player: {
...more functions and variables...
}
}
The problem I'm faced with is that the header file where the script resides has grown to around 500 lines of code. I would like to break the sections like Page and Player up into separate files for easier manipulation. An obstacle of this is that some of the functions rely on output from PHP, and must remain on the base page. Is there a way that I can include separate files into the object and preserve the structure already in place?
Note that by convention, variables starting with a capital letter are reserved for constructors.
File 1:
var Site = Site || {};
Site.Page = {
...some functions...
}
File 2:
var Site = Site || {};
Site.Player = {
...more functions...
};
You can also use an extend function so that you declare an object literal, then copy the proerties and values to a base object. Or you can use an IIFE to assign functions. This is handy if you are doing feature detection and creating different functions depending on the outcome.
var Site = Site || {};
(function(global) {
function Player() {
// stuff
}
global.Site.Player = Player;
if (test) {
global.Site.someFn = function() {
// stuff 1
};
} else {
global.Site.someFn = function() {
// stuff 2
};
}
...
}(this));
or some version of the above.
Don't mix data with logic. That is, "some of the functions rely on output from PHP" is a code smell. If you have code like this:
setSomeContent("<? echo $myobj->title() ?>");
setMoreContent("<? echo $myobj->description() ?>");
Then it's time to backup a bit.
First, it's easy to break your JS up. Just make a script tag for each file like so.
<script src="main.js"></script>
<script src="page.js"></script>
<script src="player.js"></script>
Now they are loaded in order, so we can be sure main is loaded first.
// main.js
var Site = {
// functions
};
// page.js
Site.Page = {
// functions
};
// player.js
Site.Player = {
// functions
};
Now as for you data from PHP, export it to the page as JSON, stored in it's own variable:
var myObj = <? echo myObj->toJSON() ?>;
Site.Page.setContentForObject(myObj);
Which is then passed entirely to whatever function you have declared in your JS files. Separation of data and logic remains fairly clean this way.
Related
I am working on supporting a REST API that literally has thousands of functions/objects/stats/etc., and placing all those calls into one file does not strike me as very maintainable. What I want to do is have a 'base' file that has the main constructor function, a few utility and very common functions, and then files for each section of API calls.
The Problem: How do you attach functions from other files to the 'base' Object so that referencing the main object allows for access from the subsections you have added to your program??
Let me try and illustrate what I am looking to do:
1) 'base' file has the main constructor:
var IPAddr = "";
var Token = "";
exports.Main = function(opts) {
IPAddr = opts.IPAddr;
Token = opts.Token;
}
2) 'file1' has some subfunctions that I want to define:
Main.prototype.Function1 = function(callback) {
// stuff done here
callback(error, data);
}
Main.prototype.Function2 = function(callback) {
// stuff done here
callback(error,data);
}
3) Program file brings it all together:
var Main = require('main.js');
var Main?!? = require('file1.js');
Main.Function1(function(err,out) {
if(err) {
// error stuff here
}
// main stuff here
}
Is there a way to combine an Object from multiple code files?? A 120,000 line Node.JS file just doesn't seem to be the way to go to me....not to mention it takes too long to load! Thanks :)
SOLUTION: For those who may stumble upon this in the future... I took the source code for Object.assign and back ported it to my v0.12 version of Node and got it working.
I used the code from here: https://github.com/sindresorhus/object-assign/blob/master/index.js and put it in a separate file that I just require('./object-assign.js') without assigning it to a var. Then my code looks something like this:
require('./object-assign.js');
var Main = require('./Main.js');
Object.assign(Main.prototype, require('./file1.js'));
Object.assign(Main.prototype, require('./file2.js'));
And all my functions from the two files show up under the Main() Object...too cool :)
At first each file works in its own scope, so all local variables are not shared.
However, as hacky approach, you may just add Main into global scope available everywhere by writing global.Main = Main right after you define it, please make sure that you require main file first in list of requires.
The better(who said?) approach is to extend prototype of Main later, but in this case you may need to update a lot of code. Just mix-in additional functionality into base class
file1.js
module.exports = {
x: function() {/*****/}
}
index.js
var Main = require('main.js');
Object.assign(Main.prototype, require('file1.js'));
Shure.
constructor.js
module.exports = function(){
//whatever
};
prototype.js
module.exports = {
someMethod(){ return "test";}
};
main.js
const Main = require("./constructor.js");
Object.assign( Main.prototype, require("./prototype.js"));
Thus far I've worked only with relatively small projects (and mostly alone), but this time I have to collaborate with other programmers... basically because of that I must plan the structure of the website very carefully for the avoidance of spending hours debugging the code.
At this point I suppose doing that in the following manner. I divide my code in modules and store each module in a separate file inside an object (or a function) with a made-up name (lzheA, lzheB, lzheC etc.) to avoid conflicts whether an object with the same name was used in an another piece of code. When the document is loaded, I declare a variable (an object) that I use as a main namespace of the application. Properties of the object are the modules I defined before.
// file BI.lib.js
var lzheA = {
foo: function() {
},
bar: function() {
},
}
// file BI.init.js
function lzheK() {
BI.loadPage();
}
// file BI.loadPage.js
function lzheC() {
var result = document.getElementById('result');
result.innerHTML = "that worked";
}
// and so on
var lzheA,lzheB,lzheD,lzheE,lzheF,lzheG,lzheH,lzheI,lzheJ;
// doing the following when the document is loaded
var BI = {
lib: lzheA,
menu: lzheB,
loadPage: lzheC,
customScripts: lzheD,
_index: lzheE,
_briefs: lzheF,
_shop: lzheG,
_cases: lzheH,
_blog: lzheI,
_contacts: lzheJ,
init: lzheK,
}
BI.init();
https://jsfiddle.net/vwc2og57/2/
The question... is this way of structuring worth living or did I miss something because of lack of experience? Would the made-up names of the modules confuse you regardless of the fact that each one used only twice - while declaring the variable and assigning it to a property?
I consider the namespaces a good option when you want to modularize applications in Javascript. But I declare them in a different way
var myModule = myModule || {}; // This will allow to use the module in other places, declaring more than one specificComponent in other js file for example
myModule.specificComponent = (function(){
// Private things
var myVar = {};
var init = function() {
// Code
};
return {
init: init // Public Stuff
};
})();
If you want to call the init method, you would call it like this
myModule.specificComponent.init();
With this approach, i guarantee that the module will not be overwritten by another declaration in another place, and also I can declare internal components into my namespaces.
Also, the trick of just exposing what you want inside the return block, will make your component safer and you will be encapsulating your code in a pretty way.
Hope it helps
I did't found any realy working solution of this issue on Google, so...
There is a module called vm, but people say it is very heavy. I need some simple function, like PHP's include, which works like the code of an including file inserts right into the place in code you need and then executes.
I tryed to create such function
function include(path) {
eval( fs.readFileSync(path) + "" );
}
but it is not as simple... it is better if I'll show you why in example.
Let's say I need to include file.js file with content
var a = 1;
The relative file look like this
include("file.js");
console.log(a); // undefined
As you already realized a is undefined because it is not inherits from a function.
Seems the only way to do that is to type this long creepy code
eval( fs.readFileSync("file.js") + "" );
console.log(a); // 1
every time with no wrapper function in order to get all the functionality from a file as it is.
Using require with module.exports for each file is also a bad idea...
Any other solutions?
Using require with module.exports for each file is also a bad idea...
No, require is the way you do this in NodeJS:
var stuff = require("stuff");
// Or
var stuff = require("./stuff"); // If it's within the same directory, part of a package
Break your big vm into small, maintainable pieces, and if they need to be gathered together into one big thing rather than being used directly, have a vm.js that does that.
So for example
stuff.js:
exports.nifty = nifty;
function nifty() {
console.log("I do nifty stuff");
}
morestuff.js:
// This is to address your variables question
exports.unavoidable = "I'm something that absolutely has to be exposed outside the module.";
exports.spiffy = spiffy;
function spiffy() {
console.log("I do spiffy stuff");
}
vm.js:
var stuff = require("./stuff"),
morestuff = require("./morestuff");
exports.cool = cool;
function cool() {
console.log("I do cool stuff, using the nifty function and the spiffy function");
stuff.nifty();
morestuff.spiffy();
console.log("I also use this from morestuff: " + morestuff.unavoidable);
}
app.js (the app using vm):
var vm = require("./vm");
vm.cool();
Output:
I do cool stuff, using the nifty function and the spiffy function
I do nifty stuff
I do spiffy stuff
I also use this from morestuff: I'm something that absolutely has to be exposed outside the module.
What you are trying to do breaks modularity and goes against Node.js best practices.
Lets say you have this module (sync-read.js):
var fs = require('fs');
module.exports = {
a: fs.readFileSync('./a.json'),
b: fs.readFileSync('./b.json'),
c: fs.readFileSync('./c.json')
}
When you call the module the first time ...
var data = require('./sync-read');
... it will be cached and you wont read those files from disk again. With your approach you'll be reading from disk on every include call. No bueno.
You don't need to append each of your vars to module.exports (as in comment above):
var constants = {
lebowski: 'Jeff Bridges',
neo: 'Keanu Reeves',
bourne: 'Matt Damon'
};
function theDude() { return constants.lebowski; };
function theOne() { return constants.neo; };
function theOnly() { return constants.bourne; };
module.exports = {
names: constants,
theDude : theDude,
theOne : theOne
// bourne is not exposed
}
Then:
var characters = require('./characters');
console.log(characters.names);
characters.theDude();
characters.theOne();
I created a javascript application with all of the code in one file. The application has grown quite a bit and I think it's time to split it up into multiple files, but I'm having a hard time figuring out how to do this. I think the problem lies with how I have decided to build the app, which uses the following template:
var myApp = function(){
//there are several global variables that all of the modules use;
var global1, global2, module1, module2;
global1 = {
prop1:1
};
//There are also several functions that are shared between modules
function globalFunction(){
}
var ModuleOne = function(){
function doSomething(){
//using the global function
globalFunction();
}
return{
doSomething:doSomething
}
};
var ModuleTwo = function(){
function doSomething(){
//module 2 also needs the global function
globalFunction();
//Use the functionality in module 1
//I can refactor this part to be loosely coupled/event driven
module1.doSomething();
}
};
module1 = new ModuleOne();
module2 = new ModuleTwo();
};
Even if all of the modules were loosely coupled and event driven, I still don't know how I would go about splitting this into multiple files given each module's reliance on the shared functions/variables. Does anyone have suggestions?
Take a look at the design pattern in this article: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth - you can split your module definition across multiple files in a way that lets common properties be shared but also lets you create variables or methods that are private just to a particular file.
The basic idea is that the individual JS files add to the same module with code like this:
var MODULE = (function (my) {
var privateToThisFile = "something";
// add capabilities...
my.publicProperty = "something";
return my;
}(MODULE || {}));
Where in each JS file if MODULE is already defined (from another JS file) you add to it otherwise you create it. You can set it up so that it (mostly) doesn't matter what order the various files are included in.
The article details several variations, and of course you'll probably come up with your own tweaks...
not to add to the confusion, but coming from a C++ background, I've tried to construct something that resembles something like a c++ namespace in the manner described below. it works, but I'd like to know if this is an acceptable pattern for the OP ?
--------------------------------file main.js:----------------
var namespacename = function(){}
namespacename.mainvalue = 5;
namespacename.maintest = function() {
var cm = new namespacename.game();
cm.callme();
}
--------------------------------file game.js:----------------
namespacename.gamevalue = 15;
namespacename.game = function(){
this.callme = function(){
console.log( "callme" );
}
}
namespacename.gametest = function() {
console.log( "gametest:gamevalue:" + this.gamevalue );
console.log( "gametest:mainvalue:" + this.mainvalue );
}
--------------------------------file index.html:--------------
<html>
<head>
<title>testbed</title>
</head>
<body onload="init();">
</body>
<script type="text/javascript" src="main.js"></script>
<script type="text/javascript" src="game.js"></script>
<script type="text/javascript">
init = function()
{
namespacename.maintest();
namespacename.gametest();
console.log( "html main:" + namespacename.mainvalue );
console.log( "html game:" + namespacename.gamevalue );
}
</script>
</html>
Give require.js a shot. http://requirejs.org/
Example:
require(["dir/file"], function() {
// Called when file.js loads
});
You can put the shared functions and shared modules on the myApp object so they don't pollute the global namespace, but can be accessed anywhere without being inside the same closure.
myApp.moduleOne = function() {...}
myApp.moduleTwo = function() {...}
myApp.globalFunction = function() {...}
Then, you can define them in any file and use them in any file.
You could also just break the file up into multiple files, but require them to be included in a specific order that preserves your closure. If you're breaking up the files for practical editing reasons, but recombining and minimizing them for actual deployment, then this wouldn't cost you anything in terms of how you write code or how it's deployed, but would give you lots of smaller files for editing convenience.
My favorite solution to this is use server side scripting to include the other files inside my "main" file. For example, using Perl's Template Toolkit:
var myApp = function(){
[% INCLUDE lib/module1.js %]
[% INCLUDE lib/module2.js %]
[% INCLUDE lib/module3.js %]
}
Or PHP:
var myApp = function(){
<?php
include 'lib/module1.js';
include 'lib/module2.js';
?>
}
I failed to create a mini-library with some useful functions that I have found over the Internet, and I want to use them easily by just including a file to the HTML (like jQuery).
The problem is that some vars and functions share the same name and they are causing problems.
Is there a better solution to this instead of giving crazy names to the vars/funcs like "bbbb123" so the odds that someone is working with a "bbbb123" var is really low?
I would put all of your functions and variables into a single object for your library.
var MyLibrary = {
myFunc: function() {
//do stuff
},
myVar: "Foo"
}
There are a few different ways of defining 'classes' in JavaScript. Here is a nice page with 3 of them.
You should take one variable name in the global namespace that there are low odds of being used, and put everything else underneath it (in its own namespace).
For example, if I wanted to call my library AzureLib:
AzureLib = {
SortSomething: function(arr) {
// do some sorting
},
DoSomethingCool: function(item) {
// do something cool
}
};
// usage (in another JavaScript file or in an HTML <script> tag):
AzureLib.SortSomething(myArray);
Yes, you can create an object as a namespace. There are several ways to do this, syntax-wise, but the end result is approximately the same. Your object name should be the thing that no one else will have used.
var MyLibrary = {
myFunc: function() { /* stuff */ }
};
Just remember, it's object literal syntax, so you use label : value to put things inside it, and not var label = value;.
If you need to declare things first, use a wrapping function to enclose the environment and protect you from the global scope:
var MyLibrary = (function() {
var foo = 'bar';
return {
myFunc: function() { /* stuff */ }
};
})(); // execute this function right away to return your library object
You could put all of your library's functions inside of a single object. That way, as long as that object's name doesn't conflict, you will be good. Something like:
var yourLib = {};
yourLib.usefulFunction1 = function(){
..
};
yourLib.usefulFunction2 = function(){
..
};