Let's say I have these files: a.js b.js c.js which each one is defined like this:
(function(){
function afunction() {
}
function yetanotherfunction() {
}
... ...
})();
I also have a file named common.js, which contains functions that can be shared by multiples:
function commonFunction() {
}
function yetAnotherCommonFunction() {
}
I would like to put commonFunction, yetAnotherCommonFunction inside scope. ie:
(function() {
... //commonFunction, yetAnotherCommonFunction goes here
})();
however if I do so, I won't be able to call the common functions from a/b/c.js scope. Is there a better way to handle this?
Namespaces:
var Common = (function () {
var Common = {};
Common.commonFunction = function() {
}
return Common;
}())
Common.commonFunction() // do something from anywhere
You can create a namespace for each script. A simple script to do this would be to have a namespace script like this :
var ns = function (namespace, callback) {
var nssplit = namespace.split('.'), x, curObj = window, curPos = null, lasObj;
for (x = 0 ; x < nssplit.length ; x++) {
curPos = nssplit[x];
if (curObj[curPos] === undefined) {
curObj[curPos] = {};
}
lasObj = curObj;
curObj = curObj[curPos];
}
lasObj[curPos] = callback;
};
ns('local.test', function() {
document.getElementById('test').innerHTML = "test";
});
local.test();
You can see it in action here http://jsfiddle.net/Nemesis02/Qtq8Q/
Related
I've checked a lot of codes and I've saw a lot of people doing
module.exports = (function(){
return {
functionA: function() {
}
},
functionB: function() {
}
};
})();
so, why not just do
module.exports = {
functionA: function() {
},
functionB: function() {
}
};
Thanks!
Your first example allows you to hide variables within its own closure scope that can be shared with your return object's methods. The For example, if you did the following...
var foo = (function(){
var x = 2;
return {
addToTwo: function(y){
return x + y;
},
subtractFromTwo: function(y){
return x - y;
}
}
};
The above example shows that the x variable is protected and shared between addToTwo and subtractFromTwo. The second example only will allow you to make x as part of the object without the same protection.
module.exports = {
x: 3,
functionA: function() {
return this.x;
},
};
x can be altered in this example.
Those are exactly the same. It's a stylistic decision.
According to the Node.js docs:
Variables local to the module will be private, as though the module was wrapped in a function.
You could also do it this way:
module.exports.functionA = function() {
};
module.exports.functionB = function() {
};
Or:
// either method for creating a function works
function functionA () {}
var functionB = function () {}
module.exports = {
functionA : functionA,
functionB : functionB
};
One of the greatest advantages of directly invoked functions is the use of closures which cannot be obtianed in a separate manner, so literally they are not the same.
Let's say I have the namespace,
var Namespace = {
A : function() {
alert('Hello!');
},
B : function() {
// Call A() from here, do other stuff
}
}
In this namespace, I intend for A to be a helper function to B. That is to say, A() will never be called outside the namespace. It will only be called by the functions within the namespace.
What's the best way to address the issue of a local/helper function within a namespace? The way I see it there are two possibilities:
// Method #1
var Namespace = {
A: function() {
alert('Method #1');
},
B : function() {
Namespace.A();
}
}
Namespace.B();
// Method #2
function Namespace2() {
var A = function() {
alert('Method #2');
};
this.B = function() {
A();
}
}
var ns2 = new Namespace2();
ns2.B();
In the first method, it is ugly and awkard to type Namespace.A() (repeatedly) in every function within the namespace. This leads me to prefer Method #2. But I was curious what was the best practice here.
I recommend placing the "namespace" inside a function scope. Everything not explicitly public will be naturally private:
var Namespace = (function() {
var self = {};
// Private
var A = function() {
...
};
// Public
self.B = function() {
A();
}
return self;
}());
Namespace.B(); // Works
Namespace.A(); // Doesn't work
You can call it using this statement
this.A();
Well you can event use a third option where the Namespace is created in it's own scope:
var Namespace = (function(){
var A = function() {
alert('scoped method');
};
function Namespace() {
var A1 = function() {
alert('Namespace "private" method');
};
Namespace.prototype.B1 = function(){
A(); //will run
A1(); //will run with no errors
};
};
Namespace.prototype.B = function(){
A(); //will run
A1(); //ERROR!
};
return Namespace;
})();
If you only intend to use A inside B, why not define it inside B?
var Namespace = {
B: function() {
var A = function() {
...
}
A();
}
};
Namespace.B();
var Namespace = {
A : function() {
alert('Hello!');
},
B : function() {
Namespace.A();
},
}
note the Semi-colon at the end
I have the following code
var PROMO = PROMO || {};
PROMO.Base = (function () {
var _self = this;
var Init = function () {
WireEvents();
};
var WireEvents = function () {
//wire up events
};
} ());
In the same file I have the code to call the above function
I am trying to get to an end point where I can use the following code
$(document).ready(function () {
PROMO.Base.Init();
});
this gives the error
Cannot call method 'Init' of undefined
Now I know there are many ways to write javascript, but in this case I want to be able to call my functions, or least the Init method in the way shown above.
var PROMO = PROMO || {};
PROMO.Base = (function () {
var _self = this;
var Init = function () {
WireEvents();
};
var WireEvents = function () {
//wire up events
};
var reveal = {
Init: Init
};
return reveal;
} ());
You need to return the public facing functions. See updated code.
Working fiddle with both patterns, using IIFE and direct attribution.
Using var makes the definition private and your function is returning nothing. Use this:
PROMO.Base = {
Init: function() {
},
WireEvents: function() {
};
};
You are wrapping the definition with an IIFE(Immediately Executed Function Expression). So your PROMO.Base object will be assigned the value of that (function(){//blabla})(); returns. But your function doesn't have a return statement. By default it will return undefined.
Which is way your PROMO.Base will be undefined and you get this:
Cannot call method 'Init' of undefined
If you really want that IIFE:
var PROMO = PROMO || {};
// NEVER use _self = this inside static functions, it's very dangerous.
// Can also be very misleading, since the this object doesn't point to the same reference.
// It can be easily changed with Function.prototype.call and Function.prototype.apply
PROMO.Base = (function () {
_PROMO = {
Init : function () {
document.body.innerHTML += "itworks";
},
WireEvents : function () {
//wire up events
}
}
return _PROMO;
} ());
PROMO.Base.Init();
Update
The better and easier pattern is to simply assign the functions to PROMO.Base. Dully note you should not capitalize static functions, but only constructors. So if something is not meant to be instantiated, don't call it Init, it should be init. That is the convention.
var PROMO = {};
PROMO.Base = {};
PROMO.Base.init = function() {
console.log("this works");
};
PROMO.Base.wireEvents = function() {
console.log("this is a static function too");
};
You can attach it to the window object like ...
window.PROMO = (function($, _){
// this will access PROMO.Base
PROMO.Base = {
// inner functions here
Init:{}
};
})(jQuery, _);
Then load it as you do.
Or if you depend from jQuery
(function($){
var PROMO = {
// inner functions
Init: function(){},
WireEvents: function(){}
};
$.PROMO = PROMO;
})(jQuery);
On DOM ready
jQuery(function ($) {
var promo = $.PROMO || undefined;
promo.Base.Init();
});
I have a namespace in the following format allowing for public and private members:
function A() {
return('a');
}
namespace1 = (function () {
// private
namespace2 = (function() {
// private
prC = function () {
return(namespace1.puB() + 'c');
};
puC = function () {
return(prC());
};
// public
return({
puC: puC
});
})();
prB = function () {
return(A() + 'b');
};
puB = function () {
return(prB());
};
// public
return({
puB: puB,
namespace2: namespace2
});
})();
document.write('A() = '); try { document.write(A()); } catch (ex) { document.write('inaccessible'); }
document.write('<BR />');
document.write('namespace1.prB() = '); try { document.write(namespace1.prB()); } catch (ex) { document.write('inaccessible'); }
document.write('<BR />');
document.write('namespace1.puB() = '); try { document.write(namespace1.puB()); } catch (ex) { document.write('inaccessible'); }
document.write('<BR />');
document.write('namespace1.namespace2.prC() = '); try { document.write(namespace1.namespace2.prC()); } catch (ex) { document.write('inaccessible'); }
document.write('<BR />');
document.write('namespace1.namespace2.puC() = '); try { document.write(namespace1.namespace2.puC()); } catch (ex) { document.write('inaccessible'); }
Output:
A() = a
namespace1.prB() = inaccessible
namespace1.puB() = ab
namespace1.namespace2.prC() = inaccessible
namespace1.namespace2.puC() = abc
How might I go about appending both public and private members to such a namespace (IE: from different files)?
Here's a JSFiddle.
"How might I go about appending both public and private members to such a namespace..."
Well, your functions are exposed because you didn't properly declare your variables with var.
But once you fix that, you can add more exposed properties (since all properties are exposed) from any code that can reference your namespace objects.
Adding more properties that reference local (the proper term for private) functions, you'd need a new function and variable scope.
Just invoke a function that references the namespace objects, create some functions inside that function, and add properties that reference those local functions.
// Other file
(function() {
var newLocalFunc = function() {
// local function
}
var anotherLocalFunc = function() {
// local function
}
namespace1.exposedFunc = function() {
return newLocalFunc()
}
namespace1.namespace2.anotherExposedFunc = function() {
return anotherLocalFunc()
}
})();
And again... don't forget to put var before your variables in the original code.
Any variable declared without the var keyword will be in the global scope. So your puB() function is NOT inaccessible or private, it is just not a member of the object returned by the namespace1 function. Try window.prB() for example, you'll see that method exists within the global scope of the window object.
<head>
<script type="text/javascript">
obj1 = {}; //in global scope
var obj2 = {}; //in global scope. Although used the var keyword, this line itself is in the global scope; so the variable.
function someFunc() {
obj3 = {}; //in global scope
var obj4 = {}; //'so-called' private (inaccessible from global scope)
}
</script>
</head>
For combining two different JS files under the same 'namespace' (or let's say object):
File-1.js
var namespace1 = (function() {
// some code...
var namespace2 = (function() {
// some code...
return {
obj2: 'value2'
};
})();
return {
obj1: 'value1'
};
})();
File-2.js
namespace1.namespace3 = (function() {
// some code...
var ns4 = (function() {
// some code...
return {
obj4: 'value4'
};
})();
return {
obj3: 'value3',
namespace4: ns4
};
})();
What is what:
namespace1 is declared inside the global scope; so it is accessible
from anywhere and it is our main object.
namespace2 is inaccessible (private).
namespace3 is inaccessible in the global scope but accessible as a
member of namespace1; e.g.: namespace1.namespace3.
namespace4 is accessible as a member of namespace1. e.g.:
namespace1.namespace4.
So; the members of our main object namespace1 is:
namespace1 = {
obj1: String,
namespace3: {
obj3: String,
namespace4: {
obj4: String
}
}
};
You are a long way from Kansas, here.
You can't "declare" things as public or private.
As long as you define things inside of function, and then choose to return specific things, or append them to an object/array which you passed in as an argument, then you will have "public" (outer) access to those things, after the function returns.
In order to have "private" access, you return a function which references something on the inside.
var Wallet = function (amount, overdraft_limit) {
var balance = 0,
overdraft = overdraft_limit || 0,
deposit_funds = function (funds) { balance += funds; return true; },
withdraw_funds = function (request) {
var funds = 0;
balance -= request;
funds = request;
return funds;
},
validate_request = function (pin) { /* ... */ },
sufficient_funds = function (val) { return val <= (balance + overdraft); },
add = function (pin, deposit) {
if (!validate_request(pin) || deposit <= 0) { return false; }
var result = deposit_funds(deposit);
return result;
},
deduct = function (pin, withdrawl) {
if (!validate_request(pin) || withdrawl <= 0) { return false; }
if (!sufficient_funds(withdrawl)) { return false; }
var funds = withdraw_funds(withdrawl);
return funds;
},
check = function () { return balance; },
public_interface = { deduct : deduct, add : add, check : check };
return public_interface;
};
var myWallet = Wallet(30, 20);
var cash = myWallet.deduct(40);
cash; // 40
myWallet.check(); // -10
myWallet.balance = 40000000000;
cash = myWallet.deduct(4000);
cash; // === false
By building functions inside of my "constructor", which have access to balance, the variable that I return that "public" object to can call methods to interact with the "private" data, but can't access it or modify it through any method but to use those "public" functions.
Nesting this stuff 8-layers deep, using IIFEs uses the exact-same concept of closure which I just demonstrated.
Explicitly decide what you're going to return and what you are not.
The functions which you send into the world are public. The functions/etc inside of the function, which weren't returned or attached to an object are private.
They have been closed over, by the "constructor" function which returned, and now they are 100% inaccessible, except by using the functions which were built inside of the constructor, which reference the private vars, and were returned as public methods.
We have some js code splitted in many files. We have a core file that defines code used by many other js files.
Currently we have something like this:
core.js:
window.mycore = function() {
var myfunction1 = function() {
};
var myfunction2 = function() {
};
var myfunction3 = function() {
//..
var a = myfunction1(b);
//..
};
//...
// many "myfunction"
//...
var myfunctionN = function() {
};
var publish = function() {
for(var i = 0; i < arguments.length; i++) {
try {
window.mycore[arguments[i]] = eval('(' + arguments[i] + ')');
}
catch(e) {
Log.err(600, arguments[i], e);
}
}
};
publish("myfunction1", "myfunction7", "myfunction8",/*...*/"myfunctionM")
}
app.js:
// ...
// ...
var result = window.core.myfunction1("myparam");
// ...
// ...
Note that none core methods are declared as members of the window.core object. Instead they are attached to the core object with the publish function.
This has some pros:
The core code can reference any core function without the need of writing "window.core."
We avoid writing "var myfunction = window.mycore.myfunction = function() ..." in every public function declaration
The exposed methods can be seen centraliced.
But, the use of eval in the publish function is bringing us problems when using code analysis tools since they don't tend to understand eval declarations.
So, here is my question.
Which is the better way to improve this code, so we can keep the advantages mentioned but eradicating the eval declaration.
I am aware of the solution of sending to the publish function some name/value pairs like publish({'myfunction1': myfunction1}, ... ), but I also want to avoid function name repetitions.
Consider that I am not looking for radical changes since there is a lot of code written already.
Thanks!
I'm not sure I understand completely your reasons for using the "publish" method, but is there any reason your not just returning an object with the correct functions from your constructor?
ie:
window.mycore = (function() {
var myFunc1 = function(a) {
alert(a);
};
var myFunc2 = function(b) {
// call to other function in the same scope
myFunc1(b);
}
...
// at the end just expose the public members you want
return {
myFunc1: myFunc1,
myFunc2: myFunc2
};
})();
or
window.mycore = (function() {
return {
myFunc1: function(a) {
alert(a);
},
myFunc2: function(b) {
this.myFunc1(b);
}
};
})();
or, yet another way to end up with the same object :) ... as always there are different ways to get there
(function(){
var o = {};
o.func1 = function(a) {
alert(a);
}
o.func2 = function(b) {
this.func1(b);
}
window.mycore = o;
})();
So, at a fundamental level, I think it would have benefitted you to have written those name spaces as objects. But thats a whole different subject entirely. (and it disqualifies based on the fact that you dont want to do a lot of refactoring).
With that said, my first idea was that you could probably sidestep the need for eval by using the .call() or .apply() method. What they allow you to do is to chain a function call out of your function name. but that doesn't apply to a "string" which is what you're giving your publish function.
so after googling, this is how you execute a function from a string:
var fn = window[settings.functionName];
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
https://stackoverflow.com/a/912642/680578
Personally I prefer the #Jaime approach, but maybe you may do something like
window.mycore = function() {
function myfunction1() {
};
function myfunction2() {
};
function myfunction3() {
//..
var a = myfunction1(b);
//..
};
//...
// many "myfunction"
//...
function myfunctionN() {
};
var publish = function() {
for(var i = 0; i < arguments.length; i++) {
try {
window.mycore[arguments[i].name] = arguments[i];
}
catch(e) {
Log.err(600, arguments[i].name, e);
}
}
};
publish(myfunction1, myfunction7, myfunction8,/*...*/myfunctionM);
}