In order to be GDPR compliant I wrapped all affiliate scripts on our webshop inside functions and add them to a job queue.
After the user accepts our privacy policy I run all queued jobs. I want to run them in global scope so all declared variables are accessible in global scope because some affiliate scripts are depending on global variables (I know that's ugly ;) ).
I know, I could rewrite all the javascript code and declare the varibales in global scope and wrap the rest of the code inside a function.
But then I would need to edit a lot of external modules (we are running a magento webshop and use external modules for including the affiliate scripts)
my current approach:
var jobQueue = [];
var add = function (fn) {
jobQueue.push(fn);
console.log("function pushed to queue");
};
var execute = function () {
while ((curJob = jobQueue.pop()) !== undefined) {
curJob();
console.log("executed job");
}
};
my problem is that some external scripts are depending on the variables declared inside my jobs. Is there any possibility to run the functions like the code was run globally?
I already found something like this but I could not make it work:
Javascript eval on global scope?
(this does not work with functions)
eval.call(window, x, y, z)
I found a possible solution but it is ugly:
I save the body of the function (How to get function body text in JavaScript?) to a string and evaluate it in window scope
var execute = function () {
while ((curJob = jobQueue.pop()) !== undefined) {
var entire = curJob .toString();
var body = entire.slice(entire.indexOf("{") + 1, entire.lastIndexOf("}"));
eval.call(window, body);
console.log("executed job");
}
};
Variables in Javascript have 'function scope', meaning that if you declare a variable inside a function, it won't be accessible from outside that function.
But when a variable doesn't exist inside a function, Javascript will look for that variable outside that function until it reaches the global object.
So variables declared in the global object are visible everywhere.
You can assign variables to the global scope just by declaring them in the global scope.
var pushing = "function pushed to queue";
var executed = "executed job";
var jobTitle = "... programing ...";
var jobQueue = [];
var add = function (fn) {
jobQueue.push(fn);
console.log( pushing );
};
var execute = function () {
while ((curJob = jobQueue.pop()) !== undefined) {
curJob();
console.log( executed );
}
};
// Lets add a Job
add( function(){ console.log( jobTitle ); } );
execute();
JS Bin
As you can see, the job added has access to the variable jobTitle that is declared in the global scope.
Hope it helps
Related
I know there are a lot of posts here and elsewhere about selfexecuting functions but I still have some questions after reading posts.
why would I ever assign a self-executing function to a variable? If seems that they execute themselves anyways.
var myFunc=(function() {
console.log('Hello World');
})();
I read a lot that the reason to use self-executing functions is to keep variables private. If I have a not self-executing function, everything I define inside that function is gonna be private anyways?!
(function() {
var name="my Name"
console.log(name);
})();
vs.
function() {
var name="my Name"
console.log(name);
};
//its the same
So I dont quite understand how self-executing functions are to keep local scope (as you can do that using not self-executing functions) so the only reason I see is to use them when you want to execute automatically for example on page load.
Thanks!
just one more question:
var test=(function myFunc(){
var name="Hello World"
return {
test1: function(){
return name;
},
test2:function(){
return name+"1"
}
}
})()
test.test1()
vs
var test=function myFunc(){
var name="Hello World"
return {
test1: function(){
return name;
},
test2:function(){
return name+"1"
}
}
}
test.test1()
--> what exactly happens here that because of IIFE I can actually execute test.test1() and not with a regular function?
You usually wrap your functions in a anonymous function when you want to keep your scope contained. This is also part of the module pattern which is still pretty popular:
https://toddmotto.com/mastering-the-module-pattern/
Then you can assign the outcome of that IIFE to a variable so your scope can only be accessed by calling that variable.
myScope.myLocallyScopedProperty or myScope[myLocallyScopedProperty]
Your other function needs to be called manually and it also accessible from anywhere.
I suggest reading the article by Todd Moto it explains a lot.
If that IIFE doesn't return anything, then there's indeed absolutely no use to assign it to anything. Though there may of course be examples of IIFEs returning something you want to use later; in that case the IIFE is a private scope to set up some object for example:
var foo = (function () {
var bar = 'something';
// here be dragons
return baz;
})();
This gives you a private scope to assemble baz without unnecessarily leaking temporary variables into the global scope.
There's no difference in those examples, except that the second one doesn't execute and therefore never does anything. Scoping and the purpose for the scoping are unchanged.
First, briefly, these are not self-executing functions. (That would be a recursive function.) These are inline-invoked function expressions (IIFEs). The function doesn't call itself, the expression calls the function.
why would I ever assign a self-executing function to a variable?
That's not what that code does. It assigns the result of calling the IIFE to the variable. You'd use it when you want that result, for instance:
var x = (function() {
var n = 0;
return {
increment: function() { return ++n; }
};
})();
console.log(typeof x); // "object"
console.log(x.increment()); // 1
console.log(x.increment()); // 2
x doesn't receive the IIFE, it receives what that IIFE returns — in this case, an object with a function on it.
I read a lot that the reason to use self-executing functions is to keep variables private. If I have a not self-executing function, everything I define inside that function is gonna be private anyways?!
Yes, that's true. You use an IIFE when you only need to do what's inside the IIFE once. Otherwise, absolutely, you define the function, give it a name, and then reuse it wherever you need it. The variables inside the function are indeed private to it (unless exposed in some way), and are specific to each call to the function.
1: To assign an IIFE to a local Variable makes sense for something like that:
var getID = (function () {
var id = 0;
return function () { return id++; };
})();
This way you can get new IDs without running the risk to reset the internal counter from anywhere else in the code, except by redeclaring the variable.
2: Basically you create Scope by creating a function. But if you do not execute it, well, it doesn't do anything. So if you have that:
function () { return 'foo' };
How do you want to call it if it is not assigned to a variable or does not have a name? By itself it wont do anything, since it is not called. Something like that is dead code and can safely be removed.
your first thing has no sense whatsoever:
var myFunc = =(function() {
console.log('Hello World');
})();
myFunc is not a function and it is undefined.
The sense, as I see it, for a self executing function is to package some code that has to be executed right away.
var p1=1, p2=2, obj = {
prop: (function(x,y){ return x+y;})(p1, p2)
}
OR
avoiding overwriting already defined functions/objects in the case your script will be inserted in a already existing application and also creating a kind of private methods, if you like:
function aFunction() {
console.log('a code');
}
(function(w) {
function aFunction() {
console.log('b code');
}
w.run = function() {
aFunction();
};
})(window)
aFunction();
run();
You use self executing functions to expose only what you need out of a scope. I think I have a somewhat clear example:
let myObject = (function(){
let privateVariable = "I'm private";
function privateMethod() {
//private method
};
function methodToExpose() {
//this method I will expose
}
//what is returned here, is what is public
return {
PublicMethod: methodToExpose
//other public properties
}
}());
So, the function gets executed immediately, and what happens is I have an object that is defined by what I returned from the function.
Another example I could give you is to retain variables of the current scope inside a closure, but you wouldn't really use it that much, since we now have let. A practical example:
<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
toPrint = "new: " + i;
document.getElementById(i.toString()).addEventListener('click', function(event){ event.target.innerHTML = toPrint; })
}
</script>
When you click on a span, the value will be replaced with the value... "new: 4"!
That's because when you finished executing, that's the value that toPrint has. The function assigned to the click event retrieves that toPrint, and at the time it retrieves it, it is "new: 4". We solve this with closures:
<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
toPrint = "new: " + i;
document.getElementById(i.toString()).addEventListener('click', function(event){
var currPrint = toPrint;
return function(event){ event.target.innerHTML = currPrint ; };
}())
}
</script>
By using a self executing function, we save the current value of toPrint in the currPrint variable inside a local scope. When we later click on a span, the function assigned to the click even will use the variable currPrint, which contains the value that toPrint had at the time the function was assigned, not the value that toPrint has at finished execution.
Note that this is solved also by using let instead of var, but still, it's an example of self-executing functions :)
In the form of IIFE (or immediately invoked function expressions), they can then be used to create plugins or used as namespaces and attached to window / jquery / or other global level object for use later.
When you name a function like assigning anonymous function to a variable, you can use it later by calling the variable with parentheses, in your example, defined myFunc with
var myFunc=(function() {
console.log('Hello World');
});
Use it later in code as myFunc();
In your example, you are storing the output of function directly in variable, by calling it immediately, and there is no output to be stored.
So, if you later write console.log(myFunc);, there is undefined as output.
Better IIFE example from your code samples is the one mentioned below.
(function() {
var name="my Name"
console.log(name);
})();
It executes, does a console.log and that's it. Adds nothing to namespace or the global object in your case.
The last of your examples defines a function, does not execute it then, and since it does not have a named variable assigned, or a name, it gives syntax error and cannot be used later in code. So, below example is useless.
function() {
var name="my Name"
console.log(name);
};
You have added two more examples with var test = function myFunc. First one will work fine with test.test1(). For the second one, you need to evaluate test as a function first and then call its function, like test().test1().
I guess you miss something here. Just to make basic things clear - if you assign a self executed function to a variable the actual return value of the function when executed at this time is assigned to the variable and not the function itself.
var myFunc = (function() {
console.log('Hello World');
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === undefined
var myFunc = (function() {
console.log('Hello World');
return 'japp';
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === 'japp'
So why is this pattern around?
IIFEs are very useful to
limit the scope
if you declare
var test = 'test'; // var test actually will be assigned as a property of the current context (this)
window.test = 'test'; // so you pollute the global namespace which is not a good practice
so this would be mouch better
(function() {
var test = 'test';
})();
another very good thigs with IIFs is that you can achieve a design with "privates"
var myFunc;
(function() {
var i = 0; // i is available for myFunc with private access
myFunc = function() { console.log( ++i ) };
})();
myFunc(); // logs 1
myFunc(); // logs 2
I have this code snippet.
var mapping = {};
_.each(labels,function(i,label){
debugger;
});
but mapping variable is not accessible inside the function.
I have a similar code somewhere else
var labels = {};
_.each(arrOfFields, function(element,index){
labels[prefix+element.fcnbb] = element.UI.label;
});
and labels is accessible here and i am able to use it.
Please explain me why does this happen ??
The problem here that mapping variable isn't declare within the function code block.
In debug mode if you used a callback function like in here you need to declare it within the function, so debugger will save it as his local variable.
so:
var mapping = {};
_.each(labels,function(i,label){
console.log(mapping); // here
debugger;
});
Just write variable name even in console.log() function, the debug will know his local variables, and then you will have an access to the variable itself.
I have some functions inside of functions and I am having trouble retrieving a variable. It will be easier to show in code I want to log the var three in the testit function but not sure how to do so.
test();
function test(){
var abc;
function one(){
abc = 1;
two();
}
var three;
function two(){
console.log(abc);
three = 2;
testit();
}
one();
}
function testit(){
console.log(three);
two();
}
to make test an object you would do the following:
function test(){
this.abc = 0;
this.three = 0;
this.one();
}
test.prototype.one = function(){
this.abc = 1;
this.two();
}
test.prototype.two = function(){
console.log(this.abc);
this.three = 2;
}
test.prototype.testit = function(){
console.log(this.three);
this.two();
}
and run it like so:
testObj = new test();
testObj.testit();
hope this helps.
edit: BTW: if you put a call in function 'two' back to function 'testit' you'll end up with an infinite loop.
Here's an explanation of what's happening:
When you wrap code in a function, you get what's called function scope. This means that the scope within the function belongs to the function and not to a scope above or outside of it (whichever way you want to look at it).
A closure allows an expression (typically, a function, as MDN states) to have it's own scope while sharing the scope of it's outer or higher scope.
So, let's look at an example:
// This represents the global, or window, scope.
// Analogous to window.outer_var.
var outer_var = 'outer var';
function outer_func() {
// New scope! Local only to outer_func and those
// expressions (functions) *enclosed* by
// `outer_func(){...}, e.g. inner_func(){...}.
var inner_var = 'inner var';
// Only outer_func() or inner-enclosed (to
// inner_func()'s definition) functions can
// access inner_func().
function inner_func() {
// Another new scope! Can access inner_var
// and inner_func_var (below). outer_func()
// canNOT access inner_func_var, though.
var inner_func_var = 'inner func var';
}
}
outer_func(); // Of course, it's in scope and accessible.
inner_func(); // This will cause ReferenceError: inner_func is not defined error.
Simply as it is (no wrapping context, with a closure), var outer_var is created with the global or window scope. It may be accessed in all of the following:
console(window.outer_var);
function outer_func() {console.log(outer_var);}
function inner_func() {console.log(outer_var);} No matter where inner_func's defined.
Here, #2/3 are analogous to:
function outer_func() {console.log(window.outer_var);}
function inner_func() {console.log(window.outer_var);}
Or global this:
function outer_func() {console.log(this.outer_var);}
function inner_func() {console.log(this.outer_var);}
Now, inner_var is accessible from the following:
function outer_func() {console.log(inner_var);}
function inner_func() {console.log(outer_var);} Only from within outer_func().
inner_func() may also only be accessed within outer_func(), because it belongs to the outer_func() scope, and thus is not visible/accessible outside of outer_func()*.
Lastly, inner_func_var is only accessible by:
function inner_func() {console.log(inner_func_var);} Only within outer_func().
To access your three variable, you have three choices:
Make three globally accessible (globals are generally discouraged as they may easily introduce difficult to resolve bugs when one is overwritten by some other code).
Return three from your test() function. In this case the value is accessed, not the actual variable within the function.
Create a property as #logic8 demonstrates, so it may be accessed as a property of an object.
* This isn't entirely true. outer_func() could export a reference to the function out of scope with return inner_func;. This is a more advanced concept, though, and won't be addressed here in depth. Here is an example.
You have to put it in a global to do so:
test();
var three = false;
function test(){
[..]
}
function testit(){
console.log(three);
two();
}
when you declare a variable with var it becomes local to that scope. If you want to access three in both functions, you can either declare it without var (making it global - generally frowned upon for good reasons) or declare it outside of the two functions: var three;
The correct way to do this is by using the closure pattern in javascript. This wraps your javascript class in its own function so anything you declare within that file is only local to your code.
Using jQuery, this is easily accomplished like so:
(function($){
//your code goes here
})(jQuery);
People typically do it this way so their javascript only executes when the page is ready:
$(document).ready(function(){
//your code goes here
});
It's a bit more complicated without jQuery if you want to execute your code when the document is ready:
document.addEventListener('DOMContentLoaded', function(){
console.log('document is ready. I can sleep now');
});
With your code, it would look something like this:
$(document).ready(function(){
var test = function(){
//test code here
};
var one = function(){
//one code here
};
var two = function(){
//two code here
};
var three = function(){
//three code here
};
var testIt = function(){
//test code here
};
});
This way, you can safely access all of your functions from the others without polluting the global namespace.
A couple of days ago I have learned on my own example how bad global variables and functions are. So apparently the best solution is NOT to use them, however sooner or later I will need to reuse my variables and functions over and over again.
So my question is: Can I reuse my functions and variables without declaring them globally? Can it be done?
For example, I want to reuse my alertBox function and my containsP variable couple of times:
DEMO: http://jsfiddle.net/ajmyZ/
//I am BAD GLOBAL FUNCTION inside var
//But I am reusable!!!
var alertBox = function () {
alert("Hey I am BAD function!!")
}
$(document).ready(function () {
//I am BAD GLOBAL var
//But I am reusable TOO!!!
var containsP = $("div p:first");
containsP.click(function () {
alert("Hi BAD var HERE!!");
});
$("p").eq(1).click(function () {
alertBox();
});
//I am the NICEST function here
//but I am NOT reusable :(
$("p").eq(2).click(function () {
alert("I am the NICEST function here!!");
});
});
I guess the simplest way to avoid clobbering the global object is just to create your own "application context". You can do that, by creating a self-invoking function which wraps your whole js-code within each file.
(function( win ) {
"use strict";
var still_global_but_only_in_this_anonymous_closure = true;
$(document).ready(function() {
// ...
// accessing the global object:
win.some_global_property = true;
});
}( this ));
Actually, you're already creating such a local context with your anonymous function you pass into .ready(). This is just the more explicit way. That self-invoking method, just calls itself with the global object as argument (where you still can explicitly access global variables). Furthermore, by invoking "use strict"; you're protected from accidently creating global variables alá "Ops_I_Forgot_The_Var_Statment = true;
The code you posted has no global variables. A variable declared inside of a function (in the case of your example, the anonymous document.ready handler) will never be global unless you make one of two mistakes:
forget the var keyword, making an implicit global
explicitly say window.myVar = ...;
I'm trying to optimize a small web application's use of JavaScript variables. I have about five functions that each produce an Ajax call, and repeatedly make use of a query string. Should I declare the query variable inside of each function, or will it increase efficiency to declare it globally? A very simple example of what I'm talking about is:
Local Declaration
<script type="text/javascript">
function queryOne() {
var queryString = "query arguments";
}
function queryTwo() {
var queryString = "query arguments";
}
</script>
Global Declaration
<script type="text/javascript">
var queryString;
function queryOne() {
queryString = "query arguments";
}
function queryTwo() {
queryString = "query arguments";
}
</script>
Is there are notable efficiency benefit to using the global declaration scheme?
Should be declared locally, as any global declaration will take extra time to look for the variable in the local scope and then the global scope, making the global declaration actually slower. Plus a variable declaration might not require a search for the variable name, it can simply just attempt to create a new variable.
Also, if code were added in the future, declaring the variable globally could cause it to be overwritten by other code or conflict.
Actually you might save a little time with a module level variable, if the query string is only assigned to once. However, if you are reassigning the query variable each time the function is called, then you definitely save time making the query variable local to each function.
You could enclose it for neatness;
var MyApp = {
queryString: null,
queryOne: function() {
print( this.queryString );
},
queryTwo: function() {
print( this.queryString );
}
}
.
MyApp.queryString = "foo=boob";
.
a = MyApp.queryOne(123);
b = MyApp.queryTwo(456);