Checking item of array on "undefined" in JavaScript - javascript

My JS-code has array arrayResults, some element of him can be "undefined" - this is feature of algorithm. To check that there is no such elements I use the follow code:
for (i in arrayResults)
{
if (typeof(arrayResults[i])=='undefined')
{
// ask user to repeat
};
};
But, using the debugger, I found that JS-engine passes the "undefined"-item of array (in for condition), respectively I don't have the possibility to make the comparing and make the follow instructions.
So, is there any way to really check the "undefined" items in array? (I can't to set items of array in sequence, because if I found the position of "undefined" item, I tell to user to go to this position).

Don't use a for..in loop to iterate arrays. If you are interested in the reasons, please read this StackOverflow question. They should only be used for traversing objects.
Use a simple oldschool for loop instead, it will solve your problem.
for (var i = 0, l = arrayResults.length; i < l; i++) {
if (typeof(arrayResults[i])=='undefined') {
// ask user to repeat
};
};
jsFiddle Demo

You can use indexOf method on array.
function hasUndefined(a) {
return a.indexOf() !== -1;
}
hasUndefined([1,2,3, undefined, 5]);

Related

Redefine array using itself

I wrote this solution to a problem I had, but I don't feel entirely comfortable with it. It seems to be dangerous, or at least in bad practice to use an array to redefine itself, sort of like trying to define a word but using the word in the definition. Can anyone explain either why this is wrong, or why it's ok?
let array = []
// other stuff happens to fill the array
array = array.filter(element => element !== true)
The reason I'm doing it this way is that I need that same variable name (array, for these purposes) to remain consistent throughout the function. The contents of the array might be added or removed multiple times before the array gets returned, depending on other behavior happening around it.
Let me know if this is too vague, I'll try to clarify. Thanks!
It's perfectly fine. The right side (array.filter(element => element !== true)) of the assignment will be evaluated first, generate a completely new array and only then it'll be assigned back into array.
You can loop through your array backwards and remove the items, as to not allocate another array and reassign.
for (i = array.length - 1; i >= 0; --i) {
if (!!array[i]) {
array.splice(i, 1);
}
}
This solution is:
Fast
Memory efficient
Will not interfere with any other code that has a reference to your original array.

How to find the first undefined array element in javascript, to fill it?

If entries are being added and removed in an array (not pushed/popped) what is the optimal way to scan and find the first undefined element, so that it can be set with a new value?
If the array contains holes with findIndex you can find the first one like so:
[1, 2,, 4, 5].findIndex(Object.is.bind(null, undefined))
indexOf will ignore holes. So
[1, 2,, 4, 5].indexOf(undefined)
Always returns -1.
Assuming we have no prior knowledge of operations being performed on the array, the fastest way is to simply iterate through the entire array linearly
var arr = [1, 2, , 4];
for (var i = 0; i < arr.length; i++) {
if (typeof arr[i] === 'undefined') {
arr[i] = 'foo';
break;
}
}
Or we can keep track of whats being removed using something like this
var earliestRemoved;
if (newRemoved < earliestRemoved || !earliestRemoved) {
earliestRemoved = newRemoved;
}
I guess the simplest way would be to use Array.indexOf to find the index of the first undefined element.
Today I've got the same question, so here's my take on it.
It all depends on your specific problem. My problem was this:
I have an array instances[], with objects in it;
Methods of some of these are registered as callbacks elsewhere;
Sometimes I do need to remove some instance from an array;
Sometimes I need to add new instance;
The problem is that I can't just splice an array, because it'll invalidate all my callback registrations. Well, I can just leave them in the array and forget, adding new elements at the end. But it's.... bad. It's leaking memory.
So I came with an idea of making "holes" in an array in place of removed elements, and then re-using these holes for new elements.
Thus the question "how to find undefined elements in an array?".
Someone here suggested using array.indexOf(undefined) - unfortunately that won't work... for some reason.
But, if it's okay in your case to use null or 0 instead, then it will work.
Here's an example:
var A = [1,1,1,1, , ,0,0,null,1,1];
A.indexOf(undefined); // output: -1 (doesn't work)
A.indexOf(0); // output: 6
A.indexOf(null); // output: 8
Hope this'll be useful.
With the hindsight of about 4.3 years behind me, What I'd do now is, since I'm the owner of the array, is to make an object with 2 arrays in it, the 2nd just contains the indexes that are cleared out. (prob. manage it in a class). So always have clear set with knowledge of what's undefined.
This to avoid iterating through arrays linearly.
2021
Nowadays you can safely use:
myArray.findIndex((element) => (typeof element === "undefined"));

How to test whether a JavaScript object is an ordered type of object

I'm looking for an efficient way to test whether or not a JavaScript object is some kind of ordered object. Hopefully someone knows a trick that doesn't involve writing some huge type assessor function. Fortunately, I don't have to deal with IE < 9 so most of the newer methods are OK.
The fundamental problem is this: I need to figure out whether or not to run a for loop or a for...in loop on an object. However, I don't always know if the object is going to be an object literal, an array, a jQuery object, etc.
Here are some of the obstacles I'm running up against:
I clearly can't only use typeof because both arrays and objects return object.
I clearly can't only use Object.prototype.toString.call(collection) because, while arrays do return [object Array], custom ordered collections such as jQuery objects still return [object Object] and the whole reason I want this test is to determine whether I need a for loop or a for...in loop. Using a for...in loop on a jQuery object includes properties that aren't actually part of the collection and messes things up.
I did come up with one idea that looks like this:
function isOrdered(item) {
// Begin by storing a possible length property
// and defaulting to false for whether the item
// is ordered.
var len = item.length, isOrdered = false;
// Functions are an easy test.
if (typeof item === 'function') {
return false;
}
// The Arguments object is the only object I know of
// with a native length property that can be deleted
// so we account for that specifically too.
if (Object.prototype.toString.call(item) === '[object Arguments]') {
return true;
}
// Attempt to delete the item's length property.
// If the item is ordered by nature, we won't get
// an error but we also won't be able to delete
// this property.
delete item.length;
// So if the length property still exists as a
// number, the item must be an ordered collection.
if (typeof item.length === 'number') {
isOrdered = true;
}
// If we originally stored a custom length property,
// put it back.
if (len !== undefined) {
item.length = len;
}
// Return the result.
return isOrdered;
}
So far this technique has passed all of my tests but I'm worried about possible performance hits that could arise from deleting properties on custom objects and I'm not 100% confident I'm not missing something. Does anyone have any better ideas?
You can do something like this:
function isOrdered(item) {
var len = item.constructor.prototype.length;
return len === +len;
}
If 'item' is a js object this will evaluate to false but if it's an array or jQuery collection this will return true.
Note that things other than arrays can have numeric length properties (try checking the length of a function). If you might pass things like integers or functions you will need to do something more complicate, but this should catch all the cases you catch in your posted code. Also, I think deleting the length property can have unpredictable results so I would avoid that approach in favor something that does not mutate the object you are testing.
If your trick is working in Firefox, Chrome, and recent IE, I think it's probably okay....though a bit wonky.
Delete goes through and deletes the key and value from an object, rather than just clearing the reference. It will actually return false if it cannot delete the property, so you could tighten up your logic a bit further.
There's a bit of performance overhead to property deletion, and it does some weird stuff to regular objects currently in memory [see this article], but negligible depending on the browser. It really depends on how many collections you'd be doing this on at a time. For a single array/object/mystery, I think it would be fine. But for a nested collection of thousands of arrays, you might want to look into some other alternative.
Here's a JS perf if you're primarily concerned with performance:
http://jsperf.com/delete-vs-undefined-vs-null/3
update
Alternatively, if you are concerned with Jquery collections vs arrays, you could do something like the following:
if (foo.length != undefined) {
if (Array.isArray(foo)) {
// regular array. Could also do
// foo instanceof Array
}
else if(foo.constructor.toString().match(/jQuery/g)) {
// jquery collection
}
} else {
// not an ordered collection
}

Create nested arrays on a loop in Javascript

When I'm working with data, I normally have the need of create Arrays or Objects on a loop, let's say "on the fly".
Lets say for example I want to rearrange an array grouping the element by one of the array keys: One of the methods I use is to loop trough an for in. But the problem is when I define more than one index on the fly.
for(key in array){
newArray[array[key]['gouping_key']] = array[key];
}
This example works fine. But if you have more than one element with the same grouping_key, this code is going to override your previous element.
So, I try this:
var i = 0;
for(key in array){
newArray[array[key]['gouping_key']][i] = array[key];
i++
}
But when I add that second index the interpreter complains saying that the newArray[array[key]['gouping_key']] is undefined. Problem it doesn´t seems to have on the previous example.
Why is that?
I've made this fiddle with an example in case the previous snippets an explanation would be insuficient and unclear. In the fiddle you have three snippets (two commented out).
The first one is the error I get when trying something like what Iǘe mentioned previously.
The second is the solution I use.
And the third an example of the creation of an array on the fly with only one index.
Summing up, I want to know why, when you add the second index, you get that error.
Thanks!
var i = 0;
for(key in array){
// If nested object doesn't exist, make an empty one.
newArray[array[key]['gouping_key']][i] =
newArray[array[key]['gouping_key']][i] || [];
newArray[array[key]['gouping_key']][i] = array[key];
i++
}
You need to create an array to push to, it's not created for you. You can use the || operator to only create an empty array if it's undefined.
Also, that's a lot of nesting to follow... If I may...
var x, y;
y = 0;
for(key in array){
x = array[key].gouping_key;
newArray[x][y] = newArray[x][y] || []
newArray[x][y] = array[key];
y++
}
See how much more readable that is? It's also faster! You dont have to deeply traverse complex objects over and over again.
First using for in for arrays is no good idea, it does not what you are expecting I think. see: https://stackoverflow.com/a/4261096/1924298. Using a simple for loop (or while) should solve your problem.

Array type being picked up as array value

I have some simple Javascript looping through an array of items (Tridion User Groups) to check if the user is a member of a specific group.
I can easily code around the issue shown below ( see && extensionGroup !== 'true') but I want to understand why the isArray = true is counted as a value in the array - any ideas?
The screenshot below demonstrates that the value extensionGroups has been set thus
var extensionGroups = ["NotEvenARealGroup", "Author", "ExampleGroupAfterOneUserIsActuallyIn"];
but returns the isArray value as a 4th value?
updated to show images a little clearer
You're using for in to iterate an array; don't do that. Use for (or forEach):
for(var i = 0; i < extensionGroups.length; i++) {
var extensionGroup = extensionGroups[i];
// ...
}
The reason this fails is because for in is used to iterate over an object's properties in JavaScript. Iterating over an array in this way means you get anything else assigned to it, such as this property or length.
And if you're able to use Array#forEach, it's probably most appropriate here:
extensionGroups.forEach(function(extensionGroup) {
// ...
});
For..in, technically speaking, doesn't iterate through values. It iterates through property names. In an array, the values ARE properties, under the hood. So when you iterate over them with for..in you get funky stuff like that happening.
Which highlights my next point: don't use for..in. Don't use it for arrays -- don't use it for anything, really. Ok -- maybe that's going a bit too far. How about this: if you feel the need to use for..in, think hard to see if it's justifiable before you do it.

Categories