Set a global variables and use them in function (javascript) - javascript

I am new to programming and I am stuck. Here is my code:
function Subtraction() {
var a = document.getElementById('inputA').value;
var b = document.getElementById('inputB').value;
var c = (parseFloat(a) - parseFloat(b)).toFixed(5);
alert(c);
}
This works fine to me, but I have many functions that waits for onclick event to be executed. And every function have the same a and b variables. How can I get them in global scope so I don't need to wait them over and over again? I tried to put them outside of the function, but what event can trigger their declaration? There is what I tried:
var a = document.getElementById('inputA').value;
var b = document.getElementById('inputB').value;
parseFloat(a).toFixed(5);
parseFloat(b).toFixed(5);
function Subtraction() {
var c = a - b;
alert(c);
}

I see two options at least:
One is to declare them after window has loaded.
Other is to pass the elements as function parameters:
1
var a,b;
window.onload = function(){
a = document.getElementById('inputA').value;
b = document.getElementById('inputB').value;
}
2
element.onclick = function(){
var a = document.getElementById('inputA').value;
var b = document.getElementById('inputB').value;
Subtraction(a, b);
};
Btw, capital letters is used for Classes, if its a normal function better to use small "s".

You can try to declare the vars in a different javascript source file or put them in an upper block the environment of the variables holds through the entire execution from the moment you declare them so if you do this:
<script src="declare_vars.js"></script>
<script src="use_vars.js"></script>
In declare_vars.js you can try doing:
var a;
var b;
and in the other scripts use them as you want and give them the values you need, they will always be available.

The value of an input is a primitive (specifically a string) and is therefore passed by value. This means that if you do this:
var oldvalue = document.getElementById('someinput').value;
document.getElementById('someinput').value = "derp";
alert(oldvalue); // it has not changed
What you can do, if you want, is cache the result of getElementById:
var inputA = document.getElementById('inputA');
var inputB = document.getElementById('inputB');
// in your function {
var c = parseFloat(inputA.value)-parseFloat(inputB.value);
// }
This works because the result of getElementById is the input element itself. You then retrieve the desired property of this element (.value) at the specific time you need it.
That said, avoid global variables. Put variables in a scope if you want, but don't make them global.

Disclaimer: this solution makes no attempt to avoid using global variables. The usage of global variables may introduce all sorts of problems, though for an application as simple as the one described by the OP the potential pitfalls are limited.
You can add the initialization in the change event handler of each input to make sure it is always up to date:
HTML
a<input id="inputA"/>
b<input id="inputB"/>
<button id="sum">sum</button>
JAVASCRIPT
var a,b;
document.getElementById('inputA').addEventListener('change',function(evt){
a = +evt.target.value;
});
document.getElementById('inputB').addEventListener('change',function(evt){
b = +evt.target.value;
});
document.getElementById('sum').addEventListener('click', function(evt){
console.log('Sum is ' + (a+b));
});
DEMO: http://jsbin.com/EZECEraR/2/edit

Related

JavaScript shadowing with initialization

Before I dive into the question I want to clarify that my use case involves patching a trans-compiler to generate a proper equivalent, hence the somewhat awkward question.
I want to shadow an outside variable but initialize it to the same value as outside as well. Here is an example:
var a = 2;
(function(){
var a = a;
a += 3;
// I want `a` to be 5
})();
// I want `a` to be 2
I realize with the above example the internal a will be NaN (undefined + 3), but can I initialize the variable doing the shadowing to the same one that it shadows somehow? Passing it as an argument is not an option as that function will be written by the user, the only thing that will be consistent is the presence of inner scope. I was thinking of changing the name of internal variable a but the compiler isn't currently built in a way to track it easily and this would introduce additional headaches.
You need to pass a as parameter in your IIFE.
(function(parameter){
// «parameter» contains the given value.
// parameter = "Some value".
})("Some value");
Something like this:
var a = 2; // Variable declaration in the global scope.
(function(a) {
a += 3;
// I want `a` to be 5
console.log(a); // Prints the current value in the local scope.
})(a); // The parameter: var a = 2;
console.info(a); // Prints the current value in the global scope.
// I want `a` to be 2
Since that is a immediately invoked function expression it has a completely different scope than the code written outside of it. There's no way to do what you are asking without passing in an argument in some way (whether directly when executing or using bind), or changing the function so the scope is that of the scope where the wanted var a is defined.
With that being said perhaps you can return some methods that will set a to the appropriate value.
http://jsbin.com/vazequhigo/edit?js,console
var a = 2;
w = (function(){
var setA = function(val) {
a = val;
}
var addA = function(val) {
a += val;
return a;
}
var a = 0;
return {
setA: setA,
addA: addA,
};
})();
w.setA(a);
console.log(w.addA(3));

Create a class in Javascript that can access local variables

I'm working on a debugger that injects code into already existing code. Which then use eval() to log and run it.
However eval() seems to work in only its existing scope. To overcome this I tried to add a class that i recreated in each local scope. But it doesnt work.
I've added code to ilustrate my problem. The first alert works as expected, I'm assuming that it is because MyClass is created in the same scope.
The second alert still display b as 10 even though I've set b in local scope to 20 inside the TestC function. And the last alert doesn't work at all eval() returns in console "Uncaught ReferenceError: c is not defined".
If I add the whole MyClass inside each function and the assign it, then it works, but that doesn't feel like an elegant solution. And can add 1000's of lines of code to a project.
http://jsfiddle.net/ekim/zryj3taq/2/
var MyClass = function()
{
this.MyAlert = function(codex)
{
eval(codex);
}
}
var b = 10;
var MyOne = new MyClass();
MyOne.MyAlert("alert(b);");
function TestC()
{
var b = 20;
var MyOne2 = new MyClass();
MyOne2.MyAlert("alert(b);");
var c = 20;
var MyOne2 = new MyClass();
MyOne2.MyAlert("alert(c);");
}
TestC();
You can use new Function(\[arg1\[, arg2\[, ...argN\]\],\] functionBody)
(function(){
var str = "return (A+B)*C";
var myFunc = new Function("A","B","C", str);
var result = myFunc(2,3,4);
console.log(result);
}());
/* Example with function */
(function(){
var fncDouble = function (X) {
return X*2;
}
var str = "return F(A)+B";
var myFunc = new Function("F","A","B", str);
var result = myFunc(fncDouble,3,1);
console.log(result);
}());
As far as I know, there is no easy solution to this, as the eval() function just creates a new, separate compiler.
Try this: MyOne2.MyAlert.call(this, "alert(b)");

What is the best way to delete an object in JavaScript?

In JavaScript, I have complex objects comprising functions, variables and closures.
These objects are very large, very complex and created and destroyed over and over again. I will be working on a very low-powered, very low-memory device, so it's important to me that when the objects are deleted that they are really gone.
Here's a code example:
window["obj"] = {};
obj.fun1 = function(){
console.log(1);
};
(function(){
var n = 2;
function fun(){
console.log(n);
}
obj.fun2 = fun;
})();
(function(){
var w = "Three";
function fun(){
console.log(w);
}
obj.fun3 = fun;
})();
(function(){
var w = "f.o.u.r.";
function fun(){
setInterval(function(){
console.log(w);
}, 1e3); // e.g. a timeout
}
obj.fun4 = fun;
})();
obj.fun1();
obj.fun2();
obj.fun3();
obj.fun4();
var fun2 = obj.fun2;
// window.obj = null;
// window.obj = undefined;
delete window.obj;
console.log(typeof obj); // undefined
A secondary issue is the question of "lingering references", such as the following:
fun2(); // 2
// Interval: "f.o.u.r.", "f.o.u.r.", "f.o.u.r.", "f.o.u.r." ...
Is there anything that can be done about those (except a manual clean up before deleting the object)?
A JSFiddle of the code above is here: http://jsfiddle.net/8nE2f/
You will have the best effect by doing this
window.obj = null;
delete window.obj;
Setting objects to null removes any references to it. Also remember that the delete command has no effect on regular variables, only properties.
To better ensure object destruction you may consider not using the global context at all, that is usually considered as an antipattern.
The only way to get rid of an object is for JavaScript to garbage-collect it, so making sure there really aren't any references to the object left and praying is the only way to go.
If you're repeatedly creating and destroying the same object, consider using an object pool.

JS function to return function, shares data which should be private

I'm trying to create a function which returns another function. I want separate information when each of the inner function is run, but this isn't happening. I know that explanation is not great, so I've put together a small example.
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return that;
})(testVal);
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());
This outputs 2, 2. What I would like is 2, 4 to be output. I know this isn't explained perfectly, so if it's not clear what I'm trying to achieve, can someone explain why the variable seems to be shared across the two functions?
Thanks
Like this ?
var testFn = function(testVal) {
var test = testVal
return {
getVal: function() {
return test
}
}
};
var ab = testFn (4)
var ac = testFn (2)
console.log(ab.getVal(),ac.getVal()) //4 //2
The problem in your code is this.getVal() / returning this
because 'this' refers to the global scope / Window
You are glubbering with the global namespace and overwriting Window.getVal() , the moment you are setting b = testFn (2)
This results in overwriting as method getVal too because they both refer to the global Object and always share the same method getVal
Therefore they share the same closure and are outputing 2
console.log("The same: " + (Window.a === Window.b)) // true
console.log("The same: " + (a === b)) // true
you can see that if you change it a little:
var testFn = function(testVal) {
var x = {}
return (function(testVal) {
var test = testVal;
x.getVal = function () {
return test;
}
return x
})(testVal);
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());//4 2
it suddenly works because it results in 2 different Objects returned (btw you don't even need the outer closure)
console.log("The same: " + (a === b)) // false
Here are the JSbins First / Second
I hope you understand this, I'm not good in explaining things
If theres anything left unclear, post a comment and I'll try to update the answer
This question comes down to the context in which functions are invoked in JavaScript.
A function that is invoked within another function is executed in the context of the global scope.
In your example, where you have this code:
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return this;
})(testVal);
}
The inner function is being called on the global scope, so this refers to the global object. In JavaScript a function executed within another function is done so with its scope set to the global scope, not the scope of the function it exists within. This tends to trip developers up a fair bit (or at least, it does me!).
For argument's sake, lets presume this is in a browser, so hence this refers to the window object. This is why you get 2 logged twice, because the second time this runs, this.getVal overwrites the getVal method that was defined when you ran var a = testFn(4);.
JavaScript scopes at function level, so every function has its own scope:
var x = 3;
function foo() {
var x = 2;
console.log(x);
};
console.log(x); //gives us 3
foo(); // logs 2
So what you want to do is run that inner function in the context of the testFn function, not in the global scope. You can run a function with a specific context using the call method. I also recorded a screencast on call and apply which discusses this in greater detail. The basic usage of call is:
function foo() {...}.call(this);
That executes foo in the context of this. So, the first step is to make sure your inner function is called in the right context, the context of the testFn method.
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return this;
}.call(this, testVal);
}
The first parameter to call is the context, and any arguments following that are passed to the function as parameters. So now the inner function is being called in the right scope, it wont add getVal to the global scope, which is a step in the right direction :)
Next though you also need to make sure that every time you call testFn, you do so in a new scope, so you're not overwriting this.getVal when you call testFn for the second time. You can do this using the new keyword. This SO post on the new keyword is well worth reading. When you do var foo = new testFn() you create and execute a new instance of testFN, hereby creating a new scope. This SO question is also relevant.
All you now need to do is change your declaration of a and b to:
var a = new testFn(4);
var b = new testFn(2);
And now console.log(b.getVal(), a.getVal()); will give 2, 4 as desired.
I put a working example on JSBin which should help clear things up. Note how this example defines this.x globally and within the function, and see which ones get logged. Have a play with this and hopefully it might be of use.
The output you get is (2,2) because when you do
var that = this;
what you actually get is the global object (window),
the object that holds all the global methods and variables in your javascript code.
(Note that every variable that is not nested under an object or function is global and
every function that is not nested under an object is global, meaning that functions that are nested under a function are still global)
so, when you set:
var test = testVal;
this.getVal = function() {
return test;
}
you actually set the function "getVal" in the global object, and in the next run you will again set the same function - overriding the first.
To achieve the affect you wanted I would suggest creating and object and returning it in the inner function (as #Glutamat suggested before me):
var testFn = function(testVal) {
return new Object({
getVal: function() {
return testVal;
}
});
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());
In this way, in the outer function we create an object with an inner function called "getVal" that returns the variable passed to the outer function (testVal).
Here's a JSBin if you want to play around with it
(thanks to #Glutamat for introducing this site, I never heard of it and it's really cool :D)

Javascript: Change value of variable inside conditional inside function

I'm trying to reuse a complicated function, and it would work perfectly if I could change the value of a local variable that's inside a conditional inside that function.
To boil it down:
var func = complicated_function() {
// lots of code
if (something) {
var localvar = 35;
}
// lots of code
}
I need localvar to be some other number.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Update: The answer is yes! See my response below.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Nope.
No, but it is possible to assign it conditionally so that the function signature (basically, the required input and output) does not change. Add a parameter and have it default to its current value:
var func = complicated_function(myLocalVar) {
// lots of code
if (something) {
// if myLocalVar has not been set, use 35.
// if it has been set, use that value
var localvar = (myLocalVar === undefined)?35:myLocalVar;
}
// lots of code
}
No.
Without changing the complicated function there is no way, in javascript you can manipilate this by using call and apply. You can override functions in the complicated function or add new if this is an option (but they won't be able to access the local variable localvar).
this is more for fun my real answer is still no.
If you are feeling crazy :)
var complicatedFunction = function() {
var i = 10;
var internalStuff = function() {
console.log(i); // 10 or 12?
};
return internalStuff();
};
var complicatedFunction;
eval("complicatedFunction = " + complicatedFunction.toString().replace(/i = 10/, 'i = 12'));
complicatedFunction(); //# => 12
If the function uses this.localvar:
var func = function() {
alert(this.localvar)
if (true) {
var localvar = 35;
}
// lots of code
alert(this.localvar)
}
var obj = {localvar: 10};
func.call(obj); // alerts 10 twice
If not, then you can't change it without changing the function.
In javascript variables are "pushed" to the top of their function. Variables in javascript have function scope, not "curly brace" scope like C, C++, Java, and C#.
This is the same code with you (the developer) manually pushing it to the top:
var func = complicated_function() {
var localvar = 0;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
}
Does declaring the variable "up" one function help you out? At least the declaration is isolated.
function whatever() {
var localvar = 0;
var func = function() {
var something = true;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
};
func();
alert(localvar);
}
whatever();
Here is the jsFiddle: http://jsfiddle.net/Gjjqx/
See Crockford:
http://javascript.crockford.com/code.html
JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.
I asked this question about three weeks ago and within a half hour got five answers that all basically told me it wasn't possible.
But I'm pleased to announce that the answer is YES, it can be done!
Here's how:
var newfunc = func.toString().replace('35', '42');
eval('newfunc = ' + newfunc);
newfunc();
Of course, it uses eval, which probably means that it's evil, or at least very inadvisable, but in this particular case, it works.

Categories

Resources