JavaScript combining function parameter with excisting variable - javascript

I am creating a piece of code that repeats for multiple variables and I was wondering if it might be easier to make a function for it, and in the function 'dynamically' adjust the variable that I need to change.
Example: I am creating 31 doors that are either open or closed. So I have:
var door1State = 0;
var door2State = 0;
...
var door31State = 0;
My question is wether it's possible to create a function where I pass the door number as a parameter, like this:
function openDoor(doorNumber) {
door+doorNumber+State = 1;
}
So when I bind a listener to the door, I don't have to write anonymous functions everytime.
I hope my explanation is clear, if not I'm happy to clarify it a bit more.
Thanks in advance!
EDIT: Thanks for all the helpfull replies, I have a next question regarding this issue. I am working with 'Blippar', and they have an API which works fairly easy, but now I need to animate the doors to open. First I've declared the 'sprites' in the 'scene', and next I need to animate the specific parts
deur1.onTouchEnd = function() {
if (door1Openable == 1) {
deur1.animate().rotationY(180).scale(600,360).translation(0,0,95).duration(1000);
deur1text.animate().rotationY(0).scale(600,360).translation(0,0,100).duration(1000);
setTimeout(function(){
door1State = 1;
}, 1500);
} else {
return false;
}
This happens 31 times, for 31 doors. My question is, how would it be easiest to covert this into a function with parameters? The only required parameters are 'door number', 'x position' and 'y position'.
I tried something like this, which obviously didn't work, but I'm having a hard time finding the correct way to do it.
function() openDoor(doorNumber,xPos,yPos) {
if ('door'+doorNumber+'Openable' == 1) {
'deur'+doorNumber.animate().rotationY(180).scale(600,360).translation(xPos,yPos,95).duration(1000);
'deur'+doorNumber+'text'.animate().rotationY(0).scale(600,360).translation(xPos,yPos,100).duration(1000);
setTimeout(function(){
'door'+doorNumber+'Openable' = 1;
}, 1500);
} else {
return false;
}
Again, hopefully it's clear enough, I am basically trying to dynamically use variables within a function by using parameters.
EDIT 2: The API doesn't accept window[] for some reason, it runs in-app.

Try using an array that holds your state
const Doors=[
{
id:1,
isOpen:true,
},
{
id:2,
isOpen:true,
},
{
id:3,
isOpen:false,
}
//..etc
]
this is much easier to handle and manipulate than a huge number of variables.
To open the door you can do something like this :
const OpenDoor=(doorNumber)=>{
Doors.forEach(function(door, index) {
if(door.id===doorNumber)
Doors[index].isOpen = true;
});
}
and then OpenDoor(3);

It's possible, if you change the door#State variables to a single object instead of 31 separate variables. Then, you can just use bracket notation to look up the correct object.:
const doorStates = { door1State: 0, door2State: 0, ... };
function openDoor(doorNumber) {
doorStates['door' + doorNumber + 'state'] = 1;
}
Or, you might consider using an array instead:
// Create an array of length 31, all elements are 0:
const doorStates = Array.from({ length: 31 }, () => 0);
function openDoor(doorNumber) {
// arrays are zero-indexed
doorStates[doorNumber - 1] = 1;
}

You could try to make a dictionary of the doors.
It seems like your usage might merit the use of a dictionary instead of multiple variables.
Here's an example:
list_dict = {};
function(doorname)
{
this.list_dict[doorname] = 0;
}
You might also want to read a bit about maps, here: Javascript Maps

Yes, it's possible.
function openDoor(number) {
window['door'+number+'State'] = 1;
}
for (var i = 1; i <= 31; i++) {
window['door'+i+'State'] = 0;
}
openDoor(2)
console.log(door2State)
You can also use an array for that:
var doors = [
0,0,0,0,0,0,...0 // to 31 0s
];
Then reference door1State using doors[0]

Related

how to work with a large array in javascript [duplicate]

This question already has answers here:
Best way to iterate over an array without blocking the UI
(4 answers)
Closed 6 years ago.
In my application I have a very big array (arround 60k records). Using a for loop I am doing some operations on it as shown below.
var allPoints = [];
for (var i = 0, cLength = this._clusterData.length; i < cLength; i+=1) {
if (allPoints.indexOf(this._clusterData[i].attributes.PropertyAddress) == -1) {
allPoints.push(this._clusterData[i].attributes.PropertyAddress);
this._DistClusterData.push(this._clusterData[i])
}
}
When I run this loop the browser hangs as it is very big & in Firefox is shows popup saying "A script on this page may be busy, or it may have stopped responding. You can stop the script now, or you can continue to see if the script will complete". What can I do so that browser do not hang?
You need to return control back to the browser in order to keep it responsive. That means you need to use setTimeout to end your current processing and schedule it for resumption sometime later. E.g.:
function processData(i) {
var data = clusterData[i];
...
if (i < clusterData.length) {
setTimeout(processData, 0, i + 1);
}
}
processData(0);
This would be the simplest thing to do from where you currently are.
Alternatively, if it fits what you want to do, Web Workers would be a great solution, since they actually shunt the work into a separate thread.
Having said this, what you're currently doing is extremely inefficient. You push values into an array, and consequently keep checking the ever longer array over and over for the values it contains. You should be using object keys for the purpose of de-duplication instead:
var allPoints = {};
// for (...) ...
if (!allPoints[address]) { // you can even omit this entirely
allPoints[address] = true;
}
// later:
allPoints = allPoints.keys();
First of all, avoid the multiple this._clusterData[i] calls. Extract it to a variable like so:
var allPoints = [];
var current;
for (var i = 0, cLength = this._clusterData.length; i < cLength; i+=1) {
current = this._clusterData[i];
if (allPoints.indexOf(current.attributes.PropertyAddress) == -1) {
allPoints.push(current.attributes.PropertyAddress);
this._DistClusterData.push(current)
}
}
This should boost your performance quite a bit :-)
As others already pointed out, you can do this asynchronously, so the browser remains responsive.
It should be noted however that the indexOf operation you do can become very costly. It would be better if you would create a Map keyed by the PropertyAddress value. That will take care of the duplicates.
(function (clusterData, batchSize, done) {
var myMap = new Map();
var i = 0;
(function nextBatch() {
for (data of clusterData.slice(i, i+batchSize)) {
myMap.set(data.attributes.PropertyAddress, data);
}
i += batchSize;
if (i < clusterData.length) {
setTimeout(nextBatch, 0);
} else {
done(myMap);
}
})();
})(this._clusterData, 1000, function (result) {
// All done
this._DistClusterData = result;
// continue here with other stuff you want to do with it.
}.bind(this));
Try considering adding to the array asynchronously with a list, for a set of 1000 records at a time, or for what provides the best performance. This should free up your application while a set of items is added to a list.
Here is some additional information: async and await while adding elements to List<T>

What is the JavaScript equivalent to Ruby's Enumerable#cycle?

In Ruby, there's a method called, Enumerable#cycle, which allows for repeated loops by x number of times in a collection. I'm looking for something similar in JavaScript but could not find an equivalent.
Does anyone know of a JavaScript equivalent to Ruby's, Enumerable#cycle?
Context: I am trying to loop over the same array in JavaScript -- twice. Once iteration reaches the end, I would like the iteration to start from the beginning of the array and eventually stop. The stopping part is not hard -- it's the cycling of the iteration that I'm trying to achieve in JavaScript. I've been able to do this in Ruby, however, with said method.
I think there is nothing inbuilt which is equivalent to this but if you need to you can follow this post for more detail:
Javascript call a function several times with the arguments.
Apart from the options provided there, you could also extend the Array.prototype to enable this method:
Array.prototype.cycle = function (n, callback) {
for (var i = 0; i < n; i++) {
this.forEach(callback);
}
}
and, could use this like following:
a = [1, 2, 3, 4]
a.cycle(2, function (i) { console.log(i); });
// this will print all the values two times
There is no JavaScript built in (or even proposed to my knowledge) that can do this. However, it's not too hard to accomplish yourself.
Let's assume for a minute that your talking about Arrays, and let's waive away discussion about modifying prototypes or not. The simple version of what you want could be:
Array.prototype.cycle = function(cycleCount, callback) {
for(var i = 0; i < cycleCount; i++) {
this = this.map(callback);
}
}
Let's assume you have an array of numbers. Then you could call this by doing:
myNumberArray.cycle(2, function(num, i) {
return num * 2;
});
We could even get fancy, and let you specify a different action for each cycle:
Array.prototype.cycle = function(cycleCount, callback) {
if(Object.prototype.toString.call( callback ) === '[object Array]') {
if(callback.length === cycleCount) {
for(var i = 0; i < cycleCount; i++) {
this = this.map(callback[i]);
}
} else {
// Uhoh, we don't have the right number of callbacks
throw new Error('If using multiple callbacks, the umber of callback\'s must match the number of cycles');
}
} else {
for(var i = 0; i < cycleCount; i++) {
this = this.map(callback);
}
}
}
There is more error checking you would need to do to make that robust, but you get the idea. :)

inovke functions javascript using while

can anyone tell me what is wrong here im just try to invoke this list of functions using array and while if it's possible thanks in advance.
var funciones = ["basicas();", "likeFbk();", "cambiarFondo();"],
i = 0;
while (funciones[i]) {
funciones[i];
i++;
}
jslint show this errors:
91 Expected an assignment or function call and instead saw an expression. funciones[i];
92 Unexpected '++'.
Solved, I use "i += 1;" instead of "i++;" and update the list of functions treated as a string, here is the code:
var funciones = [basicas, likeFbk, cambiarFondo], i = 0;
while (funciones[i]) {
funciones[i]();
i += 1;
}
thank's guys!
try it this way (not sure what you intend to do though, i am guessing you want to iterate unless there is no value at ith index)
var funciones = [basicas, likeFbk, cambiarFondo], i = 0;
while (funciones[i])
{
funciones[i]();
i++;
}
You can't invoke functions like that. The functions array is just a list of strings and not a list of functions. You have two ways of doing this:
Instead of list of strings, use list of functions as below:
var functions = [basicas, likeFbk, cambiarFondo];
while (i in funciones) {
functions[i]();
}
Use eval to evaluate string that contains javascript executable code:
var funciones = ["basicas();", "likeFbk();", "cambiarFondo();"],
i = 0;
while (funciones[i]) {
eval(funciones[i]);
i++;
}
Always go for the first approach, because the second approach is considered as evil.
Or if you prefer
var call = Function.call;
[basicas, likeFbk, cambiarFondo].forEach(call, call);
How this works is left as an exercise.

Simplifying a javascript function with repeated similar lines (with a loop?)

Okay, I hope you don't all facepalm when you see this - I'm still finding my way around javascript.
I am putting together an RSVP form for a wedding website.
I want the guests to be able to add their names to the RSVP form, but only have as many fields showing as required. To this end, after each name field, there is a link to click, which will, when clicked, show a name field for the next guest.
The code below works... but I am sure it can be tidier.
I have tried to insert a for() loop into the code in several different ways, I can see that the for() loop increments correctly to the last value - but when it does so, it leaves only the last addEventListener in place. I can only assume, that I should be using a different kind of loop - or a different approach entirely.
How should I tidy up the following?
<script>
function showNextGuest(i) {
document.getElementsByTagName(\'fieldset\')[i].style.display = \'block\';
}
function initiateShowNextGuest() {
document.getElementsByTagName('fieldset')[0].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(1);},false);
document.getElementsByTagName('fieldset')[1].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(2);},false);
document.getElementsByTagName('fieldset')[2].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(3);},false);
document.getElementsByTagName('fieldset')[3].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(4);},false);
document.getElementsByTagName('fieldset')[4].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(5);},false);
}
window.onload = initiateShowNextGuest();
</script>
Your intuition is right - a for loop could indeed simplify it and so could a query selector:
var fieldsSet = document.querySelectorAll("fieldset"); // get all the field sets
var fieldss = [].slice.call(asSet); // convert the html selection to a JS array.
fields.map(function(field){
return field.querySelector("a"); // get the first link for the field
}).forEach(function(link, i){
// bind the event with the right index.
link.addEventListener("click", showNextGuest.bind(null, i+1), false);
});
This can be shortened to:
var links = document.querySelectorAll("fieldset a:first-of-type");
[].forEach.call(links, function(link, i){
link.addEventListener("click", showNextGuest.bind(null, i+1), false);
});
function nextGuest () {
for(var i = 0; i < 5; i++){
document.getElementsByTagName('fieldset')[i]
.getElementsByTagName('a')[0]
.addEventListener('click',function(){
showNextGuest(parseInt(i + 1));
}, false);
}
}
Benjamin's answer above is the best given, so I have accepted it.
Nevertheless, for the sake of completeness, I wanted to show the (simpler, if less elegant) solution I used in the end, so that future readers can compare and contrast between the code in the question and the code below:
<script>
var initiateShowNextGuest = [];
function showNextGuest(j) {
document.getElementsByTagName('fieldset')[j].style.display = 'block';
}
function initiateShowNextGuestFunction(i) {
return function() {
var j = i + 1;
document.getElementsByTagName('fieldset')[i].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(j);},false);
};
}
function initiateShowNextGuests() {
for (var i = 0; i < 5; i++) {
initiateShowNextGuest[i] = initiateShowNextGuestFunction(i);
initiateShowNextGuest[i]();
}
}
window.onload = initiateShowNextGuests();
</script>
In summary, the function initiateShowNextGuests() loops through (and then executes) initiateShowNextGuestFunction(i) 5 times, setting up the 5 anonymous functions which are manually written out in the code in the original question, while avoiding the closure-loop problem.

JavaScript converting an array to array of functions

Hello I'm working on a problem that requires me to change an set array of numbers into an array that returns the original numbers as a function. So we get a return of a2 instead of a[2].
I dont want the answer I just need a hint. I know i can loop through the array and use .pop() to get the last value of the array, but then I dont know how to convert it to a function from there. any hints?
var numToFun = [1, 2, 3];
var numToFunLength = numToFun.length;
for (var i = 0; i < numToFunLength; i++) {
(function(num){
numToFun.unshift(function() {
return num;
});
}(numToFun.pop()))
}
DEMO
basically it pops out a number from the last, builds a function with that number returned, and put back into the first of the array. after one full cycle, all of them are functions.
here's the catch: how this works, it's up to you to research
why the loop does not look like the straightforward pop-unshift:
for (var i = 0; i < numToFunLength; i++) {
numToFun.unshift(function() { //put into first a function
return numToFun.pop() //that returns a number
});
}
and why i did this: (HINT: performance)
var numToFunLength = numToFun.length;
There's three important steps here:
Extract the number value from the array. Within a loop with an iterator of i, it might look like this:
var num = numArray[i];
This is important, because i will not retain its value that it had when you created the new function - it'll end up with the last value it had, once the for loop is finished. The function itself might look like this:
function() { return num; }
There's no reference to i any more, which is important - to understand better, read about closures. The final step would be to add the new function to the array of functions that you want.
...and you're done!
EDIT: See other's answers for good explanations of how to do this right, I will fix mine also though
As others have pointed out, one of the tricky things in javascript that many struggle with (myself included, obviously) is that scoping variables in javascript is dissimilar to many other languages; scopes are almost purely defined by functions, not the {} blocks of, for example, a for loop, as java/C would be.
So, below you can see (and in other answers here) a scoping function can aid with such a problem.
var numArray = [12, 33, 55];
var funcArray = [];
var numArrLength = numArray.length; // Don't do this in for loop to avoid the check multiple times
for(var j=0; j < numArrLength; j++) {
var scopeMe = function() {
var numToReturn = numArray[j];
console.log('now loading... ' + numToReturn);
var newFunc = function() {
return numToReturn;
};
return newFunc;
}();
funcArray.push(scopeMe);
};
console.log('now me');
console.log(funcArray);
console.log(funcArray[0]());
console.log(funcArray[1]());
console.log(funcArray[2]());
console.log(funcArray[1]()); // To ensure it's repeatable
EDIT my old bad answer below
What you'll want to do is something like
var funcArray = [];
for(...) {
var newFunc = function() {
return numArray.pop();
}
funcArray.push(newFunc);
}
The key here is that functions in javascript can be named variables, and passed around as such :)

Categories

Resources