I have checked this page : mozilla documentation
I dont understand why the index 0 with :
const object3 = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(object3)[0]);
// expected output: Array ["100", "a"] <== i thought of this
instead the documentation says you get :
// expected output: Array ["2", "b"]
Someone can explain it why ?
The Docs say that Object.entries returns an array of given objects enumerable property [key,value] pairs . So yes its confusing if you look at this statement
const object3 = { 100: 'a', 2: 'b', 7: 'c' };
and end up getting ["2", "b"] when you call Object.entries(object3)[0].
When you are doing this Object.entries(object3)[0] , you are accessing a pair at the index of 0 returned by this function Object.entries(object) . The order of this array has nothing to do with how you defined the object3 in the first place. The order according to the doc is the same as the provided by a
for...in loop. I ran the for...in loop on the object and this is what i got as the order.
2,7,100.
This is why you are getting ["2", "b"] instead of ["100", "a"]. As others have mentioned here , the order seems to be that way because 2<7<100.
This is because the object has numeric keys and when you manipulate the object with the numeric keys the javascript sort the key-values in ascending order of the key value and since you have keys 2, 7, and 100. So, check this when you console.log the object Object.entries(object3) you get that sorted and when you access [0] you get Array ["2", "b"]
const object3 = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(object3));
Further clarification on sorting the object by ascending values of key when they are numeric. The javascript sorts them behind the scenes.
var a = {
10: 'ten',
5: 'five',
11: 'eleven',
1: 'one'
};
console.log(a);
Related
This question already has answers here:
Sorting object property by values
(44 answers)
Closed 5 months ago.
I have an indexed object and need to sort it by alphabetic value. I tried sort() function but it remove the given indexes and assign new indexes starting from 0, and I want to keep the existing indexes but just sort by the value.
Here is my code.
var response = {3: 'Ab', 8: 'Fe', 10: 'Bc', 15: 'Eg'};
var sorted = Object.values(response).sort();
sorted output = {Ab, Bc, Eg, Fe} but I don't want to change the existing indexes of each value.
I need to sort the object like this.
var sorted = {3: 'Ab', 10: 'Bc', 15: 'Eg', 8: 'Fe'};
Using an object for your case will not work since the ordering will be by the numeric keys, I suggest you use a Map as follows:
const obj = {3: 'Ab', 8: 'Fe', 10: 'Bc', 15: 'Eg'};
const sorted = Object
.entries(obj)
.sort(([, a], [, b]) => a.localeCompare(b))
.reduce((map, [key, value]) => map.set(+key, value), new Map);
console.log([...sorted]);
extension of this question
So I was playing around with a project and I found myself needing to create a string where I didn't know the exact order of the lettering right away, but I did know their position(and by extension, the length of this string).
Part of the reason for doing it this way is that I don't want to skip array elements at any point during the process(NO ["a", , "t"] during the process). Meaning that the order of insertion matters.
let string_length = 10;
let o = {
0: "a",
4: "q",
7: "t",
3: "p",
6: "h",
1: "z",
2: "t",
5: "a",
9: "b",
8: "z"
};
function obj_to_arr(o) {
// this returns ["a","z","t","p","q","a","h","t","z","b"]
}
All the answers I've found until now don't necessarily guarantee that given an index object, it will give the corresponding ordered object, and this is mainly because of the nature of object, being unordered.
Is there a way to implement this?
You could fix this in two possible ways (and probably more).
Array
Either you add objects containing both the key and the value to an array.
array.push({c: "a"}) or array.push({ key: c, value: "a"}), then add the next and so on.
Push puts an element at the end of an array.
Sorted object
Or you insert into the object using alphabetic keys, in which case you can use the example below.
You could sort the keys (properties) of the object, and use them to access each value and put them into another array. Here's a verbose example of how you could do that.
const someObject = {
c: "a",
4: "q",
7: "t",
b: "p",
6: "h",
1: "z",
2: "t",
5: "a",
a: "b",
8: "z"
};
function obj_to_arr(obj) {
let result = []
// Get keys from object as an array
let keys = Object.keys(obj)
console.log('keys: ', keys)
// Sort the array in alphabetical order
let sorted = keys.sort()
console.log('sorted: ', sorted)
// Add each value to the resulting array
sorted.forEach(function(key) {
console.log('adding ' + obj[key] + ' to array')
result.push(obj[key])
})
console.log('result: ', result)
return result
}
// Call the function
obj_to_arr(someObject)
Using Object.keys(), you can retrieve an array of keys, sort them numerically, then map that sorted array to one with the values.
The result will be an array of values in an order corresponding to the numeric values of the keys, even if they are not sequential.
For example
let o = {"0":"a","1":"z","2":"t","3":"p","4":"q","5":"a","6":"h","7":"t","8":"z","10":"b"}
let sortedValues = Object.keys(o)
.sort((a, b) => a - b) // numeric comparison
.map(k => o[k]) // map to values
console.info(sortedValues)
The short answer is "you can't" because of the Javascript spec.
Objects in Javascript are not guaranteed to have their keys ordered in any way due it being a primitive type that engines are allowed to optimize the hell out of, including reordering keys to speed up property access.
If ordering really matters, then you shouldn't be using an object primitive. Either an array of tuples (which has guaranteed ordering):
let fixedList = [
{ key: 0, value: 'a' },
{ key: 4, vlaue: 'q' },
...
];
or you can use a Map, which exists specifically as a way to have "an object, with the same ordering of key/value pairs as you declared".
Of the two, for data transport you probably want the former, and for running code you typically want the latter.
This question already has answers here:
Why does spread syntax convert my string into an array?
(5 answers)
Closed 4 years ago.
Here,we created Hashmap with keys and value.Then we use array.map to get our result. i.e If we input "cat",we will get output as "dog".I didnt get how spread syntax is used.
var rule =
{
"c": "d",
"a": "o",
"t": "g",
"h": "a",
"e": "n",
"n": "t",
}
function output(str) {
return [...str].map(d => rule[d]).join('')
}
console.log(output('cat'))
Break it down:
[...str]
Gives: ['c', 'a', 't'];
In this case, the spread syntax breaks up the string into an array. Where each index represents a letter from the string.
.map(d => rule[d])
Converts the above array to:
['d', 'o', 'g']
As it goes through each value and uses the javascript object to get its value: (so 'c' maps to 'd' as rule['c'] = 'd', 'a' maps to 'o', etc...)
.join('')
Converts the above array to a string dog
Thus, doing:
console.log(output('cat'))
Gives: "dog"
spread syntax on a string turns it into an array consisting of its characters. This works because strings are iterable collections. http://es6-features.org/#SpreadOperator
In your case the spread operator spreads the string "cat" into an array of characters containing ['c','a','t']
Then it iterates over this array to provide the output string matches the values. There you get the string "dog" as output!
You would not be able to apply map to the string directly, as String does not have such a method. With the spread syntax you get an array of individual characters, and then map can be applied to that array.
It is in fact better practice to use Array.from instead, because it does not create the intermediate array and still allows you to execute a function on each character (using the second argument):
Array.from(str, d => rule[d]).join('')
It takes an iterable and returns each item of the iterable by using the spread syntax ....
In this case, a string is splitted to an array of characters.
['c', 'a', 't']
The same result could be achieved, if you use Array.from, which has a built-in mapping parameter.
var rule = { c: "d", a: "o", t: "g", h: "a", e: "n", n: "t" }
function output(str) {
return Array.from(str, d => rule[d]).join('');
}
console.log(output('cat')) ;
According to the MDN JavaScript documentation you can define object literal property names using integers:
Additionally, you can use a numeric or string literal for the name of a property.
Like so:
me = {
name: "Robert Rocha",
123: 26,
origin: "Mexico"
}
My question is, how do you reference the property that has an integer as a name? I tried the usual me.123 but got an error. The only workaround that I can think of is using a for-in loop. Any suggestions?
You can reference the object's properties as you would an array and use either me[123] or me["123"]
Dot notation only works with property names that are valid identifiers. An identifier must start with a letter, $, _ or unicode escape sequence. For all other property names, you must use bracket notation.
In an object literal, the property name must be an identifier name, string literal or numeric literal (which will be converted to a string since property names must be strings):
var obj = {1:1, foo:'foo', '+=+':'+=+'};
alert(obj[1] + ' ' + obj.foo + ' ' + obj['+=+']); // 1 foo +=+
You can use me[123] or me["123"]. Both work.
You can use bracket notation me[123].
Just in case anyone else was confused by this: using integer (rather than string) property names may give slightly different - though functionally the same - results (depending on the browser) when you have objects within objects.
Simple objects with no nested objects have consistent behavior across browsers (though as the accepted answer says, we need to use brackets instead of dots to access integer property names):
var str_simple = {
a: "b", c: "d", e: "f", g: "h",
};
str_simple.a === "b"; // true
str_simple.e === "f"; // true
var int_simple = {
1: 2, 3: 4, 5: 6, 7: 8,
};
int_simple[1] === 2; // true - must use brackets instead of dots
int_simple[5] === 6; // true
// this works b/c int property names are coerced to strings anyway
int_simple[1] === int_simple['1']; // true
And this nested object with string keys works exactly as expected:
var str_nested = {
a: {b: "c"},
d: {e: "f", g: "h"},
};
str_nested.a; // returns object as expected, no matter the browser - {b: "c"}
str_nested.a.b === "c"; // true
str_nested.d.g === "h"; // true
But this equivalent nested object with integer keys returns slightly different results depending on the browser, though you can still access the nested objects in the same way (so functionally, it still works the same):
var int_nested = {
1: {2: 3},
4: {5: 6, 7: 8},
};
// latest Chrome (57)
// Safari 10 (latest for my Mac, 10.10 Yosemite)
int_nested[1]; // returns object as expected - {2: 3}
int_nested[1][2] === 3; // true
// latest Firefox (52)
int_nested[1]; // RETURNS ARRAY-LIKE OBJECT - Object [ <2 empty slots>, 3 ]
int_nested.length; // undefined because it's not technically an array
int_nested[1][2] === 3; // true - works b/c object was padded with empty slots
// and again, in all browsers, we can exchange the integer keys
// for equivalent strings since property names are coerced to strings anyway
int_nested[1][2] === int_nested['1'][2];
int_nested['1'][2] === int_nested[1]['2'];
int_nested[1]['2'] === int_nested['1']['2'];
This behavior will still be slightly different but functionally the same if you programmatically construct a nested object. For example, say we wanted to write a function that would take a list of pairs (e.g. [[0, 0], [0, 1], [1, 2], [2, 3]]) and convert it into a nested object so we could check if the pair is in the object with O(1) time (e.g. {0: {0: true, 1: true}, 1: {2: true}, 2: {3, true}}). Note that Sets check reference equality and not value equality, so we couldn't store the pair itself in the Set and achieve the same results:
// [[0, 0], [0, 1], [1, 2], [2, 3]] ->
// {
// 0: {0: true, 1: true},
// 1: {2: true},
// 2: {3: true},
// }
function createNestedObject(pairs) {
var obj = {};
for (var pair of pairs) {
var x = pair[0], y = pair[1];
// must create outer object for each unique x or else
// obj[x][y] would fail b/c obj[x] would be undefined
if (!obj.hasOwnProperty(x)) {
obj[x] = {};
}
obj[x][y] = true;
}
return obj;
}
function exists(nested, pair) {
var x = pair[0], y = pair[1];
// uses !! operator so if pair isn't in nested
// we return false instead of undefined
return !!(nested[x] && nested[x][y]);
}
Pairs with strings will work as expected:
var pairs = [["a", "a"], ["a", "b"], ["c", "d"], ["d", "e"]];
var nested = createNestedObject(pairs);
nested; // as expected - {a: {a: true, b: true}, c: {d: true}, d: {e: true}}
exists(nested, ["a", "a"]); // true
exists(nested, ["a", "b"]); // true
exists(nested, ["ZZZ", "ZZZ"]); // false
But in certain browsers, integer pairs will be different but functionally the same:
var pairs = [[0, 0], [0, 1], [1, 2], [2, 3]];
var nested = createNestedObject(pairs);
nested; // in Safari 10/Chrome 57 - returns nested objects as expected
nested; // in Firefox 52 - Object [ Object[2], Object[3], Object[4] ]
// BUT still gives correct results no matter the browser
exists(nested, [0, 0]); // true
exists(nested, [0, 1]); // true
exists(nested, ['0', '0']); // true
exists(nested, [999, 999]); // false
The situation with numeric property names seems more complicated than it is explained in the answers so far. It is true that you can access such properties via for-in loop. However, it might be important to know that for-in loop gives keys as strings, not as numbers as you might expect:
var obj = {1:2};
for (var key in obj) {
alert(typeof(obj[key])); // you get "number" as expected, however
alert(typeof(key)); // you get "string", not "number"
}
A similar thing happens during serialization with JSON:
JSON.stringify( {1:2} ) === '{"1":2}'
So if you code depends on this little detail you better be aware of it.
It is said that forEach() method is used to loop over any array like object .But here
Array.prototype.forEach.call({1:"a",2:"b"},function(eleVal,ele){alert(eleVal+":"+ele)})
The above code dont work ,why??
Because {1: "a", 2: "b"} is not an array, it's an object. Array.forEach requires that its target has a length property, which this object does not.
Try with an array such as ["a", "b"] and it will work, or alternatively with the array look-alike
{0: "a", 1: "b", length: 2}
Add a .length property to the object and it'll work.
Please note that you'll index will start at 0, so the first element will be undefined.
[].slice.call({1: 'a', 2: 'b', length: 3})
[undefined × 1, "a", "b"]
Another way to do it. I prefer this one since it doesn't modify the original object.
var obj = {1:"a", 2:"b"};
for(var i in obj) { if(obj.hasOwnProperty(i)) console.log(i + ':' + obj[i]); }