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);
}
Related
This question already has answers here:
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 4 years ago.
I was following a tutorial where they used a translator to translate a class in Typescript into javascript. The translated javascript is a bit confusing and I was wondering if someone can explain to me what the code is doing.
Original Typescript:
class Greeter {
greeting: string;
constructor(message: string){
this.greeting;
}
greet(){
return "Hello, " + this.greeting;
}
}
and the translated Javascript:
var Greeter = (function(){
function Greeter(message){
this.greeting = message;
}
Greeter.prototype.greet = function(){
return "Hello, " + this.greeting;
};
return Greeter;
}());
I am confused about this part (function() { ... }());
what is the first () doing? why is the function(){} necessary? and what is the following () doing?
The syntax is pretty confusing and I hope someone can explain this.
I am confused about this part (function() { ... }());
IIFE this function will executed as soon as it is interpreted by the browser. You don't have to explicitly call this function.
what is the first () doing? why is the function(){} necessary?
All functions in javascript are Object by nature. To create a instance of it you have to call like new Greeter() so the context this is set properly. If executed like Greeter() now the context this is from where it's executed. In most cases it's the window object.
Reference articles
https://www.phpied.com/3-ways-to-define-a-javascript-class/
https://medium.com/tech-tajawal/javascript-classes-under-the-hood-6b26d2667677
That's called IIFE.
General syntax:
(function () {
statements
})();
But sometimes, you can write:
(function () {
statements
}());
I usually use the second's because it's following these steps:
Defining a function: function () { /* statements */ }
Calling the function: function () { /* statements */ }()
And wrapping the function: (function () { /* statements */ }())
Or use it with as an asynchronous thread:
(async function () {
// await some task...
})();
(async () => {
// await some task...
})();
You can also use it to define some local variable(s), like this:
let Person = (function () {
let _name = null;
class Person {
constructor(name) {
_name = name;
}
getName() {
return _name;
}
}
return Person;
}());
let person = new Person('Harry');
console.log(person.getName());
console.log(window._name);
For modules, you want to create some plugin(s) and make it to be global, you can write:
(function (global, factory) {
// we can use "global" as "window" object here...
// factory is a function, when we run it, it return "Person" class
// try to make it global:
global.Person = factory(); // same to: window.Person = factory();
}(window, function () {
class Person {};
return Person;
}));
This construct:
const foo = (function() { })();
Creates an anonymous function, and immediately calls it. The result gets places into foo.
It's possible to split this up in more lines with an extra variable:
const temp = function() { };
const foo = temp();
The reason typescript does this, is because placing code in function creates its own new scope. This makes it possible to do certain things without changing the global namespace.
(function() { ... }()); is a form of IIFE (Immediately Invoked Function Expression)
For example:
var Greeter = (function(){
return 1;
}());
The result is equal to
function fn() {
return 1;
}
var Greeter = fn();
The value of Greeter is 1 after executing the above codes. But the former one uses anonymous function and the latter one declared a variable fn to store the function.
Greeter.prototype.greet = function(){
return "Hello, " + this.greeting;
};
This code snippet is to define a function on the prototype of object Greeter so that this function can be inherited when you create new Greeter(). You may refer to Object.prototype
I'm trying to use the Revealing Module Pattern to scope the JavaScript on my page so that I don't pollute the global namespace.
<script type="text/javascript">
var myModule = (function(){
function windowLoad() {
// window onLoad things
return;
}
function otherFunc(){
// otherFunc things
}
window.onload = windowLoad;
return { otherFunc: otherFunc };
})();
myModule.otherFunc(); // myModule is undefined here
</script>
For some reason, as shown in the comment above, myModule is undefined when I go to use it. Why?
myModule is not undefined. It is the object you returned from within your immediately invoked function; What is undefined is the result of calling myModule.otherFunc because that function doesn't return anything.
See the following snippet for an explanation.
var myModule = (function() {
function windowLoad() {
// window onLoad things
return;
}
function otherFunc() {
return 1;
}
window.onload = windowLoad;
return {
otherFunc: otherFunc
};
})();
console.log(myModule); // object {otherFunc: function otherFunc(){...}}
console.log(myModule.otherFunc()); // 1
As others have mentioned, your code works as written. As you've written it, otherFunc returns undefined since it doesn't have a return statement to explicitly return a value.
When you're debugging something like this, it's best to examine both the object and function you're calling separately:
console.log(myModule); // should print [Object object]
console.log(myModule.otherFunc); // should print a function definition
You could also try adding a return to otherFunc:
function otherFunc() {
return "This is otherFunc's return."
}
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/
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();
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.