javascript access the counter of a for in loop - javascript

How can I access the counter of a for..in loop?
I have an array and an object. I want to iterate over the object properties while doing the same with the array, without explicitly declaring a counter.
var colors = ['red','yellow','purple','blue'];
var flowers = {'rose':'','sunflower':'','violet':'','hydrangea':''};
for (prop in flowers) {
flowers[prop] = colors[i];
}
Follow up question. If not possible, how would I create my own for loop with the functionality I require. Here's how it's working currently but I find I'm doing this often and want to create something reusable.
var colors = ['red','yellow','purple','blue'];
var flowers = {'rose':'','sunflower':'','violet':'','hydrangea':''};
var i = 0;
for (prop in flowers) {
flowers[prop] = colors[i];
i++;
}

(ECMAScript 2015 changes things, see update at end of answer.)
I have an array and an object. I want to iterate over the object properties while doing the same with the array, without explicitly declaring a counter.
I don't believe you can. Moreover, it's important to understand the that properties in the object have no order. You seem to be assuming you'll get "rose", then "sunflower", etc. That is simply not guaranteed. Many engines visit object property names in the order in which the properties were added to the object, and the order in which literal properties in an object initializer are added to the object is now (as of ES5 a couple of years back) specified, but visiting them in any particular order in for-in is not specified behavior (similarly, Object.keys is not sorted in any particular way), and a perfectly correct engine can visit them in any order it wants.
As such, with just the array and object you've shown, you have no reliable way to map those properties to the array entries.
As of ECMAScript 2015 (ES6), object properties have order now:
Let keys be a new empty List.
For each own property key P of O that is an integer index, in ascending numeric index order
Add P as the last element of keys.
For each own property key P of O that is a String but is not an integer index, in property creation order
Add P as the last element of keys.
For each own property key P of O that is a Symbol, in property creation order
Add P as the last element of keys.
Return keys.
Okay, so we know that they'll be visited in "creation" order, but in what order are they created by an object initializer? Good news: Object initializers are processed in source code order, so that's deterministic. Your rose comes before your sunflower, etc.
This means that while you still can't do what you want without explicitly declaring and maintaining an index variable, you can relate that array and that object reliably:
// Works as of ES6
var colors = ['red','yellow','purple','blue'];
var flowers = {'rose':'','sunflower':'','violet':'','hydrangea':''};
let i = 0;
for (prop in flowers) {
flowers[prop] = colors[i++];
}
I'm not suggesting doing it, but it's possible now, on compliant engines.

Related

Javascript Object Storage Order

This is my Array
let setOne = [""];
Now, I created a function that takes the element from the array i.e setOne, store that element in one Object as a property name and give that property-name a value of true and prints the object data.
Function is
function checkTheSameBetter(setOne) {
let ObjectShop = {};
for (let indexSetOne = 0; indexSetOne < setOne.length; indexSetOne++) {
ObjectShop[setOne[indexSetOne]] = true;
}
console.log(ObjectShop);
}
The Output which I get is
{ '': true }
No Problem so far
Here comes the main part
when I add another value to an array i.e setOne, consider "1".
let setOne = ["",1];
And then when I execute the function checkTheSameBetter. I get output
{'1': true, '': true }
So my question is, "how did that '1' get stored in the first
position?"
The output I expected was in this order
{'': true, '1': true}
Here is the sandbox Link
https://codesandbox.io/s/cranky-cori-qx116?file=/src/index.js
can anyone please tell me what's happening here?
If you need any clarification I will give it.
Thank You
JS Objects have traditionally been 'unordered' (until ES5). Since ES6, there is a predictable order to the Object properties iteration. It, however, isn't the 'insertion' order. The order of keys will be as follows:
First, all non-negative integer keys less than 232, in ascending order. (eg. '1', '79', etc. basically all valid array indices. Caveat: '05' wouldn't be considered integer key, since the integer parsed from it will yield a different string representation).
Then, all String keys, in the original order of insertion. (Numeric strings not falling within bounds of step one will be considered here.)
Then, all Symbol keys, in the original order of insertion.
Looking at the rules above, it makes sense that '1', being an integer key, appeared before '' (a string).
Please note that this only applies to ES2015 and later. To avoid confusion, and eye rolls from colleagues habituated of viewing objects as unordered, please don't rely on enumeration order of Object properties. If the enumeration order is relevant, you can always use Map which guarantees that insertion order will be maintained.
ES6 defines an order in which own properties of an object are enumerated. Following are the rules according to which own properties of an object are enumerated:
String properties whose names are non-negative numbers are listed first, from smallest to largest. This means that properties of array and array-like objects will be enumerated in order.
After that, all properties with string names are listed in the order they were added in the object. This also includes properties that look like non-negative numbers or floating point numbers.
At last, properties whose names are Symbols are listed in the order they were added in the object.
Following functions list the properties in the above described order, subject to their own constraints.
Object.keys()
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Reflect.ownKeys()
One thing to keep in mind is that enumeration order for for in loop is not as tightly specified as it is for above mentioned enumeration functions but it typically enumerates own properties in the order described above.
As for in loop also enumerates properties in the prototype chain, once own properties have been enumerated, it will then move up the prototype chain, enumerating properties of each prototype object in the same order as described above. Although if a property has already been enumerated, any property with the same name won't be enumerated again. Property won't be enumerated even if a non-enumerable property with the same name has already been considered.
const obj = {};
obj[2] = 2;
obj['-1'] = -1;
obj['1'] = 1;
obj['as'] = 'as';
obj['10'] = 10;
obj['b'] = 'b';
console.log(Reflect.ownKeys(obj));
console.log(Object.getOwnPropertyNames(obj));
for (const key in obj) {
console.log(key);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }

Why does the isArray() Javascript method in this example returns true, if the array has been redefined as a standard object?

I'm trying to learn Javascript - here's my issue:
In the w3schools.com javascript array examples, they show the sequent example:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
document.getElementById("demo").innerHTML =
person[0] + " " + person.length;
An array "person" has been defined, but then they proceed to add some elements whit a "named" index. Then tries to print the HTML document the 0th element and the number of elements of the array, like you would do with a standard array.
The description says:
If you use a named index when accessing an array, JavaScript will
redefine the array to a standard object, and some array methods and
properties will produce undefined or incorrect results.
In fact, person[0] and person.length return respectively "undefined" and "0". Even is person was initially defined as an array, by inserting new named indexes elements, the array should be redefined as an object. But when i try do use the Array.isArray() method for checking it, it returns true:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
document.getElementById("demo").innerHTML =
person[0] + " " + person.length;
document.getElementById('test').innerHTML = Array.isArray(person);// returns true
So, why? if, as specified by the tutorial, this has been effectively redefined as a standard object, and the ECMAScript 5 has added the .isArray() method for checking if something is an array and nothing else, shouldn't this return false insted of true?
I'm sure i missed something. If i define person like this:
person = {};
then it returns false, as expected. What is happening here? I just wanted to understand arrays a little bit more, this confuses me. Is this just a broken array, but still an array?
Here's the example (without the Array.isarray() bit, just the default): https://www.w3schools.com/js/tryit.asp?filename=tryjs_array_associative_2
First of all I want to note that the example you took from the w3schools page on arrays, is from the "Associative Arrays" section, which has this important introduction:
Many programming languages support arrays with named indexes.
Arrays with named indexes are called associative arrays (or hashes).
JavaScript does not support arrays with named indexes.
In JavaScript, arrays always use numbered indexes.
This puts the example into context, because it really makes no sense to define a variable as an array and then use string keys. But this was an example to illustrate the point.
Does an Array become an Object?
That JavaScript still considers the variable to be an array is as expected. It becomes an array at the moment of assignment of [], and that does not change by adding properties to that object. Yes, arrays are objects. They just have additional capabilities.
The array did not lose any of its array-like capabilities, but those features just don't work on those string properties, ... only on numerical ones (more precisely, the non-negative integer ones).
You loosely quoted the following statement from w3schools:
If you use named indexes, JavaScript will redefine the array to a standard object.
That is wrong information and leads to your misunderstanding. There is no redefinition happening. When you add properties to any object, then the object does not change "type". It remains an instance of what it was before... An array remains an array, a date object remains a date, a regex object remains a regex, even if you assign other properties to it. But non-numerical properties do not "count" for an array: the length will remain unchanged when you add such properties. The length only reveals something about the numerical properties of the object.
This quote is yet another illustration of what the JavaScript community thinks about w3schools.com, i.e. that it is not the most reliable reference, even though it has its value for learning the language.
Example of adding useful properties to arrays
Having said the above, there are cases where you may intentionally want to make use of such properties on arrays. Let's for example think of an array of words that is sorted:
const arr = ["apple", "banana", "grapefruit", "orange", "pear"];
Now let's add something to this array that denotes that it is currently sorted:
arr.isSorted = true;
We could imagine a function that would allow one to add a value to this array, but which also verifies if the array is still sorted:
function addFruit(arr, fruit) {
if (arr.length && fruit < arr[arr.length-1]) {
arr.sorted = false;
}
arr.push(fruit);
}
Then after having added several values, it would maybe be interesting to verify whether the array needs sorting:
if (!arr.sorted) arr.sort();
So this extra property helps to avoid executing an unnecessary sort. But for the rest the array has all the functionality as if it did not have that extra property.
An object that is set up as an array and then filled as an object becomes a member of both classes. Methods of the Array class will apply to its 'array-ness':
Array.isArray(person);
returns true. Methods of the Object class will apply to its 'object-ness':
typeof(person);
returns object. When it could be either one, the 'array-ness' will prevail, because the variable was first defined as an array:
console.log(person);
will put Array [ ] on the console, because it runs the Array class's logging method. It is displayed as an empty array, since it has no numbered elements, but you could add some:
person[2]=66;
and then console.log would log Array [ <2 empty slots>, 66 ].
I think the polyfill implementation of isArray() will clear your doubt by some extent.
#Polyfill

JavaScript: Weird (edge?) case of a mixed Array/Object

I saw this for the first time (or noticed it for the first time) today during a maintenance of a colleagues code.
Essentially the "weird" part is the same as if you try to run this code:
var arr = [];
arr[0] = "cat"; // this adds to the array
arr[1] = "mouse"; // this adds to the array
arr.length; // returns 2
arr["favoriteFood"] = "pizza"; // this DOES NOT add to the array. Setting a string parameter adds to the underlying object
arr.length; // returns 2, not 3
Got this example from nfiredly.com
I don't know what the technical term for this "case" is so I haven't been able to find any additional information about it here or on Google but it strikes me very peculiar that this "behaviour" can at all exists in JavaScript; a kind of "mix" between Arrays and Objects (or Associative Arrays).
It states in the above code snippet that that Setting a string parameter adds to the underlying object and thus not affect the length of the "array" itself.
What is this kind of pattern?
Why is it at all possible? Is it a weird JS quirk or is it deliberate?
For what purpose would you "mix" these types?
It's possible because arrays are objects with some special behaviors, but objects nevertheless.
15.4 Array Objects
However, if you start using non-array properties on an array, some implementations may change the underlying data structure to a hash. Then array operations might be slower.
In JavaScript, arrays, functions and objects are all objects. Arrays are objects created with Array constructor function.
E.g.
var a = new Array();
Or, using shortcut array literal,
var a = [];
Both are the same. They both create objects. However, special kind of object. It has a length property and numeric properties with corresponding values which are the array elements.
This object (array) has methods like push, pop etc. which you can use to manipulate the object.
When you add a non-numeric property to this array object, you do not affect its length. But, you do add a new property to the object.
So, if you have
var a = [1];
a.x = 'y';
console.log(Object.keys(a)); // outputs ["0", "x"]
console.log(a); // outputs [1];

Storing regex in an array is not working in Javascript

How is regex stored in javascript. Is not stored like the usual way other var types like string is stored.
var regexOne = /^(regex).*$/gm;
var regexTwo = /^(regex).*$/gm;
var regexThree = /^(regex).*$/gm;
var regexFour = /^(regex).*$/gm;
var searchQuery = [regexOne, regexTwo, regexThree, regexFour];
for(query in searchQuery){
console.dir(query.toString());
}
The above code prints:
'0'
'1'
'2'
'3'
How can i get this working.
When you iterate an Array with for..in loop, the loop variable with have just the current index as string, not the actual value. Quoting MDN documentation on Array iteration and for...in,
The for..in statement iterates over the enumerable properties of an object, in arbitrary order.
....
....
Note: for..in should not be used to iterate over an Array where index order is important.
Array indexes are just enumerable properties with integer names and are otherwise identical to general Object properties. There is no guarantee that for...in will return the indexes in any particular order and it will return all enumerable properties, including those with non–integer names and those that are inherited.
Because the order of iteration is implementation dependent, iterating over an array may not visit elements in a consistent order. Therefore it is better to use a for loop with a numeric index (or Array.forEach or the for...of loop) when iterating over arrays where the order of access is important.
The bold text above says it all. So, you should iterate arrays with one of the following options
normal for loop
for(var i = 0; i < searchQuery.length; i += 1) {
console.dir(searchQuery[i]);
}
Array.prototype.forEach function
searchQuery.forEach(function(currentRegEx) {
console.dir(currentRegEx);
});
for...of, loop (Note: This will work only in environments which implement ECMAScript 6)
for(var currentRegEx of searchQuery) {
console.dir(currentRegEx);
}
for-in, in JavaScript, loops through the enumerable property names of an object. It's not for looping through array entries or array indexes (although with safeguards it can be used for the latter, which is why you're seeing 0, 1, etc. — those property names are array indexes).
For details about looping through arrays, see this answer, which has a thorough list of options and explanations of each of them.
Side note 1:
Your code is falling prey to The Horror of Implicit Globals because you never declare the query variable. (The for-in construct doesn't declare it for you.)
Side note 2:
Unless you need the regexOne and such variables, you can create your array of regexes more concisely:
var searchQuery = [
/^(regex).*$/gm,
/^(regex).*$/gm,
/^(regex).*$/gm,
/^(regex).*$/gm
];

Javascript's JSON.stringify doesn't take key-indexed (associative) arrays?

In JavaScript, you can have objects, like this:
var a = { foo: 12, bar: 34 };
Or arrays with key (named) indexes, like this:
var b = [];
b['foo'] = 56;
b['bar'] = 78;
They're somewhat similar, but obviously not the same.
Now the strange thing is, JSON.stringify doesn't seem to take the array. No errors or anything, JSON.stringify(b) just results in [].
See this jsfiddle example. Am I doing something wrong, or do I just misunderstand how arrays work?
Javascript doesn't support Associative arrays (Like PHP).
var b = []; Declaring explicitly an array, when you are trying to create an Object.
Arrays in Javascript can only contain the Index approach of Arrays, while Objects are more of
Associative arrays.
If you change var b = []; to var b = {}; it will solve the problem.
var b = {} Declaring explicitly an Object.
Javascript arrays are objects. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Predefined_Core_Objects#Array_Object for details.
Note: if you supply a non-integer value to the array operator in the
code above, a property will be created in the object representing the
array, instead of an array element.
JSON supports only a subset of Javascript. See http://www.json.org/ for details.
JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed
list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
A Javascript array that has properties created in the underlying object does not fit into either of these structures because it has both a collection of name/value pairs and an ordered list of values, so there is no simple way to represent such an object directly in JSON.
The JSON.stringify method is defined in the ECMAScript specification. For example, see http://www.ecma-international.org/ecma-262/5.1/#sec-15.12.3.
While there are many details, the bit that is relevant here is how object values are stringified:
If Type(value) is Object, and IsCallable(value) is false
If the [[Class]] internal property of value is "Array" then Return the result of calling the abstract operation JA with argument value.
Else, return the result of calling the abstract operation JO with argument value.
Given your array, despite the addition of parameters to the underlying object, the result is of stringifying the ordered set of array elements, not the underlying object.
There is nothing wrong about adding parameters to an array object, but they are not part of the array and functions or methods that handle arrays might ignore them or deal with them arbitrarily. You have seen that JSON.stringify ignores the additional parameters. Other functions might do otherwise - you will have to find out in each case.
While it is not wrong, it will probably be easier to understand if you do not add properties to array objects. If you want to add properties, start with a non-array object.
Rather than:
var b = [];
b['foo'] = 56;
b['bar'] = 78;
You might use:
var b = {};
b['foo'] = 56;
b['bar'] = 78;
This snap is from IE explorer. See the array is still blank.
Actually the way of inserting the elements to the array is :
1. Use push()
2. insert the elements in the array during declaration
If you want to stringify the array you have to have the data inside the array.
So, now you want to stringify the key value pairs so you have to pass the object as the argument of JSON.stringify() as follows:
var test = {}; // Object
test['a'] = 'test';
test['b'] = []; // Array
test['b'].push('item');
test['b'].push('item2');
test['b'].push('item3');
var json = JSON.stringify(test);
alert(json);
Solution to your problem now:
Note: Console of Google Chrome is giving different result, which is a bug in Google Chrome.

Categories

Resources