Is it okay to loop functions in JavaScript? - javascript

Is there any kind of built-in method that would iterate through the object parameters without loop. Like the array object has methods(forEach, sort, filter..).
For example there's an array
var numbers = [3,342,23,22,124];
var max = 0;
for(var i=0;i<numbers.length;i++){
if(numbers[i] > max){
max = numbers[i];
}
}
alert(max);
Instead of looping sort() method could be used
var numbers = [3,342,23,22,124];
numbers.sort(function(a,b){return b - a});
alert(numbers[0]);
Is there any method for regular objects {} in JavaScript, that would work the same way as sort()?
More generally is there any way to avoid such looping:
for(var parameter in object){
var data = object[parameter]
exampleMethod(data);
}
is there a way to execute a function several times without looping?

No, but you can often use a function like Object.keys() to open a pathway to the Array prototype methods like .forEach().
The Object.keys() method returns an array with the "own" property names of an object. (The "own" names are the names of properties directly on the object, and not inherited from the prototype chain.) From there, you can use the Array methods like .forEach to iterate through the property names and, by using those to reference the object, through the property values as well.
For example, consider this object:
var dimensions = {
length: 20,
height: 30,
width: 40
};
If you wanted to sum up the edges, you could do this:
var perimeter = Object.keys(dimensions).reduce(function(sum, dkey) {
sum += 4 * dimensions[dkey];
return sum;
}, 0);
Note also the related methods Object.getOwnPropertyNames() and Object.getOwnPropertySymbols(), which expand the properties available for iteration.

Not like sort because there is no order of properties in JavaScript objects. However, you can use Object.keys and map to turn an object into an array of values.
var o = {a:1,b:3, c, :2};
var arr = Object.keys(o).map(key=>o[key]).sort((a,b)=>b-a);
var max = arr[0];
For regular iteration, combine keys and forEach
Object.keys(o).forEach(key=>console.log('key',key, 'value', o[key]));

Related

Reverse() doesn't work in array with string key

Why reverse() doesn't work if my array have elements with string as a key.
var myArray = [];
myArray["test"] = 100;
myArray["test2"] = 200;
console.log(myArray)
console.log(myArray.reverse())
Both returns the same result.
How can I change it to make it work?
DEMO: https://www.w3schools.com/code/tryit.asp?filename=GG4PXCHZ4VUD
.reverse() is a function of arrays, where elements are indexed by their position. Your code is not adding elements to the array, but rather adding properties on the array object. This works and the properties can be accessed, but reversing does nothing as these are not elements. The array is still of 0 length.
You will have to either:
Make myArray an object of a different type. In this case, reverse will still not work, and you will have to write code to sort manually. Other answers have provided some guidance as to how to achieve this
Add your elements to the array using push() or numeric indices, in which case you'll lose the string indices but can use array sorting methods such as .reverse()
While numbers have an intrinsic ordering, object property keys follow different rules. If you want to reverse a string-indexed object, consider writing a function to insert objects to a new Map in reverse order.
Arrays values are only accessible by index.
myArray[0] = 100;
myArray[1] = 200;
console.log(myArray) // [100, 200]
console.log(myArray.reverse()) // [200, 100]
You can store values by keys in objects.
var myObject = {};
myObject["test"] = 100;
myObject["test2"] = 200;
console.log(myObject) // {test: 100, test2: 200}
That said, you can reverse an object by doing this:
Object.entries(myObject).reverse().reduce((a, b) => {
a[b[0]] = b[1];
return a
},{})
Since you do not actually need any array methods, it would be better to simply use an object instead.
You can create a new reversed array by looping over Object.keys() backwards. See the code in action here.
var myArray = [];
myArray["test"] = 100;
myArray["test2"] = 200;
function reverseAssociative(arr){
const keys = Object.keys(arr);
const res = [];
for(let i = keys.length - 1; i >= 0; i--){
res[keys[i]] = arr[keys[i]];
}
return res;
}
const res = reverseAssociative(myArray);
for(const key in res){
console.log(key, res[key]);
}
You can simplify it by using reduce on Object.entries after reversing. See the code in action here.
myArray = Object.entries(myArray).reverse().reduce((acc,[key,val])=>(acc[key]=val,acc),[])

Can't create JS object with array indices as key & value?

Task: convert an array into an object with one key-value pair, where the first array item is the key, and the last array item is the value.
E.g., [1,2,3] should convert to {1: 3}
I can't get it to work as:
function transformFirstAndLast(array) {
var firstLast = {
array[0]: array[-1]
};
return firstLast
}
But only as:
function transformFirstAndLast(array) {
var firstLast = {};
firstLast[array[0]] = array[array.length - 1];
return firstLast
}
...why doesn't the first work? Why can't you index the array for the key & value?
You could pop the last element and take a computed property for the object. (For the first element, you could take Array#shift, if you like to do it in the same manner.)
function transformFirstAndLast(array) {
return { [array[0]]: array.pop() };
}
console.log(transformFirstAndLast([1, 2, 3]));
ES5 with a temporary variable.
function transformFirstAndLast(array) {
var temp = {};
temp[array[0]] = array.pop();
return temp;
}
console.log(transformFirstAndLast([1, 2, 3]));
Take the first is easy, take the last is the size minus one like this:
function firstAndLast(array) {
var ary = {};
ary[array[0]] = array[array.length - 1];
return ary;
}
console.log(firstAndLast([1,2,3]))
First, you must remember than an array is a type of JavaScript object and, in JavaScript, an object property (a.k.a. "key") can be accessed or assigned in two ways:
via "dot notation"
object.property = value;
via array syntax
object["property"] = value;
Next, remember that, in JavaScript, if you assign a value to a property that doesn't exist (using either syntax from above), the property will be created, like in the following:
console.log(window.someNewProperty); // undefined
window.someNewProperty = 17; // This causes the property to be created
window["someOtherNewProperty"] = "Voilla!"; // So does this, just with array syntax
console.log(window.someNewProperty); // 17
console.log(window["someOtherNewProperty"]); // "Voilla!"
Now, moving on to the specifics of an array, it's critical to understand the difference between an object property/key name (which is always represented as a string) and an array index (which is always a non-negative integer up to the max integer in JavaScript). So, if you have an array and seemingly assign a value to a negative index, you are actually creating a property that is named the negative index and not actually adding to the length of the array or making a new indexed position in the array. We can see that here:
var myArray = ["a", "b", "c"];
myArray[-1] = 15;
console.log(myArray.length); // 3 not 4
console.log(myArray[-1]); // 15
// Now to prove that -1 is a string name for a new property and not an index:
console.log(myArray); // Notice no 15 in the indexed values?
// And, if we enumerate the object (not just the indexes), we'll see that we actually created
// a property with [-1], not a new index.
for(var prop in myArray){
// Note that prop is not the value of the property, it's the property name itself
console.log(typeof prop, prop, myArray[prop]);
}
So, to sum up, Arrays have non-negative integer indexes to store the items that make up the length of the array, but Arrays are also objects and have properties, like all other objects do. Any bracket assignments that use anything other than non-negative integers as the key name will become new properties, not array indices.

How to make associative array with number as string in Javascript

I have a code :
var index = 100;
var arr =[];
arr[index.toString()] = "Hello"
The result : index still known as integer not a string. Anyone can explain what's wrong with my code?
You have to declare associative arrays using {}, which creates a new object, because in JavaScript, arrays always use numbered indexes.
You need to declare an object: var arr={};
arrays use numbered indexes.
objects use named indexes.
var index = 100;
var arr ={};
arr[index.toString()] = "Hello";
console.log(arr);
How to make associative array with number as string in Javascript
JavaScript doesn't have associative arrays in the sense that term is frequently used. It has objects, and as of ES2015 (aka "ES6"), it has Maps.
The result : index still known as integer not a string. Anyone can explain what's wrong with my code?
The index variable's value is still a number, yes, because you haven't done anything to change it. But the index in the array is a string (and would be even if you didn't use .toString()), because standard arrays aren't really arrays at all1, they're objects with special handling of a class of properties (ones whose names are strings that fit the spec's definition of an array index), a special length property, and that use Array.prototype as their prototype.
Here's proof that array indexes are strings:
var a = [];
a[0] = "zero";
for (var name in a) {
console.log("name == " + name + ", typeof name == " + typeof name);
}
That said, you don't want to use an array when you want a generic object or map.
Here's using a generic object for name/value mappings:
var o = Object.create(null);
var name = "answer";
o[name] = 42;
console.log(o[name]); // 42
The property names in objects are strings or (as of ES2015) Symbols. I used Object.create(null) to create the object so it wouldn't have Object.prototype as its prototype, since that gives us properties (toString, valueOf, etc.) that we don't want if we're using the object as a map.
Here's using a Map:
var m = new Map();
var name = "answer";
m.set(name, 42);
console.log(m.get(name)); // 42
The main advantages Maps have over objects are:
Their keys can be anything, not just strings or Symbols
They're iterable, so you can use for-of to loop through the mappings they contain
Maps have a size property telling you how many entries they have
Maps guarantee that iteration of their entries is performed in the order the entries were added to the map
With ES6, you could use a Map, which holds any type as key.
var map = new Map;
map.set(100, "Hello");
map.set('100', "Foo");
console.log(map.get(100)); // 'Hello'
console.log(map.get('100')); // 'Foo'
console.log([...map]);
JavaScript does not support arrays with named indexes, in JavaScript, arrays always use numbered indexes.
If you use a named index, JavaScript will redefine the array to a standard object.
After that, all array methods and properties will produce incorrect results.
As you can see in the following example:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
var x = person.length; // person.length will return 0
console.log(x);
var y = person[0]; // person[0] will return undefined
console.log(y);

how to get array values of keys stored in an object with "for in" loop in javascript [duplicate]

This question already has answers here:
How do I enumerate the properties of a JavaScript object? [duplicate]
(14 answers)
Closed 8 years ago.
In Javascript, I'd like to have an object with three properties, "zone1", "zone2", "zone3", each of which store an array of place names. I would like to search for a match by iterating through the arrays to find a place name.
The following questions almost gets me there, but don't work for me because I am not using jQuery, and I want the value, not the key:
Performing a foreach over an associative array of associative arrays
Getting a list of associative array keys
My code looks like this:
var zoneArray = {};
zoneArray["zone1"] = ["placeA", "placeB"];
zoneArray["zone2"] = ["placeC", "placeD"];
function getZone(place, zoneArray) {
var zone;
for (var key in zoneArray) {
for(i = 0; i<key.length; i++) {
if(key[i] == place) {
zone = key;
return zone;
}
}
}
}
getZone("placeC", climateZoneArray);
Apparently however, "key[i]" is referring to letters of the zone names, like, "z" "o" "n" "e"
Could anybody please help me understand or best handle this situation in Javascript?
Use zoneArray[key] to access the array.
for (var key in zoneArray) {
var arr = zoneArray[key]
for(i = 0; i<arr.length; i++) {
if(arr[i] == place) {
zone = key;
return zone;
}
}
}
Using for ... in to iterate over an object's properties can lead to some pretty surprising results, especially if you're working in an environment where Object.prototype has been extended. This is because for ... in will iterate over an objects enumerable properties and the enumerable properties contained in that objects prototype chain. If this isn't what you want but you are going to use for ... in anyways, it's recommended to have a conditional statement at the top of the loop that checks that the property belongs to the object which is being iterated over. (if (!foo.hasOwnProperty(x)) continue;). Luckily, there is Object.keys(). You can use Object.keys() to get an array of an objects own enumerable properties, if you do this you can skip hasOwnProperty ugliness. Instead of iterating over the object you can iterate over an array of it's keys.
var collection = {
zone1: ['placeA', 'placeB'],
zone2: ['placeC', 'placeD']
};
function getZone(needle, collection) {
var zones = Object.keys(collection),
found;
for (var i = 0, l = zones.length; i < l; i++) {
found = collection[zones[i]].filter(function(place) {
return needle == place;
});
if (found.length > 0) {
return zones[i];
}
}
};
console.log(getZone('placeC', collection));
This is also here on jsfiddle.net
One last thing, be very careful when creating variables, in the inner for loop you created the variable i without using the var keyword. This resulted in i being bound to the global context, something you really want to avoid.

How to remove all undefined keys from a javascript array (hopefully when creating the array?)

I have placed my frustrations into a jsfiddle to observe here: http://jsfiddle.net/8ShFr/1/
var brand_new_array = new Array();
brand_new_array[10] = "random array value";
alert('why does this array have a length of ' + brand_new_array.length + '???');
I am doing some calculations client side that require me to set javascript array keys of 1M+ in number.
Not knowing exactly what that number is demands that I iterate through the first 1M+ empty array values before getting to an array key that holds data.
I simply want to set a single large key value for a javascript array without creating a bunch of empty keys before it?
I am using jQuery.each to iterate over the array, and it keeps going through array[0], array[1], array[2], etc... when I only set array[123125] for example.
Just filter out the undefineds.
brand_new_array = brand_new_array.filter(function(n){return n !== undefined});
The reason for the length being 10 is that an array's length is set to the largest index number in the array. However, this does not mean there are 9 other values in there because in javascript an array is at its base an object.
The length is just a property in the object. Arrays in javascript are at their core objects (Array Object 1). They merely act like arrays through an api.
"Whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index" 1
1. ECMAScript Language Specification 15.4 Array Objects
You probably want to just use an object with strings for keys (the keys can be the toString() of Numbers, which will happen automatically if you try to use numbers).
var sparse_array_obj = {};
sparse_array_obj[10003210234] = 4; // Fair dice roll
sparse_array_obj[5] = 17; // Truly random number
sparse_array_obj[900] = Math.random(); // Pseudorandom number
for(var i in sparse_array_obj)
console.log(sparse_array_obj[i]);
The downside is that Javascript provides no guarantees about the iteration order through an object (since its keys are unordered by definition). There are however ways around this, such as:
// Sort the keys in numeric order
var sorted_keys = Object.keys(sparse_array_obj).sort(function(a, b){ return a - b; });
for(var i = 0; i < sorted_keys.length; i++)
console.log(sparse_array_obj[sorted_keys[i]]);
Object.keys needs to be shimmed in older browsers.
var brand_new_array = new Array();
brand_new_array[10] = "random array value";
var result = brand_new_array.filter(function(e) { return e != undefined;})[0];
alert(brand_new_array.indexOf(result));
Travis J is right. The array in your example only contains one entry, but your use of jQuery.each() is making you think there are 10 entries because it iterates from 0 up to the highest index number of the array (defines the length). This is from the jQuery.each() API documentation.
A generic iterator function, which can be used to seamlessly iterate over both objects and arrays. Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index, from 0 to length-1. Other objects are iterated via their named properties.
Going back to your example:
var brand_new_array = new Array();
brand_new_array[10] = "random array value";
This will result in only one console.log output:
for(var i in brand_new_array)
console.log(brand_new_array[i]);
This will result in 10 console.log outputs:
$(brand_new_array).each( function(i,e) { console.log(e) })
Similarly, this will result in 10 console.log outputs:
for (var i=0;i<brand_new_array.length;i++)
console.log(brand_new_array[i]);
If you really want to stick with using .each() then you can skip the undefined indices like so:
$(brand_new_array).each( function(i,e) {
if (this.hasOwnProperty(i)){ console.log(e) }
})
Filter the falsy items - including undifined:
var a=[1,2,"b",0,{},"",NaN,3,undefined,null,5];
var b=a.filter(Boolean); // [1,2,"b",{},3,5]
The length is 11 because the index starts at 0.
x[0] = undefined
x[1] = undefined
x[2] = undefined
x[3] = undefined
x[4] = undefined
x[5] = undefined
x[6] = undefined
x[7] = undefined
x[8] = undefined
x[9] = undefined
x[10] = "random array value"

Categories