Alternative to global variables in javascript/jquery? - javascript

So, I've got my app to work. But I don't want to use a global variable.
Here's what I'm trying to do:
var AMLid;
$(".commentButton").on('click', function () {
AMLid = $(this).closest('tr').siblings().find('p.important').text();
alert("id is:" + AMLid);
});
$(".saveButton").on("click", function () {
$(".modal-body #txtAddComment").val(AMLid);
});
I want to get an ID from a selected table row, and pass the ID to the modal dialog, so I then can use the ID as a parameter when clicking a button in the modal dialog.
How do I do the exact same thing, without using a global variable? is it possible?
And what are the cons of using a global variable like this? Does it crash or target the wrong ID's if many people use it simultaneously?
Any help is appreciated.

You can wrap the whole thing in a function
(function(){
var AMLid;
$(".commentButton").on('click', function () {
AMLid = $(this).closest('tr').siblings().find('p.important').text();
alert("id is:" + AMLid);
});
$(".saveButton").on("click", function () {
$(".modal-body #txtAddComment").val(AMLid);
});
})();

You can avoid the use of a global variable by using an Immediately-Invoked Functon Expression, which would look like this:
(function() {
var AMLid;
$(".commentButton").on('click', function () {
AMLid = $(this).closest('tr').siblings().find('p.important').text();
alert("id is:" + AMLid);
});
$(".saveButton").on("click", function () {
$(".modal-body #txtAddComment").val(AMLid);
});
})();
This works because the AMLid is now private to the function; when the function is executed it creates a new execution context which includes that variable, which is then accessible to statements made in the function, but not outside it. And because this creates a closure the variable continues to be accessible by the callbacks attached to those functions. Moreover, as the function is anonymous it itself doesn't have a name polluting the namespace.
The term Immediately-Invoked Functon Expression comes from Ben Alman, and you can read his original blog post discussing the concept here: http://benalman.com/news/2010/11/immediately-invoked-function-expression/
Some cons of using a global include: hard to keep track of variables, other scripts might mess with its value (when they probably shouldn't have access to it), harder to maintain, less clean code. Your worry about it being overwritten if multiple people use it won't be an issue because it's client-side and so there will be one instance per page loaded in any given browser.

Javascript is client-side so actually I can't get the point in your "many people use it simultaneously". One browser for user, so you don't have to worry about multiple client. Each one use his own set of global variable.
If your executions are not linked in any way (they are "onclick") you can just wrap them in a function so you're actually setting a "local/global" variable.
Every function that'll need that AMLid has to be declared inside that function scope.

The only way to keep variables out of the global scope is by wrapping them in a function. If this is all the code you're using in this particular module, it doesn't really make a difference.

Related

How do I make a nonexistent (non-member, non-global) method invocable without using eval?

Let's start from the code:
function say(name) {
var ghost=function () {
function ghost() {
alert('!');
};
return body;
};
eval("var body=''+"+name+';');
eval(name+('=('+ghost).replace('body', body)+')();');
eval(name+'();');
}
function Baal() {
if ('undefined'===typeof ghost) {
say('Baal');
return;
}
ghost();
}
say('Baal'); // or just Baal();
Looks like that saying the devil's name invoke his presence (well, maybe he needs somebody for spiritual possession) ..
As you can see the ghost doesn't exist along with Baal, but we can invoke it since there're evals in say(name).
say(name) reassigns Baal to its code body as a closure and makes it captured a ghost method, that's how things work. But I'm trying to avoid eval ..
So .. let me reword the question:
How do I make a nonexistent(and not a member or global) method invocable without using eval?
Let me rephrase your question, just to make sure I’ve got it. Given a function, you want to put a new variable in its scope, without that scope being the global scope or a scope shared between the caller and the subject, without using eval (or the equivalent new Function and other hacks depending on the environment).
You can’t.
In the case you just mentioned, you could define one function, base(), that uses arguments.callee.caller.
Don’t do that.
The short answer: You don't.
That scope is not available. If you were to attach the scope then it would be available inside of the scope used. You could then access the method handles. I assume this is not what you were looking for, but here is what that would look like. demo
function say(name){
var methods = {};
methods.Baal = function(){
alert("!");
};
return methods[name];//this could invoke as well: methods[name]()
}
var handle = say('Baal');
handle();
What your evals break down to is something along these lines (although with dynamic content from string building - this is the end result)
function say(name) {
var Baal = (function () {
function ghost() {
alert('!');
};
return function(){
if ('undefined'===typeof ghost) {
say('Baal');
return;
}
ghost();
}
})();
Baal();
}
say('Baal'); // or just Baal();
Note that the meat of what happens here is from the function Baal, namely that it calls a hardcoded ghost() which in turn calls a hardcoded alert. Why go through all of this trouble to access a hardcoded function?
A better way would be to inject this function as a callback which expects some parameters to be injected.
jsFiddle Demo
function say(callback){
var params = "!";
if( typeof callback == "function" ){
callback(params);
}
}
say(function(params){
alert(params);
});
It's very difficult for me to read through your code and figure out what you are trying to accomplish with it, but it appears that you are trying to introduce a variable into the current scope so that you can call it. You cannot do this in javascript with the method that you demonstrated. Scoping only ever "flows down". By that I mean that a variable or function defined within a function will only be available to that function and any other functions defined therein. Your function named ghost will only ever be available within the function where it is defined, regardless of when that function is evaluated.
What you can do, however, is write a function that returns a function. You can then call that function and assign the result to a variable in the scope where you want to expose functionality. Doing that would look something like this.
function defineSpecialAlert() {
return function(name) {
alert(name + "!");
};
}
var newlyDefinedMethod = defineSpecialAlert();
newlyDefinedMethod("Baal");
So if I understand, it seems like you want to create an alias of eval: Something like
#Note this code is not intended as a solution, but demonstrates
#an attempt that is guaranteed to fail.
#
function myAlias(ctx) {
eval.call(ctx, 'var ghost = 42');
}
myAlias(this);
alert(ghost);
Javascript allows many funky sleight-of-hand tricks especially with closures, but this is maybe the one impossible thing that javascript cannot do. I've tried at length to do this exact same thing, and I can tell you that you'll run into nothing but complaints from the browser, saying that eval cannot be re-contexted or aliased in any way.

Access a javascript variable from a function inside a variable

Hello i have the following issue i am not quite sure how to search for it:
function(){
var sites;
var controller = {
list: function(){
sites = "some value";
}
}
}
So the question is how to access the sites variable from the top defined as
var sites
EDIT:
Here is a more complete part. i am Using marionette.js. i don't want to define the variable attached to the Module (code below) variable but keep it private to the Module, hope that makes sense. Here is the code that works:
Admin.module("Site", function(Module, App, Backbone, Marionette, $, _ ) {
Module.sites = null;
Module.Controller = {
list: function (id) {
Module.sites = App.request("site:entities");
}
};
});
and i would like instead of
Module.sites=null;
to do
var sites;
That sort of thing does make a difference right? Because in the first case i would be defining an accessible variable from outside where as the second case it would be a private one. i am a bit new to javascript so please try to make it simple.
if you are looking for global access, just declare the variable outside the function first, make your changes to the variable inside the function, then you can get the value whenever you need it.
I have found some info on this: sadly what i am trying to do doesn't seem possible.
Can I access a private variable of a Marionette module in a second definition of that module?
So i guess i have to do _variable to make developers know its private.
Disclaimer: I have no experience using Marionette, however, what you're describing sounds very doable.
One of the most powerful (in my opinion) features of JavaScript is closures. What this means is that any function declared from within another function has access to the variables declared in the outer function.
For example:
var func;
function foo() {
var answer = 42;
func = function () {
// I have access to variable answer from in here.
return answer++;
};
}
// By calling foo(), I will assign the function func that has access "answer"
foo();
// Now I can call the func() function and it has access to the "answer"
// variable even though it was in a scope that doesn't exist anymore.
// Outputs:
// 42
// 43
console.log(func());
console.log(func());
What this means is that if you declare var sites from within your module definition function as you described, you should have access to it from within any of your inner anonymous functions. The only exception is if Marionette is re-writing your functions (by using the Function function and toString()), which seems unlikely but possible.
Your original example should would as described, my suspicion is that there is something else going wrong with the code that is unrelated to your scope.

Ajax returned variable issue

I am trying to assign the ajax callback function variable value to the existing variable.
I have
function test(){
}
test.prototype.click=function(){
this.count;
//call ajax codes.....
//ajax callback function
ajax.callback=function(var1){
//I want to assign returned data to this.count property.
this.count=var1.length
}
}
test.prototype.show=function(){
//wont work, it will show undefined...
alert(this.count);
}
var t=new test();
t.click();
t.show();
I think it's the scope issue but I don't know how to solve this. Any idea? Thanks in advance.
Yeah, using this within another scope causes all kinds of issues, so you need to work around this. One way is to avoid using this entirely by defining your function differently. For instance, you can define count like so:
function test() {
function count() {
}
...
And just use count() without the this. prefix.
You can also set a variable to this and use that to refer to count within your other scope. For instance:
var self = this;
Scoping issues with this can be a pain in the neck and can occur when you do more OO with callbacks. It's good you got introduced to this early on, so now you know to be on guard.

Is window.onload considered a global variable can I put it in my module pattern?

I'm refactoring about 600 lines of javascript into the module pattern. Here is a start from previous post:
I undertand the concept of anonymous methods...and sefl-executing....but not the scoping concepts...i.e. what global and window do.
window.onload=initialize_page;
(function (global) {
global['test'] = 'test';
function initialize_page()
{
/* fill here */
}
})(window);
Can I put window.onload=initialize_page into my module pattern? Or does it need to be put outside of it? Can someone explain how the access works?
EDIT 1: per Answer
(function () {
addEventListener('load', initialize_page);
function initialize_page()
{
alert ("hi");
}
})();
It is a global. Don't touch it like that, you'll overwrite any other code that tries to assign load handlers.
Use addEventListener (or attachEvent for old IE) instead. There are plenty of libraries that abstract the functionality.
I'm not an expert, but I think window.onload is a function that gets called, so you reset it to be another function (that you created). You're using it as a macro there. Since initialize_page does not exist when you passed it, it will probably get passed to window.onload as null.

What must an external JavaScript file look like to avoid global variables and methods?

I have the following piece of code on my page:
<script src="/Assets/JavaScripts/myJavaScript.js" type="text/javascript"></script>
<script type="text/javascript">
testAlert();
</script>
And in myJavaScript.js I have the following:
(function () {
function testAlert() {
alert('test alert');
}
})();
It's not calling testAlert. Not sure what I am doing wrong here? I'm trying to avoid global variables and methods. I did something similiar in jQuery and it worked, it just required a $ at the start of the external file. Can somebody please explain what I am doing wrong here and how to make sure I follow best practices?
I put your code in my environment and checked, I got error in mozila error console.
So, Please check it there.
you should put only below javascript function in myjavascript.js file.
function testAlert() {
alert('test alert');
}
Your function in the js-file isn't returning anything. To avoid global variables you could create one global namespace (-like) variable:
var myNS = (function () {
function testAlert() {
alert('test alert');
}
return {testAlert:testAlert};
}());
Now you can use myNS.testalert() in your inline javascript.
JS is made in such a way that you really can't totally avoid globals. (Well, you can, sort of. If you never give anything a name. But that tends to cause more problems than it solves.) When you call testAlert from some other script, you're operating under the assumption that testAlert is global. If it weren't, you couldn't just call it from anywhere like that.
You can minimize the chance of collision, though, by adding your stuff to an object that serves as a namespace, like so:
// don't clear it out if it already exists.
// that way all of your scripts can use your namespace, if you want.
// what you're really trying to protect against, are strangers picking names
// like yours.
if (!window.myNamespace) myNamespace = {};
// example function
myNamespace.testAlert = function() { alert("test alert"); };
myNamespace.testAlert();
This way, the only name that has a good chance of conflicting is myNamespace.
I was going to show an example of a namespaced global...but ya know what? A namespaced global is still a global. Global variables are something you want to try and get rid of in most cases.
You need some sort of global variable so that you can access the method you're looking for. The fact that you have <script>testAlert()</script> means you expect testAlert() to be defined in the global namespace.
What I like to do (especially when using YUI, which you have tagged this question with), is to create a global object that acts as a utility class.
var page = {
init: function() {
// Do some initialization...
},
testAlert: function() {
alert("Test Alert");
}
};
After you do that, you can use the single global "page" variable to access everything you need.
// e.g.
page.testAlert();
// or...
Y.on("domready", page.init, page);
Again, for the second example I'm assuming you're using YUI, since you tagged this question with it.

Categories

Resources