How to change a variable used as argument for function - javascript

I've looked around a little bit, and I haven't found a clear answer as to why when this proceeding code is ran, it returns myInt as 0. I've read posts about how the variable is only changed inside the function, but from my perspective, I don't see any reason why myInt cannot be changed. For refrence, this is in Javascript.
var myInt = 0;
function changeVar(x) {
x += 1;
}
changeVar(myInt);
console.log(myInt);

The reason myInt is not changing is that x has local scope (anything you do to x only affects the value of x inside of changeVar).
Here's how you could change myInt from changeVar():
var myInt = 0;
function changeVar() {
myInt += 1;
}
changeVar();
console.log(myInt);
If you want to change a variable by passing it as an argument, you should pass an object instead:
var myObject1 = {value: 0}
var myObject2 = {value: 10}
function changeVar(x) {
x['value'] += 1;
}
console.log(myObject1['value']);
console.log(myObject2['value']);
changeVar(myObject1);
console.log(myObject1['value']);
console.log(myObject2['value']);

I will expand on the example given by #N.Kern - here is a better example of how to change the initial variable passed in the function:
var myInt = 0;
function changeVar(x) {
return x += 1;
}
var y = changeVar(myInt);
console.log(y);
Now, the reason for this is offered by #Shekhar Chikara in the comment. Essentially, the value you're passing to the function is modified within the local scope of the function, but it's not actually assigned back (or saved in memory) to the globally declared variable. So when you log the original global variable, you get the unchanged value back. Thus, you want to simply save your functions' returned value to it's own variable.
This will get you started on researching more.
Hope this helps.

Related

Change javascript variable on others script outcome

I need a way where I can change the variable of a jave script function on the outcome of a different function which gets executed on a input click.
Example of the input:
<input type="image" value="74" onclick="WeaponType(this);GetDamage(74);return false;" class="CompactPistol" src=".\Weapons\Bornheim_No_3_Extended.png" alt="Bornheim No.3 Extended">
<span style="color:whitesmoke">Bornheim No. 3 Extended</span>
(I could also change the 'GetDamage' function input to 'this' instead of the value directly and then just change the function output to use the attribute 'value'. In my case it doesn't really matter as the value of one picture is set.)
My script that needs the variable currently looks like this:
<script id="ResultDamage">
function GetDamage(x) {
document.getElementById("DamageDealt").innerHTML = x;
}
</script>
This ofc only outputs the value of the function. But the value needs to be used in a more complicated calculation
What I f.e. also already tried was this:
<script id="ResultDamage">
function GetDamage(x) {
var z
z = x;
return z;
}
var d = z;
document.getElementById("DamageDealt").innerHTML = d;
</script>
and this:
<script id="ResultDamage">
function GetDamage(x) {
return x;
}
var d = GetDamage();
document.getElementById("DamageDealt").innerHTML = d;
</script>
Which gives me 'undefined'
Any help is appreciated.
As I am quite new to this keeping it simple would probably the best (if there is a simple solution)
Based on comments on the question above...
If you just need to store a value globally on the page then you can declare a variable outside of the function and set its value within any function. For example:
var a = 0;
var b = 0;
// etc.
function GetDamage(x) {
a = x;
// perform a calculation as needed
// write a result to the page as needed
}
In this case the values of a and b are stored at the page level and available to other functions, persist their values between function calls, etc. So you can have separate functions that also use those values for their own calculations.

How do I loop through an array of objects and fill the object in the mouseover function?

I'm a first year student I've been scrolling through Stack Overflow and have read a lot about the object problem (reference) but I can't figure out the solution to my problem.
I have made arrays of objects and looping over them to fill a div with all the info like img, name, value, so far no problem here.
The problem is with filling a mouseover function (attached to the image) with the object I'm looping through at the moment, so later when I hover over the image all the info of that particular object is shown on another div.
for (i = 0; i < arrgezelschap.lenght; i++) {
var x = arrgezelschap[i];
var element = document.createElement("img");
element.src = x.artikelFoto + "k.jpg";
element.addEventListener('mouseover', function() {
showinfo(x)
});
inhoud.append(element);
}
In the function showinfo(object) the output is always the last object of the array.
Why is this and what do I need to do so that it saves or points to the object that it's looping through at the moment in my function?
TL;DR: change var x to let x
I can't really do a better job explaining than Creating closures in loops: A common mistake, but I'll take a shot at rephrasing it.
Compare the output of these two snippets (below). The only difference is var vs let. The example demonstrates creating 5 functions in a loop, but does not call them yet. Each function references variables declared inside the loop, outside the loop and in the for itself. Then, at the end of the loop, we call all the functions to see what we got.
In the first case, the variables outside, i (the loop variable) and inside (declared inside the loop) are all declared with var. They are the same variable on every iteration of the loop. The inside var is hoisted to the top of the scope (outside the loop).
When we call all the functions we created, we will see that they all refer to the one-and-only instance of each variable, and they all have the value that the variables have after completion of the loop.
let functions = [];
var outside = 0;
for (var i = 0; i < 5; ++i) {
outside = i * 10;
var inside = i * 100;
functions.push(() => { console.log(outside, i, inside); })
}
functions.map(f => f()); // call all the functions
Output:
40 5 400
40 5 400
40 5 400
40 5 400
40 5 400
In this second example, the variables are all declared with let. The variable i declared in the for and the variable inside declared inside the body of the loop are different variables on each iteration of the loop. But the outside variable is declared outside the loop, so there's still only one outside variable that is used in every iteration of the loop.
When we call all the functions we made this time, we see that each function is displaying a different variable i and inside and their values are the value they held during that particular iteration of the loop, because the variables only existed for that iteration of the loop and the function was bound to the instance of the variable that was used for that iteration. But the outside variable is the same variable every iteration and holds only one value: the value that it has at the end of the loop.
let functions = [];
let outside = 0;
for (let i = 0; i < 5; ++i) {
outside = i * 10;
let inside = i * 100;
functions.push(() => { console.log(outside, i, inside); })
}
functions.map(f => f()); // call all the functions
Output:
40 0 0
40 1 100
40 2 200
40 3 300
40 4 400
In your case, each function binds to the same (one and only) variable x. If you change your declaration of x from var x to let x then you will get a different variable x for each iteration of the loop, and the event listener function will be bound to a different x each time, which will have the value corresponding to that iteration of the loop.
Footnote: Hopefully functions.map(f => f()); is not confusing for you. It just calls all the functions in the array. It is the same as this:
for (var index = 0; index < functions.length; ++index) {
functions[index]();
}
This is because x is a reference here, not a value and it change while you loop. Have a look at this :
let x = 0;
let fcn = a => console.log(a);
function execAnotherFcn(fcn) {
fcn(x);
}
execAnotherFcn(fcn);
x++;
execAnotherFcn(fcn);
You could use the dataset attribute to store your information.
Here's my implementation:
const root = document.querySelector('#root');
function createImagePlaceholder(color, data) {
const el = document.createElement('div');
el.style.width = '50px';
el.style.height = '50px';
el.style.margin = '5px';
el.style.backgroundColor = color;
el.dataset = data;
root.appendChild(el);
el.addEventListener('mouseover', () => {
document.querySelector('pre').innerText = JSON.stringify(data);
});
el.addEventListener('mouseleave', () => {
document.querySelector('pre').innerText = '';
});
}
createImagePlaceholder('red', { text: 'I am a red block' });
createImagePlaceholder('blue', { text: 'I am a blue block' });
<div id="root"></div>
<pre><pre>
You can fix this by making the scope of element block level.
This happens because here the value of x is send as a closure and the var is defined as function level.The event listner function will get executed at a future time(not to the main thread), so at that time the value of x is changed by the loop to the last value.
This can be done using the let key word or using a IIFE.
1.
for (i = 0; i < arrgezelschap.length; i++) {
let x = arrgezelschap[i];
let element = document.createElement("img");
element.src = x.artikelFoto + "k.jpg";
element.addEventListener('mouseover', function() {
showinfo(x)
});
inhoud.append(element);
}
2.
for (i = 0; i < arrgezelschap.lenght; i++) {
var x = arrgezelschap[i];
var element = document.createElement("img");
element.src = x.artikelFoto + "k.jpg";
(function(x){element.addEventListener('mouseover', function() {
showinfo(x)
});})(x);
inhoud.append(element);
}
#PopHips answer explains the theory of what is going wrong. so here is a working example with your code so you can follow it.
for(i =0;i<arrgezelschap.lenght;i++){
var x = arrgezelschap[i];
var element = document.createElement("img");
element.src = x.artikelFoto + "k.jpg";
element.dataset.identifyer = i;
element.addEventListener('mouseover', function(e) {
showinfo(arrgezelschap[e.target.dataset.identifyer])
});
inhoud.append(element);
}
So because we're using an event listener it will give the first param as an EventArgs object, this contains a property called target that is the HTMLElement effected. we can use the dataset (data-) system to save the identifier to the object's dataset so we can use it in the event handler.
Please note this answer should not be used as it is, there is some really bad practice in this answer, NEVER CREATE A FUNCTION INSIDE A LOOP in production code.

Javascript on click event not reading else statement or variables

I'm trying to make a click handler that calls a function; and that function gets a string and basically slices the last character and adds it to the front, and each time you click again it should add the last letter to the front.
It seem so easy at first that I thought I could just do it using array methods.
function scrollString() {
var defaultString = "Learning to Code Javascript Rocks!";
var clickCount = 0;
if (clickCount === 0) {
var stringArray = defaultString.split("");
var lastChar = stringArray.pop();
stringArray.unshift(lastChar);
var newString = stringArray.join('');
clickCount++;
} else {
var newArray = newString.split("");
var newLastChar = newArray.pop();
newArray.unshift(newLastChar);
var newerString = newArray.join("");
clickCount++;
}
document.getElementById('Result').innerHTML = (clickCount === 1) ? newString : newerString;
}
$('#button').on('click', scrollString);
Right now it only works the first time I click, and developer tools says newArray is undefined; also the clickCount stops incrementing. I do not know if it's an issue of scope, or should I take a whole different approach to the problem?
Every time you click you are actually reseting the string. Check the scope!
var str = "Learning to Code Javascript Rocks!";
var button = document.getElementById("button");
var output = document.getElementById("output");
output.innerHTML = str;
button.addEventListener("click", function(e){
str = str.charAt(str.length - 1) + str.substring(0, str.length - 1);
output.innerHTML = str;
});
button{
display: block;
margin: 25px 0;
}
<button id="button">Click Me!</button>
<label id="output"></label>
It is, in fact, a scoping issue. Your counter in inside the function, so each time the function is called, it gets set to 0. If you want a counter that is outside of the scope, and actually keeps a proper count, you will need to abstract it from the function.
If you want to keep it simple, even just moving clickCount above the function should work.
I do not know if it's an issue of scope
Yes, it is an issue of scope, more than one actually.
How?
As pointed out by #thesublimeobject, the counter is inside the function and hence gets reinitialized every time a click event occurs.
Even if you put the counter outside the function, you will still face another scope issue. In the else part of the function, you are manipulation a variable (newString) you initialized inside the if snippet. Since, the if snippet didn't run this time, it will throw the error undefined. (again a scope issue)
A fine approach would be:
take the counter and the defaultString outside the function. If the defaultString gets a value dynamically rather than what you showed in your code, extract its value on page load or any other event like change, etc. rather than passing it inside the function.
Do not assign a new string the result of your manipulation. Instead, assign it to defaultString. This way you probably won't need an if-else loop and a newLastChar to take care of newer results.
Manipulate the assignment to the element accordingly.
You can use Javascript closure functionality.
var scrollString = (function() {
var defaultString = "Learning to Code Javascript Rocks!";
return function() {
// convert the string into array, so that you can use the splice method
defaultString = defaultString.split('');
// get last element
var lastElm = defaultString.splice(defaultString.length - 1, defaultString.length)[0];
// insert last element at start
defaultString.splice(0, 0, lastElm);
// again join the string to make it string
defaultString = defaultString.join('');
document.getElementById('Result').innerHTML = defaultString;
return defaultString;
}
})();
Using this you don't need to declare any variable globally, or any counter element.
To understand Javascript Closures, please refer this:
http://www.w3schools.com/js/js_function_closures.asp

String variable prefixed with undefined in for loop

I have a drop-down on which i use .Change() to trigger a function. Function basically get certain data using getJSON and based on those value in have to create string of array for mp3 file.
Below code is generating string but always prefix undefined to string.
In code you will notice setTimeout which is just to provide certain delay till data received. In below example i am using static value and it still prefix undefined. not sure why may be i have defined variable in wrong manner.
Complete example JSBin
$('.customSurah').change(function(){
//surahNo = $('#surah option:selected').val();
setTimeout(function(){
//countSpan = $('#surah-wrapper').children().length;
surahNo = 1;
countSpan = 7;
var i=0;
for (i = 0; i <= countSpan; i++) {
strCat += surahNo+"/"+i+".mp3,";
console.log(strCat);
}
}, 3000);
});
OUTPUT
undefined114/0.mp3,
undefined114/0.mp3,114/1.mp3,
undefined114/0.mp3,114/1.mp3,114/2.mp3,
undefined114/0.mp3,114/1.mp3,114/2.mp3,114/3.mp3,
undefined114/0.mp3,114/1.mp3,114/2.mp3,114/3.mp3,114/4.mp3,
undefined114/0.mp3,114/1.mp3,114/2.mp3,114/3.mp3,114/4.mp3,114/5.mp3,
undefined114/0.mp3,114/1.mp3,114/2.mp3,114/3.mp3,114/4.mp3,114/5.mp3,114/6.mp3,
You have a variable strCat that is not initialized, and then you append a value to it in this line:
strCat += surahNo+"/"+i+".mp3,";
Since strCat is not initialized in first round of loop, you get undefined prepended to your string.
To fix this, you need to initialize the variable to empty value first:
var strCat = ''; // <- initialize your variable to empty value
surahNo = 1;
countSpan = 7;
The outcome is perfectly valid as per javascript is concerned.
Why?
I guess you probably know if you declare any variable in javascript and you don't assign its default value then automatically undefined is assigned. So, that is a valid. What happens when you do that:
var somevar; // non assigned default value set to -> undefined
console.log(somevar); // logs undefined
But,
In your case you have to give it a default value like a blank string var strCat "";. So, now when you do this:
var somevar = ""; // assigned default value to set to -> ""
console.log(somevar); // logs ""
So, the solution to your issue is, you have to initialize/assign a default value to your variable. like:
var strCat = "";

Is it possible to assign a variable with a function? [duplicate]

I’ve looked for solutions, but couldn’t find any that work.
I have a variable called onlyVideo.
"onlyVideo" the string gets passed into a function. I want to set the variable onlyVideo inside the function as something. How can I do that?
(There are a number of variables that could be called into the function, so I need it to work dynamically, not hard coded if statements.)
Edit: There’s probably a better way of doing what you’re attempting to do. I asked this early on in my JavaScript adventure. Check out how JavaScript objects work.
A simple intro:
// create JavaScript object
var obj = { "key1": 1 };
// assign - set "key2" to 2
obj.key2 = 2;
// read values
obj.key1 === 1;
obj.key2 === 2;
// read values with a string, same result as above
// but works with special characters and spaces
// and of course variables
obj["key1"] === 1;
obj["key2"] === 2;
// read with a variable
var key1Str = "key1";
obj[key1Str] === 1;
If it's a global variable then window[variableName]
or in your case window["onlyVideo"] should do the trick.
Javascript has an eval() function for such occasions:
function (varString) {
var myVar = eval(varString);
// .....
}
Edit: Sorry, I think I skimmed the question too quickly. This will only get you the variable, to set it you need
function SetTo5(varString) {
var newValue = 5;
eval(varString + " = " + newValue);
}
or if using a string:
function SetToString(varString) {
var newValue = "string";
eval(varString + " = " + "'" + newValue + "'");
}
But I imagine there is a more appropriate way to accomplish what you're looking for? I don't think eval() is something you really want to use unless there's a great reason for it. eval()
As far as eval vs. global variable solutions...
I think there are advantages to each but this is really a false dichotomy.
If you are paranoid of the global namespace just create a temporary namespace & use the same technique.
var tempNamespace = {};
var myString = "myVarProperty";
tempNamespace[myString] = 5;
Pretty sure you could then access as tempNamespace.myVarProperty (now 5), avoiding using window for storage. (The string could also be put directly into the brackets)
var myString = "echoHello";
window[myString] = function() {
alert("Hello!");
}
echoHello();
Say no to the evil eval. Example here: https://jsfiddle.net/Shaz/WmA8t/
You can do like this
var name = "foo";
var value = "Hello foos";
eval("var "+name+" = '"+value+"';");
alert(foo);
You can access the window object as an associative array and set it that way
window["onlyVideo"] = "TEST";
document.write(onlyVideo);
The window['variableName'] method ONLY works if the variable is defined in the global scope. The correct answer is "Refactor". If you can provide an "Object" context then a possible general solution exists, but there are some variables which no global function could resolve based on the scope of the variable.
(function(){
var findMe = 'no way';
})();
If you're trying to access the property of an object, you have to start with the scope of window and go through each property of the object until you get to the one you want. Assuming that a.b.c has been defined somewhere else in the script, you can use the following:
var values = window;
var str = 'a.b.c'.values.split('.');
for(var i=0; i < str.length; i++)
values = values[str[i]];
This will work for getting the property of any object, no matter how deep it is.
It can be done like this
(function(X, Y) {
// X is the local name of the 'class'
// Doo is default value if param X is empty
var X = (typeof X == 'string') ? X: 'Doo';
var Y = (typeof Y == 'string') ? Y: 'doo';
// this refers to the local X defined above
this[X] = function(doo) {
// object variable
this.doo = doo || 'doo it';
}
// prototypal inheritance for methods
// defined by another
this[X].prototype[Y] = function() {
return this.doo || 'doo';
};
// make X global
window[X] = this[X];
}('Dooa', 'dooa')); // give the names here
// test
doo = new Dooa('abc');
doo2 = new Dooa('def');
console.log(doo.dooa());
console.log(doo2.dooa());
The following code makes it easy to refer to each of your DIVs and other HTML elements in JavaScript. This code should be included just before the tag, so that all of the HTML elements have been seen. It should be followed by your JavaScript code.
// For each element with an id (example: 'MyDIV') in the body, create a variable
// for easy reference. An example is below.
var D=document;
var id={}; // All ID elements
var els=document.body.getElementsByTagName('*');
for (var i = 0; i < els.length; i++)
{
thisid = els[i].id;
if (!thisid)
continue;
val=D.getElementById(thisid);
id[thisid]=val;
}
// Usage:
id.MyDIV.innerHTML="hello";
let me make it more clear
function changeStringToVariable(variable, value){
window[variable]=value
}
changeStringToVariable("name", "john doe");
console.log(name);
//this outputs: john doe
let file="newFile";
changeStringToVariable(file, "text file");
console.log(newFile);
//this outputs: text file

Categories

Resources