I see a lot of namespacing examples with functions but, is it o.k. to declare variables (global to my program) in this way?
var mynamespace = {};
mynamespace.var1 = 5;
or should all variables be placed in functions within the namespace?
You should avoid global variables...
Use some sort of module pattern instead, e.g.
(function () {
"use strict";
var myVar = 'blob';
}());
See http://yuiblog.com/blog/2007/06/12/module-pattern/
EDIT:
More Clarification:
var NS1 = NS1 || {};
NS1.myModule = function () {
"use strict";
var myVar = 'blob';
return {
myPublicMethod: function () {
return myVar;
}
};
}();
Related
I want to build a function outside a jQuery scope:
(function($) {
function MyObject() {
console.log('foo');
};
}(jQuery));
var $my_object = new MyObject();
But function MyObject is not accessible :
ReferenceError: MyObject is not defined
However, if i build my function in the scope, it's working:
(function($) {
function MyObject() {
console.log('foo');
};
var $my_object = new MyObject();
}(jQuery));
foo
How access to MyObject outside the scope ?
I would probably not recommend it but you can basically do what you want by returning the functions as part of an object and assigning the IIFE to a variable like this
var library = (function ($) {
var exports = {};
var private = 'see you cant get this';
var MyObject = exports.MyObject = function (_in) {
console.log(_in);
};
var another_func = exports.sum = function (a, b) {
console.log(a + b);
};
return exports;
}(jQuery));
library.MyObject('foobar'); // "foobar"
library.sum(3, 5); // 8
console.log(private); // Uncaught ReferenceError: private is not defined
Although I don't know why you want to do it.. Maybe this helps
// Define Class globally
// window.MyObject also works
var MyObject = (function($) {
// Passes jQuery in
return function () {
console.log('foo');
};
}(jQuery));
var $my_object = new MyObject();
In this example code:
(function(){
var obj = function() {
};
obj.prototype.hello = function(){
console.log('Hello World!');
};
})();
I see a lot of libraries doing this. Why is wrapping your code in an Immediately Invoked Function Expression (IIFE) a good practice? And how do I access this object outside, like jquery does?
Because if I do something like this:
var test = new obj();
The browser displays that obj is undefined.
To avoid polluting outer scope. You're sure no variables are going to "get out" of it.
But yes, you do need to export it. Either using window.obj = obj; from inside (to make it global) or return it :
var obj = (function() {
var obj = function() {};
obj.prototype.sayHello = function() {};
return obj;
})();
I'm using jQuery and have a function wrapped inside an immediately-invoked function expression like so:
<script type="text/javascript" src="jquery-1.8.3.min.js"></script>
<script type="text/javascript">
(function ($) {
var message = 'x called';
function x() {
alert(message);
}
})(jQuery);
x();
</script>
This will result is an error since the function "x" is not defined outside the immediately-invoked function expression. Is there any way to call the function "x" outside the immediately-invoked function expression?
Only if you expose the function in some way. For example, you can return it from the outer function:
var x = (function ($) {
var message = 'x called';
function x() {
alert(message);
}
return x;
})(jQuery);
x();
Or, similarly, you can return it on an object:
var obj = (function ($) {
var message = 'x called';
function x() {
alert(message);
}
return {"x": x};
})(jQuery);
obj.x();
Functions and variables declared inside of a function are not directly reachable from outside of that function, unless you provide some means of accessing them by returning something, or giving a reference to a variable declared outside of that function.
Make a namespace for other classes or functions you might want to do this with. You don't want to continually pollute the global namespace but there's no reason you can't make one namespace that's global and put your individual things underneath that:
(function($){
window.MyNamespace = function(){};
var message = "Something here";
$.extend(MyNamespace, {
x: function(){
alert(message);
}
});
})(jQuery)
MyNamespace.x()
You can change your code as follows:
<script type="text/javascript" src="jquery-1.8.3.min.js"></script>
<script type="text/javascript">
var x;
(function ($) {
var message = 'x called';
x = function () {
alert(message);
}
})(jQuery);
x();
</script>
jsFiddle link for this: http://jsfiddle.net/aLnbn/
Yes, ( one way is to: )just return it from the IIFE using a return statement, also you need to "catch" the return by assigning a variable to the IIFE
var foo = (function(){
return your_function;
}());
You can access your method by using your IIFE to return (or augment) a global variable.
You might do it like this:
var globalObject = (function (theObject, $) {
if (theObject.theMethod) {
return theObject;
}
var message = 'theMethod called';
theObject.theMethod = function () {
alert(message);
};
return theObject;
})(globalObject || {}, jQuery);
globalObject.theMethod();
The pattern we use is slightly better.
We have one global object (ie namespace) and we add modules to it by importing js files that contain IIFE's.
Each IIFE adds a new module to a single global object.
This makes it so our entire project has only one global object that can optionally utilize any of our modules by including a file.
I recommend checking out this article, which is a good discussion on the JavaScript module pattern:
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
Try this:
var miFunc = (function($) {
var message = 'x called';
function x() {
console.log(message);
}
this.x = x;
return this;
})(jQuery);
miFunc.x();
Test: http://jsbin.com/erucix/2/edit
One of the purposes of a closure is to limit scope. That is why x() is defined and can be called inside of your immediately-invoked function expression but is undefined outside.
To have your code work without refactoring, you can take advantage of JS grammar which differentiates between a function statement and a function operator. Both are semantically identical but the latter can be assigned to a variable which works just right for your scenario:
var x; //scoped *outside* of the closure
(function ($) {
var message = 'x called';
x = function() {
alert(message);
}
})(jQuery);
x(); //alerts 'x called'
You can access your method by using your IIFE to return a global variable.
//IIFEs - Immediately Invoked Function Expressions
var namespaceTestIIFE = (function ($) {
/** Public functions and state. */
var pub = {};
$(document).ready(function () {
//your on ready logic
});
pub.testAlert = function () {
alert('Hello TestAlert');
}
return pub;
})(jQuery);
OR
var compareForm = (function ()
{
/** Public functions and state. */
var pub = {};
pub.testAlert = function () {
alert('Hello TestAlert');
}
return pub;
}());
To access function use "namespace.functionname" for example -
namespaceTestIIFE.testAlert();
With the code below, other than specifying manually, is there a way to export only the functions and variables whose name doesn't start with an underscore?
var myapp = myapp || {};
myapp.utils = (function() {
var
CONSTANT_A = "FOO",
CONSTANT_B = "BAR";
function func() {}
function _privateFunc() {}
return {//return all variables and functions whose name does not have the "_" prefix.}
}());
Your idea requires being able to list all of the variables in the local scope. Unfortunately, JavaScript is not capable of doing that. See this related question.
There are two ways I've seen this be done:
1) Attach every variable when they're defined to an object to be exported:
var myapp = myapp || {};
myapp.utils = (function () {
var exports = {};
exports.CONSTANT_A = "FOO",
exports.CONSTANT_B = "BAR";
exports.func = function func() {}
function _privateFunc() {}
return exports;
}());
2) Or list all the exports at the end in an object literal:
var myapp = myapp || {};
myapp.utils = (function () {
var
CONSTANT_A = "FOO",
CONSTANT_B = "BAR";
function func() {}
function _privateFunc() {}
return {
CONSTANT_A: CONSTANT_A,
CONSTANT_B: CONSTANT_B,
func: func
};
}());
I've seen both (and even mixes of the two) used in practice. The second may seem more pedantic, but also allows a reader to look at a single segment of code and see the entire interface returned by that function.
I have seen the following code
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
the properties can be accessed like MODULE.moduleProperty ...right?
But how to access globals privateVariable and privateMethod() inside the module(which are globals insode the module ...right?)
You can only access them from WITHIN the module code itself as such:
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
alert('this is private!');
}
my.moduleProperty = 1;
my.moduleMethod = function () {
privateMethod();
return privateVariable;
};
return my;
}());
Doing this:
MODULE.moduleMethod();
Will call private method (and alert 'this is private!') and return the value of privateVariable.
There is no way to access privateVariable or privateMethod outside the MODULE scope.
var MODULE = (function() {
//...declare your module as above
}());
console.log(MODULE.privateVariable); //logs undefined
Hopefully that helps clear it up for you.
No, they are not global, they are local variables inside the anonymous function.
You can access them from any code within the function, but outside the function they are not directly accessible.