JavaScript augmented module pattern var name repeat - javascript

Can we reuse var name without overwriting its details in JavaScript.Taking below example of augmented module pattern
<script>
var Module = (function () {
// Module object
var module = {},
privateVariable = "Hello World";
function privateMethod() {
// ...
}
module.publicProperty = "Foobar";
module.publicMethod = function () {
//console.log( privateVariable );
return privateVariable;
};
return module;
})();
//Defining same name MODULE var again
var Module = (function (my) {
var newvar = 999;
my.anotherMethod = function () {
return newvar;
};
return my;
}(Module));
alert(Module.publicMethod());
//How this upper MODULE property is accessible ? Should be hide by
//next same name MODULE var?**
alert(Module.anotherMethod());
</script>
Above code is running perfectly fine and adding one more anotherMethod under MODULE but how it is still accessing initial module property. Defining var with same name (MODULE) shoudn't overwrite (remove) the upper module.

Defining var with same name (MODULE) shoudn't overwrite (remove) the upper module.
Yes, it should.
The global scope (or the function if you are inside a function) is scanned for var statements. Since you have two identical ones, the second one is ignored. MODULE is created in the global scope.
Then you run a function and then assign its return value to the MODULE.
Then you run another function, passing the current value of MODULE as an argument to it, then you assign the return value to MODULE.
A reference to the object created at var my = {} still exists in the scope of the second function, but the only reference to it from the global scope has been overwritten.

Related

Calling functions from a parameterized module.exports

Referencing this solution, I need to pass a parameter into module.exports of my utils.js file.
// utils.js
var module;
module.exports = function (name) {
if (module) return module;
module = {};
module.sayHi = function () {
return `Hi, ${name}`;
};
return module;
};
I'm a bit confused as to how to call sayHi after requireing utils.js.
// index.js
const utils = require("./utils")("Jim");
utils.sayHi();
I'm getting TypeError: utils.sayHi is not a function. What's the right way to call sayHi?
First you create a variable named module.
var module;
This does nothing because you are doing this in the scope of the module, so that variable already exists.
Then you assign a function to module.exports.
In another module, you import that function and call it.
The first line of that function says:
if (module) return module;
Is module a truthy value?
Yes. It is an object. If it wasn't, then assigning to module.exports would have throw an exception.
Consequently, you never overwrite module = {}; or assign the sayHi function to it.
Now look at the answer you referenced:
module.exports = function (app, db) {
var module = {};
It creates a new variable in the scope of the function so it doesn't conflict with the existing one.

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

Javascript: Assigning a Private Method to Private Variable

So I'm having some JavaScript issues. I'm not a pro, and don't understand why this does not work. All I am trying to do is assign my private variable to the return value of a private function. If I set var xxx=function name() will it execute the function when I reference xxx. Here is my code. Note - var username=getsessionuser(); below.
//Namespace
var SESSIONCONTROLS=SESSIONCONTROLS || {};
SESSIONCONTROLS.APP=SESSIONCONTROLS.APP || {};
SESSIONCONTROLS.APP.User = (function () {
// defined within the local scope
//Private Variable
var username=getsessionuser();
//Privatemethod
var getsessionuser=function(){var mname='My Name'; return mname;}
//Private Property & Method Example
var privateMethod1 = function () { alert("private method 1"); }
var privateMethod2 = function () { alert("private method 2");}
var privateProperty1 = 'foobar';
return {
//Public Method & Nested Namespace examples
//Public Methods
publicMethod1: privateMethod1,
//nested namespace with public properties
properties:{
publicProperty1: privateProperty1,
sessionname:username
},
//another nested namespace
utils:{
publicMethod2: privateMethod2
}
}
})();
This is how its called in another routine.
var name=SESSIONCONTROLS.APP.User.properties.sessionname;
alert(name);
Why doesn't this work?
You've got a simple ordering problem:
var username=getsessionuser();
//Privatemethod
var getsessionuser=function(){var mname='My Name'; return mname;}
JavaScript won't complain about an undefined variable reference, because it treats all the var statements in a function as if they appeared at the very start of the code. However, the initializations in var statements are carried out in the sequence they appear.
Thus, at the point your code attempts to initialize username, the variable getsessionuser is not defined.
If you simply re-order those two statements so that the function is defined first, then that part at least will work.
Alternatively, you could define the function with a function declaration statement:
function getsessionuser() {
var mname = "My Name";
return mname;
}
Then your code will work even if you leave the initialization of username before the function, because function declarations are also "hoisted" up implicitly to the start of the function.
You are calling getsessionuser() before it is defined. Move
var getsessionuser=function(){var mname='My Name'; return mname;}
above
var username=getsessionuser();

Javascript namespace and private variables

i came across following example in my training guide for HTML5/javascript/css
I don't understand why the private variables from the method are added as private variables in underlying object/namespace ns.
(function () {
this.myApp = this.myApp || {};
var ns = this.myApp;
var vehicleCount = 5;
var vehicles = new Array();
ns.Car = function () { }
ns.Truck = function () { }
var repair = {
description: 'changed spark plugs',
cost: 100
};
}());
this is the explanation the book gives:
An IIFE (pronounced iffy) is an anonymous function expression that has a set of parentheses at the end of it, which indicates that you want to execute the function. The anonymous
function expression is wrapped in parentheses to tell the JavaScript interpreter that the function isn’t only being defined; it’s also being executed when the file is loaded.
In this IIFE, the first line creates the myApp namespace if it doesn’t already exist, which
represents the singleton object that is used as the namespace. Next, an ns variable (for namespace) is created as an alias to the namespace to save typing within the IIFE, so ns can
be used in place of this.myApp. After that, the private members of the namespace are defined
by using the var keyword. Car and Truck are public, so they are prefixed with ns.
I would expect following code if they wanted to make these properties privates of the myApp 'namespace'
(function () {
this.myApp = this.myApp ||
{
var ns = this.myApp;
var vehicleCount = 5;
var vehicles = new Array();
var repair = {
description: 'changed spark plugs',
cost: 100
};
};
ns.Car = function () { }
ns.Truck = function () { }
}());
They are private because they are defined in the closure and totally encapsulated as local variables inside the closure.
ns becomes a local variable too. There is no reference back to scope outside the closure.
This is a self calling closure and the scope of the definitions is similar to defining local variables in a "normal" function.

Dynamically attach a function to grant access to private variables

I'm trying to assign a callback dynamically to an Object of mine, I can't seem to figure out a way to do this while granting this function access to private variables. I've listed the relavant code below with comments where I ran into walls.
Object Factory
function makeObj ( o ) {
function F() {}
F.prototype = o;
return new F();
}
Module
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
return myMod;
})();
Various Attempts
myMod.someDynamicFunc = function someDynamicFunc(){
//privateVar === undefined;
alert( privateVar );
}
myMod.someDynamicFunc();
myMod.prototype.someDynamicFunc = function someDynamicFunc(){
//ERROR: Cannot set property 'someDynamicFunc' of undefined
alert(privateVar);
}
myMod.someDynamicFunc();
In this attempt I tried making a setter in the module object... to no avail.
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
myMod.setDynamicFunction = function ( func ){
if(func !== undefined && typeof func === "function"){
//Uncaught TypeError:
// Cannot read property 'dynamicFunction' of undefined
myMod.prototype.dynamicFunction = func;
//also tried myMod.dynamicFunction = func;
}
}
return myMod;
})();
var myModule = makeObject( MODULE );
myModule.setDynamicFunction(function(){
alert(privateVar);
});
myModule.dynamicFunction();
Am I just using JavaScript wrong? I'd really like to be able to assign callbacks after the object is initiated. Is this possible?
You can't access the private variable via a callback function set dynamically (since it can't be a closure if it's attached later), but you can set up a system by which you would be able to access the variable:
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
myMod.callback = function(fn) {fn(privateVar);};
return myMod;
})();
var someDynamicFunc = function(param) {alert(param);};
myMod.callback(someDynamicFunc);
Of course, this makes it not really private, since anyone could do this. I don't see how it would be possible at all for you to have a "private" variable that you access via dynamically attached functions, without allowing anyone else's dynamically attached functions to have the same privilege (thus making it not really private).
I guess you did not really understand exactly how closures work.
Closures mean that scopes always have access to the outer scope they were defined in.
function Counter(start) {
var count = start;
return {
increment: function() { // has access to the outer scope
count++;
},
get: function() {
return count;
}
}
}
var foo = new Counter(4);
foo.increment();
foo.get(); // 5
The above example returns two closures, both the function increment as well as get keep a reference to the count variable defined in the constructor.
One cannot access count from the outside, the only way to interact with it is via the two "closured" functions.
Remember, closures work by keeping a reference to their outer scopes, so the following does not work:
var foo = new Counter(4);
foo.hack = function() { // is not getting defined in the same scope that the original count was
count = 1337;
};
This will not change the variable count that's inside of Counter since foo.hack was not defined in that scope, instead, it will create or override the global variable count.

Categories