I've wrapped all my functions around an immediately-invoked function expression as shown:
(function(){
"use strict";
function toggleComment(parentCommentID) {
$("form#" + parentCommentID).toggle();
}
function scrollBottom() {
window.scrollTo(0, document.body.scrollHeight);
}
})();
However, upon calling one of these functions through a link:
Reply
The Chrome console outputs Uncaught ReferenceError: toggleComment is not defined. Am I mistaken in thinking that an immediately-invoked function expression, as its name suggests, should be invoked immediately and therefore toggleComment should be called? Should I call the function differently?
The function toggleComment is not visible. It's enclosed in the ready function you're using; if you want to be able to call it like that (which is not recommended, in most cases), you have to hoist it outside of that function and make it globally accessible.
And this has nothing to do with strict. If you remove the strict line, this problem will still be the same.
The functions are no longer declared in the global scope. Try
window.toggleComment = function(parentCommentID) {
$("form#" + parentCommentID).toggle();
};
You have declared the functions inside a closure. They're outside of the scope of the HTML tag.
You could set an id to your <a> tag as well as publish your function to the global scope, so you can do this:
(function(){
"use strict";
var toggleComment = function(parentCommentID) {
$("form#" + parentCommentID).toggle();
}
function scrollBottom() {
window.scrollTo(0, document.body.scrollHeight);
}
document.getElementById("yourATagId").onclick(function() {
toggleComment(159);
});
window.toggleComment = toggleComment;
})();
Maybe you could benefit from this simple singleton pattern:
(function() {
var controller = {};
controller = new function() {
this.sampleProperty = "my property";
}
controller.yourFunction = function() {
var localVariable;
console.log("I can access " + this.property);
};
window.controller = controller;
})();
This way, controller will be known to your global scope.
Related
I'm trying to call this variable outside the function but I get undefined as a result. I understand without var the variable could be called in global scope but i get undefined. I also tried setting the var outside the function and calling it but no success also. Here's my simplified code thank you :)
function function1() {
$.getJSON('random.json')
.success(successfunction)
.error(failfunction);
function successfunction(data) {
testvar = (data.name);
}
function failfunction(error) {
console.log(error);
}
};
console.log(testvar);
used
$( document ).ajaxStop(function() {}
to load the var after ajax load.
It's just visible in the method scope, you have to declare it outside the function (which means global in this case) or return it in the function call:
var testvar2 = "var 2";
function function1() {
// parse json
return successfunction("data");
function successfunction(data) {
testvar2 = "var glob";
var testvar = "var ret";
return testvar;
}
function failfunction(error) {
console.log(error);
}
};
console.log(testvar2);
console.log(function1());
console.log(testvar2);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Declaring global variables should be avoided and is not good practice, try to define the scope of a variable as small as possible. If any other js module also declares a varibale named testvar2 funny things might happen.
if you want global scope attach your variable to global object like window
function successfunction(data){
window.testvar = "var";
}
By that you will be sure that it becomes global .
However, you should note that successfunction is a callback that will be running later on : it is running after timeout & only if the ajax call succeeded .
try adding a return testvar in suc cessfunction instead of calling testvar
call the successfunction
function successfunction(data){
testvar = "var";
return testvar;
}
I have my code in mycode.js
(function($) {
function2() {
console.log("main func: " + g_var);
}
}(jQuery));
I use the code in main HTML
<script type="text/javascript" src="mycode.js"></script>
(function ($) {
var g_var = 10;
console.log("func2: " + g_var);
function2();
}
but g_var not visible in function2
Uncaught ReferenceError: function2 is not defined
Uncaught ReferenceError: g_var is not defined
How can I correct it?
You shoud read about declaration scopes. You would find this behavior of varibale and function scopes in nearly every programming language.
Answer:
To solve your problem, you have to create function2 outside of the IIFE, otherwise it is only available on the inside. And then use a parameter to pass the value.
function function2(g_var) {
console.log("main func: " + g_var);
}
(function() {
var g_var = 10;
function2(g_var);
})();
Addition:
If you create the variable g_var in the same scope as the function, you could access it on the inside of function2 too. But I would not do that in the most cases.
There are some cases were this makes sense, like when working with callbacks, created on the inside of other functions. But on the most cases you should go with the first example and use parameters!
(function() {
var g_var = 10;
function function2() {
console.log("main func: " + g_var);
}
function2();
})();
But really, that is not a good idea at all in the most cases! It makes sense when you think of something like this:
$(".foo").each(function() {
var that = this;
$(".bar").click(function() {
// access 'that'
});
});
you are using a closure, but failing to return a public method. See this example and check the docs MDN: JS Closures
var foo = (function($) {
function f2(g_var) { // private
console.log("main func: " + g_var);
}
return {
function2: function(g_var) {
f2(g_var);
}
};
})(jQuery);
and you can invoke it like this:
foo.function2(g_var);
eisbehr is right first you need to define your func out of the IIFE then yoi should define your variable outside everything. Then you can use the variable in that js file every function and snippet.
You should write your code like this.
var g_var;
function function1(){
g_var=4;
console.log("main func: " + g_var);
}
function function2(){
g_var=10;
console.log("func2: " + g_var);
}
I am wondering what the difference is between this:
(function(msg) {
alert(msg);
}('Hi'));
and this:
alert('Hi');
Because when you use an anonymous function, you can't run it twice, right? You can't do this:
(function(msg) {
alert(msg);
}('Hi')('Goodbye'));
So what's the point of an anonymous function?
This:
(function(msg) {
alert(msg);
}('Hi'));
gets the same output as this:
alert('Hi');
Could someone tell me what the difference is?
The main difference is that it has its own scope. Example:
(function(msg) {
var x = msg; // local variable in the scope
alert(x);
}('Hi'));
// the variable x doesn't exist out here
That is useful when you for example create a function in the scope, and expose it outside. The function still has access to the scope even when executed outside it. That way the function can keep a state, without exposing the state globally:
var f = (function(msg) {
var cnt = 1;
return function(){
alert(msg + ' ' + cnt);
cnt++;
};
}('Hi'));
f(); // shows "Hi 1"
f(); // shows "Hi 2"
Your example shows an Anonymous Function that is self-executing. The self-executing Function closes off scope, so you can do things like this:
var count = (function(){
var c = 0;
return function(){
return c++;
}
})();
console.log(count()); console.log(count());
In your first example nothing different will occur. An Anonymous function, just has no name, so this:
document.getElementById('whatever').addEventListener('click', function(){alert('wow')});
and
function wow(){
alert('wow');
}
document.getElementById('whatever').addEventListener('click', wow);
do the same thing.
the anonymous function is when you declare a function without name i.e
function(){
...
}
Your example is an inmediate function, here you can hide properties and functionality (using closures, this is complex I recommend you The secrets of JS Ninja, but is a intermediate lvl book.), so you can use this when use the module pattern:
(function(msg) {
alert(msg);
}('Hi'));
BTW this is a good resource about patterns in JS: http://addyosmani.com/resources/essentialjsdesignpatterns/book/
Let's say we have this script.
var apple = {
type: "macintosh",
color: "red",
getInfo: function () {
return this.color + ' ' + this.type + ' apple';
}
///more functions here....
}
How can I let all these functions run in strict mode? I can put "use strict" at the top of the file but JSlint does not approve this. An alternative is to put "use strict" in every function, but is there a better option?
Wrap everything inside an IIFE and JSLint should approve.
(function () {
"use strict";
//all your code here
}());
Note that variables/functions previously declared in the global scope would no longer be accessible in the global scope when moved to inside this immediately-invoked function expression.
You will have to explicitly set these as properties of the global object, e.g. the window object for browser environment:
(function () {
"use strict";
window.someGlobalVariable = "something";
}());
#zzzzBov's solution also works nicely on both browser and back-end environments.
Wrap everything in an IIFE, alias the global reference, and explicitly set global variables on the global object:
(function (root) { //could be window (browser), could be global (node)
"use strict";
...code...
root.apple = apple; //explicitly make apple a global variable
}(this));
If you are using namespaces for your object literals, I like this approach best:
(function (myApp) {
'use strict';
myApp.myObj = {
init: function(){}
}
}(window.myApp = window.myApp || {}));
myApp.myObj.init();
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();