While I was searching for a good way to check if a function variable is an array or a single variable and then turn both into arrays for further processing, I came across this post.
The answer provided by #VoteyDisciple
var eventsArray = events ? [].concat(events) : [];
works great for me until events is a single variable with a value of zero. In that case, eventsArray will be empty. Here is my entire code:
var eventsArray = [];
if (!(Array.isArray(events))) {
eventsArray = events ? [].concat(events) : [];
} else {
eventsArray = events;
}
I have tried to make another if-statement before the else line to catch this special occasion. But that ends up in a mess for the rest of the code and I doubt it's very elegant. Therefore I wonder if it is possible to change this line:
eventsArray = events ? [].concat(events) : [];
in a way so that if events is a single variable with a value of zero, this line will also turn this occasion into an array with a single element and a value of zero?
For understanding things better, I also want to ask: Why does this line of code "lose" the zero but works great with any other single value?
It's much simpler:
eventsArray = Array.isArray(events) ? events : [events];
The reason you lose the zero is because zero is falsey in a boolean context like the conditional operator. You'll also lose null and empty strings.
Trouble finding the reason why JavaScript for loop is not executing. Wrote 2 simple functions below that I want to execute and run i.e.: Bought method should try to "simulate" synchronous code.
The problem is that for some reason the for loop in the addNodes() method is never executed. However, if I run this separately i.e. for example line by line
var result = [];
var addressBookNodes = await generateAddressBooksNodes();
addNodes(result, addressBookNodes);
that tells me that the code is running fine however most likely it has something to do with the asynchronous nature of the generateAddressBooksNodes method. If I simply run the command :
var addressBookNodes = await generateAddressBooksNodes();
in the browser, I get an array of objects exactly what I was expecting to get. Basically the generateAddressBooksNodes returns a promise and when that promise is resolved I can see the correct array returned however what I do not understand why the for loop is not executed if the nodes objects have at least one element as shown in the picture below.
function addNodes(result, nodes){
console.log("3");
console.log(nodes);
for (var num in nodes) {
console.log("4");
let singleNode = nodes[num];
console.log(singleNode);
console.log("5");
result.push(singleNode);
}
}
async function getAddressBookAndContactNodes() {
var result = [];
console.log("1");
var addressBookNodesPromise = generateAddressBooksNodes();
addressBookNodesPromise.then( (arrayOfAddressBookNodes) => {
console.log("2");
addNodes(result, arrayOfAddressBookNodes);
})
return result;
}
Update 26 August 2020 :
After poking around the "arrayOfAddressBookNodes" object i noticed something really strange. I added additional print statement and printed the length of the "arrayOfAddressBookNodes" array. The length of the array is 0 when runned in the function. I do not understand how the length can be 0 if the object is printed shortly before the for loop and as shown on the picture below the length there is :1. What the hell is going on here?
I found another article i.e. JavaScript Array.length returning 0 that is basically explaining this. And in one of the commends it has been mentioned to use Map instead of an Array. I decided to use Set, and still get the same error i.e. the size of the set is 0 although the Set contains an object. i.e. below is the code and the picture of that execution.
async function getAddressBookAndContactNodes() {
var result = new Set();
console.log("1");
var addressBookNodes = await generateAddressBooksNodes();
console.log("2");
console.log(addressBookNodes);
console.log("3");
console.log("addressBookNodes size : " + addressBookNodes.size);
addressBookNodes.forEach(function(value) {
result.add(value);
});
console.log("6");
console.log(result);
console.log("7");
return result;
}
example using set
all this is really confusing to someone having a c++ backgroud, it makes my head explode.
Update 2 : 26 August 2020.
Ok i solved my problem. The problem was that the the promises are not working withing the for loop everything is explained here.
i need to use the regular "for (index = 0; index < contactsArray.length; ++index) " instead of foreach. after that it all worked. Somehow this leaves the impression that the tools of the language are broken in so many ways.
If generateAddressBooksNodes is returning a promise, you can use async to wait for the results:
async function getAddressBookAndContactNodes() {
var result = [];
console.log("1");
var addressBookNodesPromise = await generateAddressBooksNodes();
// note await here. Also, unless you're using this at a later time in your code, you can save space by not assigning it to a variable and simply returning generateAddressBooksNodes
addNodes(result, arrayOfAddressBookNodes);
return result;
}
Is there a better way of doing the following. I have a JSON array that gets passed in a javascript object, the object doesn't have key value pairs so i need to manual set each point in the array and bind it to a variable.
While the example bellow is only 1 item there are 80+ that need to be set.
If i try to put in item[key][2][1] as a peramiter for a function the code fails as it trys to access the array before passing off to the try catch function. Also all the try catch's happen within a loop that can run up to 200 times per page load.
The below works for everything, but when dealing with i.e 8 or below it begins to bottleneck fast. I have also isolated that it is this checking function that bottlenecks and not other parts of the code.
var someArr = "";
for(i=0;i<data.length;i++){
var item = data[i];
for(key in item){
try{someArr = item[key][2][1]}
catch(err){}
final{someArr = checkData(someArr)}
}
}
function checkData(value){
if(!value){value = "";}
return value;
}
You could exchange your try catch block with a check if the parts of variable are set.
if (item && item[key] && item[key][2]) {
someArr = item[key][2][1];
}
So I have a fairly good amount of experience in coding. I've dabbled in Basic, HTML, Javascript, C, and C++, though the ones I've been using most recently are HTML and Javascript.
I am incredibly familiar with the for-loop. I've used it many times to loop through arrays, to operate recursive functions, etc. I know what it does and how to use it, but my question is about how it works.
Premise
In most languages, the basic syntax of a for loop is such:
var upperLimit = 10;
for(var i = 0; i < upperLimit; i++) {
/*Code to be executed*/
console.log(i);
}
In Javascript, this will output the numbers from 0 to 9 in the console.
I know that the parentheses contains 3 parts, each separated by semicolons.
The first is the initialization, which typically sets up the variables to be used to loop the statements.
The second is the condition, which runs before any of the code between the curly braces is executed. If it results in a True, the code is executed. Otherwise, the for-loop stops.
The third is the increment, which contains the last bit of code to be executed in the loop, and, by extension, the last thing executed before the next condition check.
Question
So, again, my question is how strict are these definitions?
The initialization's definition doesn't allow for much. It just says that that line is executed once, it's executed before anything else in the loop, and it's scope is limited to the loop. I can't think of much else you'd want to put in that position other than an iterative variable.
But what about the other two? I've seen codes where the condition is simply a variable, and as long as it's positive (since positive numbers taken as a boolean just covert to true), the loop continues.
Then there's the increment, which seems to be the loosest of these parts. Is it really just the last thing to be executed in a code, or does it explicitly need to iterate the variable declared in the initialization? It seems to be the former for the languages I'm familiar with.
For example, I decided to make a non-standard for-loop, and I came up with this routine:
var numbers = [0,1,2,3,4,5,6,7,8,9];
for(var i = 0;
numbers.length;
console.log(numbers.pop())) {}
It runs exactly as I expected: It outputs each member of the numbers array in the console in descending order, leaving an empty numbers array afterwards, and it's done using what is basically an empty for-loop.
Ending
So are my assumptions correct? If so, are there any practical applications for using a for-loop in a format apart from the one I wrote at the top of this question (possibly closer to he second format)?
Before all, you give a array
var numbers = [0,1,2,3,4,5,6,7,8,9];
The codes below is a correct for loop.
for(var i = 0;
numbers.length;
console.log(numbers.pop())) {}
Javascript defined for like this
for ([initialization]; [condition]; [final-expression])
statement
For you code initialization is 'var i = 0', and execute once at start of loop.
The condition is 'numbers.length', and value is 10. When a number not 0, Javascript will convert it to boolean true. So condition is true.
The final-expression is 'console.log(numbers.pop())'. When execute 'numbers.pop()', numbers.length change to 9. But it still is true.
At second time, condition will return true again. The final-expression is execute too.
Until numbers.length become 0, Javascript convert it to boolean false. The loop will end.
The scope of the initialized variable is not limited to the loop, it's valid for the whole function (undefined before that line). You can initialize multiple variables using a comma. for (var i=0, j=1; i < 10; i++)
The second part, anything that evaluates to a truthy value will cause the loop to keep going:
Truthy: 1, -1, true, "something", {a: 2}
Falsey: 0, false, null, undefined
You could omit this and rely on a break in your code
The third part just lets you update the looping variable, you could omit it and do it within the for loop body.
Here's an answer that provides a nice way to loop that is non-standard, and comes with caveats, please see the link.
var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];
for (var i=0, item; item = list[i]; i++) {
// Look no need to do list[i] in the body of the loop
console.log("Looping: index ", i, "item" + item);
}
In most languages, the basic syntax of a for loop is such:
for(initialization; condition; iteration) {
/*Code to be executed*/
}
Both three are usual expressions and you can use any valid expressions here:
for(
var i=arr.length, othercond=true;
i;
othercond?i--:i++, console.log(i),updateothercond()
);
As javascript developers we all have to write a lot of for loops. Before a couple of months I saw an alternative syntax, which I really liked. However, I'm now interested, is there any other nice way.
Let's say that I have an array of data representing users in a system. What I did before is:
var users = [
{ name: "A"},
{ name: "B"},
{ name: "C"},
{ name: "D"},
{ name: "E"}
];
var numOfUsers = users.length;
for(var i=0; i<numOfUsers; i++) {
var user = users[i];
// ...
}
There is one additional row var user = users[i];. Normally I feel more comfortable if I have user instead of users[i]. So, the new way:
for(var i=0; user=users[i]; i++) {
// ...
}
I'm also wondering if the second approach produces problems in some of the browsers. One of my colleagues reported that this syntax is a little bit buggy under IE.
Edit:
Thankfully, the answers below pointed me out to the right direction. If some of the elements of the array is falsy then the loop will stop. There is some kind of solution:
for(var i=0; typeof (user=users[i]) !== "undefined"; i++) {
// ...
}
But that's too much for me. So, I guess that I'll use this syntax only when I'm 100% sure that all the elements are truly (which means never :)).
In your “new” approach, you don’t need numOfUsers any more.
As for the potential problems: This approach relies on all users[i] having values evaluating to true for the loop to continue (and user becoming undefined, equal to false and therefor ending the loop after the last user is processed) – but sometimes you might have data where not every record evaluates to true, but “false-y” values might also occur in the data – and in that case, this approach of course fails.
The problem with this approach:
for(var i=0; user=users[i]; i++) {
// ...
}
...is that it assumes user won't be "falsey" (0, "", null, undefined, NaN, or of course false) until you've gone past the end of the array. So it'll work well with an array of non-null object references, but if you then get in the habit of using it, it will bite you when you have an array of numbers, or strings, or such.
The other reason not to declare variables within the for construct is that it's misleading: Those variables are not scoped to the for loop, they're function-wide. (JavaScript's var doesn't have block scope, only function or global scope; ES6 will get let which will have block scope.)
On modern JavaScript engines (or with an "ES5 shim"), you can of course do this:
users.forEach(function(user) {
// ...
});
...which has the advantage of brevity and not having to declare i or numUsers or even user (since it's an argument to the iteration callback, and nicely scoped to that). If you're worried about the runtime cost of doing a function call for each entry, don't be. It'll be washed out by whatever actual work you're doing in the function.
I'm amazed if the second syntax works at all your middle operation should evaluate to true for each loop you want to complete and false as soon as you want to be done looping. As for any issues with your first for loop, a JavaScript is function scoped so that inner var statement will still leak to the containing function (as well as that i). This is different than most other languages that have block scoping. It's not so much of a problem but something to keep in mind if you are debugging.
If you are already using jQuery, you can use the jQuery.each function to loop over your arrays.
In any case you can look at the source code of that function and copy the relevant parts for your own foreach function: http://james.padolsey.com/jquery/#v=1.10.2&fn=jQuery.each