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.
Related
I'm trying to find a way of accessing a scoped function - take this code for example:
(function() {
one();
console.log('IIFE END');
function scoped() {
console.log('scoped');
}
scoped();
})();
function one() {
console.log('one');
}
scoped(); // error
How can I access the call to the function to prevent the error? Using the return keyword fails
What you're doing is more or less saying "I locked the keys in the car. How do I access the keys." You can't. You locked them up in a way that makes them impossible to retrieve (well, unless you break the window, but you get my point). If you could simply open the door to get the keys there wouldn't be any point to locking the car.
That "scoped" function is the keys locked in the car.
What you want to do, is declare "scoped" outside of that anonymous function (before it, actually). Now, you can call it from within your anon function and outside of it.
You could either:
let scope;
...in anon function...
{
scope = { ...some function };
}
or
const scope = { some function }
... in anon function
scope();
Either way, outside of the anon function, you can now call "scope ()".
I guess I would add, that in JS, it's almost always possible to grab something that isn't intended to be grabbed. You could probably work with a top-level "this", or something, or just name your anon function (so essentially creating a named object that is of type function) and accessing the members of it by bracket notation. You would probably have to remove the immediate return though and call it in another line of code (after the function declaration).
But that's all hackery voodoo. You're breaking the window. In the day to day, what you say you want to do here is by design verboten.
Depending on how flexible you are, you can do this:
const scoped = (function() {
one();
console.log('IIFE END');
function scoped() {
console.log('scoped');
}
scoped();
return scoped;
})();
function one() {
console.log('one');
}
scoped(); // NO error :)
Or if your function's return is reserved for something else, just do this:
var scoped; // If you don't want this pre-declaration, you can just use a global scope instead (e.g. window.scoped)
(function() {
one();
console.log('IIFE END');
scoped = function() {
console.log('scoped');
}
scoped();
})();
function one() {
console.log('one');
}
scoped(); // NO error :)
Let's assume that I define a self-executing function like the following :
({
function1: function(){//...}
function2: function(){//...}
})
How can I call function2 from inside function1 ?
(I tried calling it just like : function2(); and this.function2(); , none worked, both returned error : function2() or this.function2() is not a function)
Actually this is part of the Aura framework, so maybe it is specific to this framework.
There are several things wrong here. First, this is not a self-executing function. This is an object with two functions defined inside it and wrapped in parentheses, which make it invalid. Something like this would be a valid JavaScript object:
object1 = {
function1: function(){
console.log('function1 called!'); // logs the text 'function1 called!' to the console
},
function2: function(){
console.log(this); // logs the details of `object1`
this.function1();
}
};
object1.function2();
Equivalent functionality using an anonymous function would look something like this:
(function (){
console.log('anonymous function called!');
})();
Note the lack of curly brackets surrounding the anonymous function. Unlike the functions in the object, the anonymous function isn't a member of any object. Also note the last set of parentheses at the end, those are what triggers the execution of the anonymous function that has just been defined.
JavaScript functions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
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!');
I want to create a closure dynamically. See code below for explanation.
function myFunction(){
parentScopedVar(); //Would like to be able to call without using 'this'.
}
function myDynamicFunc(dynamicClosure){
//What do I need to do here to dynamically create
//a var called 'parentScopedVar' that can be referenced from myFunction?
myFunction.call(self);
}
myDynamicFunc(
{
parentScopedVar : function() { alert('Hello World'); }
});
Javascript uses lexical scope (based on where the code is declared), not dynamic scope.
If you are determined to try to do something that the language doesn't really encourage, you can force a string of code to be evaluated in your current execution context using eval(string of code here). In fact, you can do all sorts of odd things with eval(), but I'd much rather write code in a way that leverages the strengths of Javascript than to use a coding style that goes against the main design theme of the language (that's my opinion).
It's not entirely clear to me what problem you're trying to solve, but you can just pass a function as an argument and then call it via the argument from the called function.
// declare your function that takes a function reference an argument
function myFunction(callback) {
// call the function that was passed
callback();
}
function myDynamicFunc(){
// declare a local function
function myAlert() {
alert('Hello World');
}
// call your other function and pass it any function reference
myFunction(myAlert);
}
This will not pass an entire execution context. To do that, you'd have to package up the context in an object and pass a reference to the object, then dereference the properties from the object. That is typically how you pass an environment in JS.
You can use locally declared functions to provide access to parent scope from a callback (again lexical scope):
// declare your function that takes a function reference an argument
function doSomething(callback) {
// call the function that was passed
callback();
}
function myFunc() {
var myLocal1 = "Hello";
var myLocal2 = "World";
function callback() {
// when this is called, it has access to the variables of the parent scope
alert(myLocal1 + " " + myLocal2);
}
doSomething(myFunc);
}
You can even use it as a lasting closure:
// declare your function that takes a function reference an argument
function doSomething(callback) {
// call the function that was passed
callback();
}
function myFunc() {
var myLocal1 = "Hello";
var myLocal2 = "World";
function callback() {
// when this is called, it has access to the variables of the parent scope
// which are still alive in this closure even though myFunc has finished
// executing 10 minutes ago
alert(myLocal1 + " " + myLocal2);
}
// call the callback function 10 minutes from now,
// long after myFunc has finished executing
setTimeout(callback, 10 * 60 * 1000);
}
Here are some reference articles on lexical and dynamic scope in Javascript:
Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?
Are variables statically or dynamically "scoped" in javascript?
What is lexical scope?
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) {