Global import variables and IIFEs - javascript

A number of different articles around the web have been professing the greatness of using global import when designing modules (similiar to jQuery).
So, doing something like this...
(function(globalVariable){
globalVariable.printStuff = function(){
console.log(‘Hello World’)
};
}(globalVariable));
...means that I can call a function with something like this:
globalVariable.printStuff();
The problem is, whenever I run this in the console, I keep getting:
globalVariable undefined
My quesiton is, where exactly do I need to declare this variable so that I can get this to work?

For such a real simple module, you don't need any IIFE. Just write an object literal:
var globalVariable = {
printStuff: function() {
console.log('Hello World');
}
};
globalVariable.printStuff();
If you want to use an IIFE scope, you still have to create the object somewhere. That could be inside the module or outside:
var globalVariable = (function() {
var module = {};
var localVariable = 'Hello World';
module.printStuff = function() {
console.log(localVariable);
};
return module;
}());
globalVariable.printStuff();
var globalVariable = {};
(function(module) {
var localVariable = 'Hello World';
module.printStuff = function() {
console.log(localVariable);
};
}(globalVariable));
globalVariable.printStuff();

For a browser window object is the object that stores all the global variables. Below code shows a basic implementation of IIFEs with global variable.
//Set a variable 'globalVariable' in the window object
window.globalVariable = 10;
//Access the global variable 'globalVariable' in IIFE
(function(globalVariable) {
console.log(globalVariable);
})(globalVariable);

Related

Javascript: How to access properties and method of IIFE

I have this code and wondering how can we access properties and method of IIFE
var app = (function () {
function app() {
this.name = 'fasf';
}
app.prototype.greeting = function () {
this.a = 'hello world';
console.log(name);
window.alert('hello world');
};
app.prototype.sayhello = function () {
var j = 't';
console.log(this.a);
};
return app;
}());
also about this piece of code
var t = (function greet(name){
name = name || 'enter your name'
console.log('Hello ' + name);
})();
With the code you have, you can just do this:
// create an instance of the app object
var a = new app();
// call methods on it
a.greeting();
a.sayhello();
Your IIFE returns the internal app constructor function and then assigns that to a variable named app. So you can then do new app() to create an instance of that object. Once you create an instance of that object, you can then call any of the methods on the prototype.
In your second IIFE, nothing is returned from the IIFE so t is undefined.
The IIFE itself does not have properties and methods. That's just an immediately invoked function expression. In your first one, it returns a constructor function which is then assigned to a variable so that variable can be used to create objects with that constructor function. There are no properties or methods of the IIFE itself.
The way the IIFE pattern works is that you use local variables for the stuff you want to keep private. Local variables are are only visible inside the function they were defined in they cannot be read or written from anywhere else in the program.
If you want to expose things inside the IIFE outside the IIFE one way to do it is via the return value of the immediately-invoked function:
var stuff = (function(){
// These variables and functions are not
// visible from the outside:
var myvar1 = "Hello";
var myvar2 = "World";
var func1(){
return myvar1 + " " + myvar2;
}
// But we can return a record that contains a
// reference to our private functions, making them
// visible outside this block.
return {
thefunc: func1
}
}());
//Now we can call the "thefunc" function we exported
console.log( stuff.thefunc() );
I made sure to not repeat any variable names to avoid confusion.
In your first example, there isn't much of a point to using the IIFE pattern since there are no local variables that you are making private. You could have just defined the app function outside the IIFE and it would have worked the same.
The second case could have been written more clearly by putting the function in a separate line:
function greet(name){
name = name || 'enter your name'
console.log('Hello ' + name);
}
var t = greet();
Not only is it a bit weird to immediately invoke a named function but in your particular example, the "default argument value" pattern suggests that this function was designed to be called multiple times, sometimes passing the "name" argument and sometimes not passing it (in which case it defaults to the "enter your name" string.
When using IIFE pattern (closure) you usually keep local variables and function private as properly mentions by hugomg's answer.
In case you need to selectively make public some specific property you could consider using "The Revealing Module Pattern" instead, more info here.
Below a simple example showing this pattern:
var app = (function () {
var privateVar = 'hello world';
function sayhelloPrivate() {
console.log(privateVar);
}
function sayhelloPublic() {
console.log(privateVar);
}
// reveal public pointers to
// private functions and properties
return {
sayhello : sayhelloPublic
};
})();
app.sayhello();
//app.sayhelloPrivate(); this will not work as function is private and not visible outside module

Access Variable from a different function without creating global variables

I've recently started using CasperJS to do web automation, and something is confusing me a little.
How do access local variables from one function to another? For example:
casper.start('http://google.com', function(){
var someVar = 20;
});
casper.thenOpen('http://google.com/analytics', function(){
// How can I access someVar?jav
});
I know someVar is not in scope in the second function, but how do I access someVar in the second function without defining globals?
What about using an object to get a certain variable as property:
var myObj = {};
casper.start('http://google.com', function(){
myObj.someVar = 20;
});
casper.thenOpen('http://google.com/analytics', function(){
console.log(myObj.someVar);
});
Without using Globals you say, then create a third function (bean) which would have var someVar = 20; local variable and provide getter and setter functions to use by others.
var SharedSpace = (function(){
var shared = 20; //initialization
return {
getShared: function(){
return shared;
},
setShared: function(val){
shared = val;
}
}
})();
(function(){
alert(SharedSpace.getShared());
SharedSpace.setShared(500)
})();
(function(){
alert(SharedSpace.getShared());
SharedSpace.setShared(400)
})();
(function(){
alert(SharedSpace.getShared());
SharedSpace.setShared(10)
})();
You can't do this so that it is clean and makes sense. Defining a global variable is the only clean way. You could of course put the variable on the casper object, but that is not clean as it might interfere with the CasperJS functionality if you use wrong variable names. I only do this when I define helper functions for casper.
casper.start('http://google.com', function(){
this.someVar = 20;
});
casper.thenOpen('http://google.com/analytics', function(){
this.echo(this.someVar);
});

How are both of these referring to the same variable?

I have a very confusing situation...
(function sayStuff(){
this.word = "hello2";
(function (){
console.log(this.word);
}())
}())
var myObject = {
word: "bar",
func: function() {
(function() {
console.log(this.word);
}());
}
};
myObject.func();
Outputs
hello2
hello2
How is this happening? How can the closure on the 'func' of myObject actually see the variable that is referenced in sayStuff()? I thought IIFE were meant to protect internals from Global scope?
In both cases, this is window, the global default context replacing the one you don't provide when you call the internal function expressions.
If you want to keep the context, don't use IIFE internally or call them with the context :
(function sayStuff(){
this.word = "hello2"; // still this is window, use var if you don't want that
(function() {
console.log(this.word); // window.word
}).call(this); // well, this is window...
}())
var myObject = {
word: "bar",
func: function() {
(function() {
console.log(this.word); // myObject.word
}).call(this);
}
};
myObject.func();
IIFE only hide locally scoped variables (i.e. those created with the var keyword).
All your functions that touch this.word are invoked in the global context (i.e. not as methods of an object, not with the new keyword and not with apply, call or bind), so this is window in each case. You are dealing with global variables.
If you wanted a private variable you would do something more like this:
(function (){
var word = "hello2";
(function (){
console.log(word);
}())
}())

How to access properties of object created and returned from a function

var steve = function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
}
window["steve"]["WayCoolTest"]
running this in chrome console, my test app, anywhere results with undefined. I do not understand why, can someone explain why this does not work and help me fix it. Thank you very much!!
Using window is usually redundant - let me demonstrate:
var foo = '123';
alert(foo); //123
alert(window.foo) //123
alert(window['foo']) //123
It is evident which is more convenient. There is a circumstance in which the use of window makes sense, but that circumstance is almost always because of poor architecture. Using window allows us to access a variable global variable - funny wording :) This should clear it up:
var foo = '123';
var bar = 'abc';
var prop;
if (blah) { //some condition here
prop = 'foo';
}
else {
prop = 'bar';
}
Now...how can we use prop to get the value of a corresponding variable?
console.log(window[prop]); //123 or abc - bracket notation lets us use variable property names
This sort of thing is very common within objects, but not with window. The reason is that we should be avoiding global variables (properties of window) as much as possible. Therefore, any logic that needs a variable property name should be inside of an object, dealing with objects - NOT window. Now window can be out of the picture.
It is usually bad practice to create functions inside of other functions. That would mean that each time you call function A, you recreate function B. Most of the time, people do that because they don't know better, not because they need to.
It appears to me that you intended to give steve a property called WayCoolTest, both being functions. That can be done.
var steve = function() {
console.log("I'm Steve!");
}
steve.WayCoolTest = function() {
console.log("I'm a Way Cool Test!");
}
steve(); //I'm Steve!
steve.WayCoolTest(); //I'm a Way Cool Test!
This works because functions are objects in javascript. Therefore, you can add properties to them.
Let's step it up!
To emphasize good practices, I'm going to wrap this example in an object testApp (it acts like a namespace..we're using that instead of window).
I will create a property of testApp called steve, which will be a function.
Rather than creating steve directly as a function, I will use an IIFE (immediately invoked function expression), which is a function that will return something to be set as steve.
Inside the IIFE, I will create the function for steve and also attach WayCoolTest to it, as demonstrated in the previous example, then that function is returned and assigned to steve.
var testApp = {
steve : (function() {
var steve = function() { //the name here doesn't matter, just being consistent, since this will be the value of the property `steve`.
console.log("I'm Steve!");
}
steve.WayCoolTest = function() {
console.log("I'm a Way Cool Test!");
}
return steve;
}());
};
testApp.steve(); //I'm Steve;
testApp.steve.WayCoolTest(); //I'm a Way Cool Test!
Now, let's consider another variation.
var testApp = {
steve : (function() {
var steve = function() { //the name here doesn't matter, just being consistent, since this will be the value of the property `steve`.
console.log("I'm Steve!");
WayCoolTest(); //Steve can use this, but nothing else can! Encapsulation.
}
var WayCoolTest = function() { //THIS PART!! No longer a property of "steve"
console.log("I'm a Way Cool Test!");
}
return steve;
}());
};
testApp.steve(); //I'm Steve! I'm a Way Cool Test
testApp.steve.WayCoolTest(); //undefined, of course
That is very useful if for example steve is a complicated function and you want to break it up into some other small functions that only steve will know about.
To complement the other answers, your code would work this way:
var steve = function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
}
window["steve"]()["WayCoolTest"]();
or
var steve = (function() {
var bob = {};
bob.WayCoolTest = function () {console.log('done deal');};
return bob;
})();
window["steve"]["WayCoolTest"]();
or, the dirtiest way...
steve=(function() {
var bob = {};
bob.__defineGetter__("WayCoolTest", function () {console.log('done deal');});
return bob;
})();
window["steve"]["WayCoolTest"];
Assuming steve is in the global scope and you dont seem to use steve as a constructor you can use immediate function and return the new object that you have created inside of it.
var steve = (function () {
var bob = {};
bob.WayCoolTest = function () {
console.log('done deal');
};
return bob;
})();
window["steve"]["WayCoolTest"]();
If it is in a closure then you would have to either remove var for hoisting to happen so it becomes a part of window or set it to the window object as a property.
window.steve = (function () {
var bob = {};
bob.WayCoolTest = function () {
console.log('done deal');
};
return bob;
})();
If you declare using var it doesn't get associated with the global window scope. It's instead a local variable. Also bob is not a property on the steve object they way you have it set up

Immediately-Invoked Function Expression (IIFE) vs not

I see a lot of code like:
var myApp ={};
(function() {
console.log("Hello");
this.var1 = "mark"; //"this" is global, because it runs immediately on load. Caller is global
myApp.sayGoodbye = function() {
console.log("Goodbye");
};
})();
Which causes the anonymous function to execute immediately. But what is the advantage of this, compared to just putting the code inline?
var myApp ={};
console.log("Hello");
var1 = "mark";
myApp.sayGoodbye = function() {
console.log("Goodbye");
};
Apparently it's to do with scope of the function, but as the function is anonymous and called by window, it's scope (i.e. this) is global, no?
Usually, you would have this :
var myApp ={};
(function() {
console.log("Hello");
var var1 = "mark";
myApp.sayGoodbye = function() {
console.log("Goodbye");
};
})();
The main difference is that var1 doesn't clutter the global namespace. After this call, var1 is still the same than before (generally undefined).
As var1 can only be accessed from the function defineds in the closure, it is said "private".
Apart avoiding possible causes of conflicts, it's just cleaner not to keep global variables when useless.
Here, you don't have a local variable but a global one defined as this.var1. It's probably a bug, or the reason would be found elsewhere in the code.
One reason: wrapping your code in an anonymous function allows you to create a module which distinguishes a public API from private functions and variables that are only used internally to the module. This avoids polluting the global namespace.
var myApp ={};
(function() {
console.log("Hello");
this.var1 = "mark";
function helper() {/*Some code here*/;}
myApp.sayGoodbye = function() {
helper()
console.log("Goodbye");
};
})();
I could say:
var myApp ={};
console.log("Hello");
var var1 = "mark";
function helper() {/*Some code here*/;}
myApp.sayGoodbye = function() {
helper()
console.log("Goodbye");
};
But then the global scope includes a function called helper which is of no use to anyone using your module, and could lead to possible naming conflicts with other modules.
I could alternatively just include helper as a method of myApp.
var myApp ={};
console.log("Hello");
var var1 = "mark";
myApp.helper = function() {/*Some code here*/;}
myApp.sayGoodbye = function() {
this.helper()
console.log("Goodbye");
};
However, I may wish to prevent users from directly calling helper, in which case this won't do.

Categories