I have a file bg.js whose contents is simply an IIFE. I'd like to load this file/call the function in from another function in another file. Since the IIFE is anonymous (it is, right?) I can't call it by name. It seems I have to load the entire file so it executes immediately.
I've done searching and found many tutorials and documents about what an IIFE is, but nowhere had I seen how to execute one from another scope.
How do I call/load a javascript file that is an IIFE from another javascript file?
More Information
The IIFE is loaded in the footer of my page. When I click a link to navigate, the header and footer scripts are not executed. The IIFE in the footer is responsible for setting the background image, so I need to get that function to execute in my perPageBindings()
What I think I need to do is invoke the IIFE from another function in the body which is being executed in perPageBindings()
Edit for clarity
There are two options I am considering:
Simply move the script tag to the body from the footer; or
Give the IIFE a name so it is no longer anonymous and then call that named function from elsewhere
If 2 is a viable option then I think I will create a new question about converting and IIFE to a named function.
If you want to access something within that script, a function or a property, after it has been anonymously invoked, you'll need to expose some of the internals of that function to something that is accessible from global scope.
I'm not saying that you must have your function put a variable into global scope, although that is what many libraries do and is one of the paths that UMD follows if a CommonJS or AMD environment is not available.
You should look into the Revealing Module Pattern for a better perspective.
Consider the following code snippet:
(function(global){
/*
* This variable will stay "private"
* because it is scoped to the IIF
*/
var someProp = "Hello World";
/*
* This property is effectively exposed
* because it is accessible through
* myLib.foxtrot below
*/
var someOtherProp = "Hello to you too";
var myLib = {
foo: "bar",
fiz: true,
buzz: 1,
foxtrot: someOtherProp
};
/*
* myLib is now accessible through the
* global that we passed to the IIF below
* at the point of calling with "window"
*/
global.myLib = myLib;
}(window));
Seems like you want to define this function some where that makes it reusable. If you want to invoke from the footer wrap the reusable function call in an IIFE. That way its immediately invoked in the footer and calls your function but you can also call this function elsewhere.
Example:
JS:
function setBackground () {
// sets background and can be called whenever
}
HTML:
<footer>
<script>
(function () {
setBackground();
} ());
<script>
</footer>
There is no need to import the global to an IIFE
instead of coding
(function(global){
//...
global.myLib = myLib;
}(window));
you can code directly
{
window.myLib = {
//...
};
}
I add IIFE always to a namespace, so it's easy referable.
var app = {};
{
app.myLibrary = {
log: (str) => window.console.log(str),
};
// is executed immediately
window.console.log(`myLibrary = ${app.myLibrary}`);
}
{
app.external = {
call: (str) => app.myLibrary.log(str),
};
// is executed immediately
window.console.log(`external = ${app.external}`);
}
// is easy referable
app.external.call('Hello World!');
Related
I have an IIFE in my code, where there are few other IIFEs. All of them have names (so they aren't anonymous). I want to invoke some of IIFE later (i mean, yes they do their job at the beginning, but i want use them later), by other function. Like in example:
(function start()
{
/* some code*/
(function firstIIFE(param1, param2)
{
if (param1 && param2)
{
console.log('param1 ',param1, 'param2 ',param2);
return;
}
/* some code done when IIFE originally was self-invoked */
}(param1, param2));
/* some code */
}());
function foo()
{
start.firstIIFE(param1, param2);
}
Is it possible, to invoke (firstIIFE) IIFE later? Because i want this function to do some things with param1 and param2 (which i created after those IIFE was invoked)?
Currently i got error like: Uncaught ReferenceError: param1 is not defined
The way your code is written, you won't be able to access firstIIFE() outside of start(), as it's an internal function. In order to access it later, you'll need to expose it some how, by either setting an external variable to that function, or moving it outside of start() and having start() just call the function, rather than defining it and then immediately executing it:
function firstIIFE(param1, param2) {
if (param1 && param2) {
console.log('param1 ',param1, 'param2 ',param2);
return;
}
/* some code done when IIFE originally was self-invoked */
}
(function start() {
/* some code*/
firstIIFE(param1, param2);
/* some code */
}());
function foo() {
firstIIFE(param1, param2);
}
(At that point you probably don't need to call it firstIIFE(), since it doesn't follow the Immediately Invoked Function Expression pattern anymore, rather it's now just a normal function call).
The name of function expressions isn't accessible to the scope where they are created, and thus can't be invoked from that scope without storing a reference to the function in a variable.
But storing your functions in variables instead of declaring them has the side effect of not hoisting your function to the top of the current scope, which is something you rarely want.
You can do:
(foo = function myNameIsKnownOnlyToMyself() {
...
})();
foo(); // again!
if you really love your IIFE pattern, but as others said, this is likely not the most elegant solution to your problem.
I read some JS module design patterns recently. I came across this small code snippet as below.
(function(window) {
var Module = {
data: "I'm happy now!"
};
window.Module = Module;
})(window);
Still not quite understand this code well, my questions are:
How to use/call this module outside this particluar JS file? Need I
assign a variable to this module? e.g. var module1 = (...)(...);
Could anyone explain what the window parameter here stands for?
Is it a good practice to have two/three such kind of modules in the
same file?
The main reason to create an anonymous function in this case is to prevent global object pollution. It's not really a module pattern.
The problem arise when you declare a variable. Without the function scope, the variable will be added to the global object (window). If you were to declare the variables within a function. It would add the variable to the function scope without polluting the global object window.
What happen is that a javascript file could add a variable named foo and on a different file use that variable named foo too. Unless you really want to have a variable shared by two javascript files, it would probably create conflicts and bug that are difficult to fix.
For example: a.js
var foo = "one"
b.js
var foo = "two"
c.js
alert(foo)
In this case, the alert box might show either "one" or "two", depending of the order in the javascript files are included.
But having this a.js:
(function () {
var foo = "one"
})()
b.js
(function () {
var foo = "two"
})()
c.js
(function () {
alert(foo)
})()
This would create an error as you cannot alert a non declared variable.
One way to detect undefined variables, is to make sure to execute the javascript code in strict mode.
To do that, add the string "use strict" at the top of the file or function.
function () {
"use strict"
...
}
Undeclared variable will raise errors and it should be possible to fix the code that way.
Also, if you forget to declare a variable with the var keyword, it might end up adding the variable to the global scope even if the code is scoped into a function. The only way to prevent global scope pollution is to run the code in strict mode.
In the code snippet that you provided, the module with name Module is explicitly added to the window object. You can access the window object from any place in javascript unless the window name is ghosted by an other variable.
Now, back to the modules. If you want to define modules, it can be done in many ways. As an exemple, you could create an object on the window object called modules. In this object, you'll insert your modules.
module.js
window.modules = {}
foo.js
(function (window) {
var module = {}
...
window.modules.foo = module
})(window)
This variant isn't super good as you have to manually add the module to the modules object. You have to manually modify the window object, and that can be subject to errors.
modules.js
window.modules = {}
function define(name, constructor) {
var module = {exports: {}}
constructor(module)
window.modules[name] = module.exports
}
function require(name) {
return window.modules[name]
}
foo.js
define("foo", function (module) {
module.exports.one = function () {
return 1
}
module.exports.plus = function (a, b) {
return a + b
}
})
bar.js
define("bar", function (module) {
module.exports = function () {
var foo = require("foo")
return foo.plus(foo.one(), foo.one())
}
})
This is a module definition that looks a bit like module defined with http://requirejs.org/. It is quite basic as it doesn't take into account module dependencies so if bar is loaded and used before foo. Then the require method won't be able to return the module.
Also, if you want to store modules without having them visible into the global scope, you can only define the require and define method on the window object and hide modules into an anonymous scope like this:
(function (window) {
var modules = {}
function define(name, constructor) {
var module = {exports: {}}
constructor(module)
modules[name] = module.exports
}
function require(name) {
return modules[name]
}
window.define = define
window.require = require
})(window)
This way, define and require are the only function that can give you access to modules. Other modules won't be able to modify other modules without requiring them first. This can be useful when using third parties script that could conflict with your module system.
In fact this is not a module, but a Self-Invoking Ananymous function or an Immediate function which gets an object in parameter and assign a Module property to it:
The page window is a parameter passed to this function.
So an object named Module containing a data property is assigned to window.
JavaScript Self-Invoking Functions:
A self-invoking expression is invoked (started) automatically, without being called.
Function expressions will execute automatically if the expression is
followed by ().
You cannot self-invoke a function declaration.
You have to add parentheses around the function to indicate that it is
a function expression
So As you can see Immediate Functions can't be called as its name states it will be immediately executed and by its self, no other function or scope can execute it.
For better reference take a look at :
Javascript Self Invoking Functions.
Self-Invoking Functions section in JavaScript Function Definitions.
And concerning your last question about its benefits and good practices as shown on the given Article reference:
Where to use self-executing functions?
One obvious situation is when you want to auto-run a function like I
showed in above example but that is trivial. If you are in a situation
where you want to run a piece of code repeatedly like updating
something in the database based on user interaction or fetching
records from database every 10 seconds or you want to load new stories
via ajax similar to how facebook does on its homepage or some other
similar situation, one would normally go for setInterval function
something like this:
setInterval(doStuff, 10000);
Above, doStuff function will get called every 10 seconds. That is the
normal approach most developers seem to go with. However, there is a
huge problem with that.
The setInterval will call doStuff function exactly at specified time of 10 seconds again and again irrespective
of whether doStuff function actually finished doing what it is
supposed to do. That is bad and will certainly get you into unexpected
results.
That is one example of where setInterval is "bad" and should be
avoided.
This is exactly where self-executing functions come in handy. We can
do the same task with the help of self-executing function along with
setTimeout like this:
function foo(){
// your other code here
setTimeout(foo, 10000);
}();
This code will also repeat itself again and again with one difference.
setTimeout will never get triggered unless doStuff is finished. A much
better approach than using setInterval in this situation.
Calling it from another file:
And if this function is on another file it will be called automatically if this file is included.
Why do we use Self-Invoking Functions in JavaScript?
And if you ask yourself why do we use these functions, self-invoked function are used to manage Variable Scope.
Take a look at the answer here for further information.
What is the main difference between a module like this
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {}
my.moduleProperty = 1;
my.moduleMethod = function () {};
return my;
}());
and a simple function like this
function MODULE_Func() {
var my = {},
privateVariable = 1;
function privateMethod() {}
my.moduleProperty = 1;
my.moduleMethod = function () {};
return my;
};
var MODULE = MODULE_Func();
I read an article about modules and in it an author describes a module's advantages as: "the module maintains private internal state using the closure of the anonymous function."
i.e, I think he means that 'privateVariable ' and 'privateMethod' is internal for the module and not acceptable from outside. But in the simple function 'privateVariable ' and 'privateMethod' are also internal and not acceptable from outside. The only difference I can see is that the module is a anonimous function so it: 1) doesn't pollute a global state 2)you can't invoke the module twice.
But the author describes a module pattern as a great thing but I can't see for what. And because you can't invoke the module twice, you can't have more than one instances of modules, I think in many cases it is even a disadvantages.
But the author describes a module pattern as a great thing but I can't see for what
Well, you've said it yourself: 1) doesn't pollute a global state 2) you can't invoke the module twice. Those are advantages if you want them.
And because you can't invoke the module twice, you can't have more than one instances of modules, I think in many cases it is even a disadvantages.
Those modules are static. Indeed, they should not have internal state but only local (internal) variables, e.g. for helper functions.
In cases where you need multiple instances, don't use a singleton-like module. Use a constructor ("class") instead, like in your second example. You might however still use a module as a namespace for your class.
the difference is that the first one
var MODULE = (function(){})();
MODULE refers to whatever an the anonymous function being executed will return. if it returns nothing then **MODULE will be set to undefined. the function being executed is an IIFE(Immediately Invoked Function Expression), More info here. It executes on page load since MODULE is referred by the global window.
and the second is a function MODULE_func(){}, MODULE_FUNC is the name of the function itself, this function is now a property of the global window meaning that it can be referred by the global window as so window.MODULE_func(){};, the other can be referred as well but note the difference, the other is an anonymous function without a name and has TWO referrers. This one has a name and one referrer..
var MODULE = (function(){})();
can be referred by
window.MODULE;
MODULE;
function MODULE_func(){}
can be referred by
window.MODULE_func; ONLY
I have two external .js files. The first contains a function. The second calls the function.
file1.js
$(document).ready(function() {
function menuHoverStart(element, topshift, thumbchange) {
... function here ...
}
});
file2.js
$(document).ready(function() {
setTimeout(function() { menuHoverStart("#myDiv", "63px", "myIMG"); },2000);
});
The trouble is that this is not running the function. I need the two separate files because file2.js is inserted dynamically depending on certain conditions. This function works if I include the setTimeout... line at the end of file1.js
Any ideas?
The problem is, that menuHoverStart is not accessible outside of its scope (which is defined by the .ready() callback function in file #1). You need to make this function available in the global scope (or through any object that is available in the global scope):
function menuHoverStart(element, topshift, thumbchange) {
// ...
}
$(document).ready(function() {
// ...
});
If you want menuHoverStart to stay in the .ready() callback, you need to add the function to the global object manually (using a function expression):
$(document).ready(function() {
window.menuHoverStart = function (element, topshift, thumbchange) {
// ...
};
// ...
});
You have declared menuHoverStart inside a function (the anonymous one you pass to the ready ready). That limits its scope to that function and you cannot call it from outside that function.
It doesn't do anything there, so there is no need to hold off on defining it until the ready event fires, so you could just move it outside the anonymous function.
That said, globals are worth avoiding, so you might prefer to define a namespace (to reduce the risk of name collisions) and hang the function off that.
var MYNAMESPACE = {}; // In the global scope, not in a function
// The rest can go anywhere though
MYNAMESPACE.menuHoverStart = function (element, topshift, thumbchange) {
If I want to give a JavaScript variable global scope I can easily do this:
var myVar;
function functionA() {
myVar = something;
}
Is there a similarly simple and clean way -- without creating an object -- to separate the "declaring" and the "defining" of a nested function? Something like:
function functionB; // declared with global scope
function functionA() {
functionB() { // nested, would have local scope if declared here
CODE;
}
}
I should clarify that I'm referring to the scope of the function name itself -- so that if it is in an iframe it can be called from a script in the parent document. (Nothing to do with scope of variables inside nested functions.)
You can create global variables and functions by creating instances on the window object:
function _A()
{
// scoped function
function localFunctionInTheScopeOf_A()
{
}
// global function
window.globalFunctionOutsideTheScopeOf_A = function ()
{
};
}
In your case, though, all you need to do is this:
var myFn; // global scope function declaration
function randomFn()
{
myFn = function () // global scope function definition
{
};
}
Note: It is never a good idea to clog up the global scope. If you can; I'd recommend that you re-think how your code works, and try to encapsulate your code.
Perhaps I'm misunderstanding the question, but it sounds like you want something like this:
var innerFunc;
function outerFunc() {
var foo = "bar";
innerFunc = function() {
alert(foo);
};
}
You cannot globalize variables/functions cross windows/iframes that way. Each window/iframe has it's own global scope and to target variables/functions in another window/iframe, you need explicit accessor code and conform to the same origin policy. Only variables/functions inside the windows/iframes global scope are accessible.
code in top window.
var iframe = document.getElementById('iframeId');
var iframeContext = iframe.contentWindow || iframe;
// this will only work if your iframe has completed loading
iframeContext.yourFunction();
You could also possibly define functions/variables in the top window instead and simply work in one scope by binding the stuff you need from the iframe through a closure. Again, assuming you meet the same origin policy. This will not work cross domain.
code in iframe.
var doc = document;
var context = this;
top.myFunction = function(){
// do stuff with doc and context.
}
It is also important to note, that you need to check if your iframe content and it's scripts are fully loaded. Your top page/window will inadvertidly be done and running before your iframe content is done, ergo variables/functions might not be declared yet.
As for exposing a private function, others have awnsered this, but copy/pasting for completeness.
var fnB;
var fnA = function(){
var msg = "hello nurse!";
fnB = function(){
alert(msg);
}
}
I have the habbit of declaring stand alone functions as variables (function expression) and only use function statements to signify constructors/pseudo-classes. It also avoids a few possible embarrasing mistakes.. In any case, fnB resides in the global scope of the iframe and is available to the top window.
Why exactly you want this beats me, seems it makes matters more complicated to debug or update a few months later.
You can kind of do what you want.
You can create a function that acts like a namespace for properties and methods, and then you could essentially call either...
functionB();
or
functionA.functionB();
There is an article on how to do it here:
http://www.stevefenton.co.uk/Content/Blog/Date/201002/Blog/JavaScript-Name-Spacing/
In response to the update...
Is the iframe on the same domain as the parent site? You can't call JavaScript across the domain boundary, which may explain the problem.