When I running this code by node app.js
'use strict';
var data = {"456":"First","789":"Second","123":"Third"};
console.log(data);
I've geting next result:
{ '123': 'Third', '456': 'First', '789': 'Second' }
Why JS or Node.js (I don't know who) sort this object by keys? I don't want this.
What you're seeing is a behavior of the V8 JavaScript engine. It's not something specified by the JavaScript specification, and it's not something you can rely on (most engines don't do that).
But the important thing here is: There is no order to a JavaScript object. So V8's behavior is just as correct as putting those keys in any other order. If you want things in a particular order, you have to use an ordered container, like an array.
JavaScript objects aren’t ordered. If you want things in order, you can use an array.
var data = [
{ key: "456", value: "First" },
…
];
Or, alternatively, keep the key order in a separate array.
Properties in an object aren't ordered. You can't expect the order you give to be preserved when a representation of your object is built for the console.
The iteration order is implementation dependent. Don't rely on it. If you need some order, use another data structure (for example and array of key-values).
// try this to sort employees by age
employees.sort(function(a, b){
return a.age-b.age
});
Related
I have two variants to work with my objects full of data:
let global_obj = {
"id0": { /*big object 0*/},
"id1": { /*big object 1*/},
"id2": { /*big object 2*/}
};
and:
let global_arr = [
{ id: "id0" /*big object 0*/},
{ id: "id1" /*big object 1*/},
{ id: "id2" /*big object 2*/}
];
So I can save my big objects full of data inside of a global array or a global object. Which way is better in terms of performace (looping through, deleting, adding new objects)?
I am going to address specific objects by their id very often, change objects' properties, loop trought them all.
I would use an object in this case as finding an element by id is easier/faster. If index/order of elements is important, object don't help here and you need to use an array.
Basically:
Objects: Keyed collections
Arrays: Ordered collections
But regular objects and arrays are not the only options if the environment supports ES2015. ES2015 has introduces several APIs for working with collections: Map, Set, WeakMap and WeakSet.
As you mentioned that you'll be "addressing specific objects through their id's very often"; using an Object will be a wise choice for you. Since accessing an object's key is done in O(1) as compared to finding the object in an array, which will be O(n), hence Object will be better in performance.
You should do what's more convenient for you, it most likely won't make a difference.
However, generally, if the top level object is small, the array is always faster than a hashtable/object (the size of the inner objects doesn't matter). If the top-level structure is big, then you should consider the big-o complexity for the operations you want to perform on the top-level structure. See http://bigocheatsheet.com/
I have an array of objects that is fed by an external API e.g
[{prop: val1}, {prop: val2}, {prop: val3}....]
I have to feed this object(my code) to a third-party library which expects the name of the property on the object to be 'xyz' instead of 'prop'.
What is the most efficient way (memory wise and faster) basically avoiding both:
1. iterating over the array
2. adding 'xyz' property to all objects in the array
to achieve this?
I am thinking along the lines of adding a getter for xyz to all objects that return the 'prop' value, but that does not save the looping.
Adding the getting on the prototype level (Object.property) seems like a bad idea at this point.
Edit: I am not looking for different ways to loop through arrays in javascript like forEach or map. I have a very specific ask, and i am interested in exploring if it is at all possible to simply have a property proxy for 'xyz'.
Array map is used to cycle trough an array.
myArray.map(function(obj){
obj.xyz = 'yourvalue';
return obj;
}
You can use Array.map to create a new from the array you received by the API.
var newArray = oldArray.map(function(obj){
return {newKey : obj.prop};
});
In this example, newKey will be the key property you want, instead of 'prop', and it's assigned the old 'prop' value
I am gettting an api response using axios.
I am sending the api response sorted w.r.t name http://localhost:8000/api/ingredients/ordering=name
The actual object sent is as below from my server.
{
2:{"id":2,"name":"anil"},
1:{"id":1,"name":"sant"},
3:{"id":3,"name":"vino"}
}
or pass the key as string instead of integer
{
"2":{"id":2,"name":"anil"},
"1":{"id":1,"name":"sant"},
"3":{"id":3,"name":"vino"}
}
or key as alphanumeric
{
"a2":{"id":2,"name":"anil"},
"a1":{"id":1,"name":"sant"},
"a3":{"id":3,"name":"vino"}
}
what axios is doing is sorting the objects w.r.t keys and the names are not in sorted order
{
1:{"id":1,"name":"sant"},
2:{"id":2,"name":"anil"},
3:{"id":3,"name":"vino"}
}
or if key is alpha numeric
{
a1:{"id":1,"name":"sant"},
a2:{"id":2,"name":"anil"},
a3:{"id":3,"name":"vino"}
}
How to stop this
I dont want in array format the list because i have to update the individual objects later based on the id. This representation is easy. I am using reactjs state.
There is answer here Does JavaScript Guarantee Object Property Order? among other that says:
most browsers returns properties in the same order as they were inserted, but it was explicitly not guaranteed behaviour so shouldn't have been relied upon.
The ECMAScript specification used to say:
The mechanics and order of enumerating the properties ... is not
specified.
However in ES2015 and later non-integer keys will be returned in insertion order.
So don't rely on order of an object keys. If you don't worry about ES5 you can try to use non-integer keys - strings for instance but note that strings like '1' are not suitable http://code.google.com/p/v8/issues/detail?id=164.
You can find on the page of the answer also:
If you rely on insertion order, you are outside the ECMAScript spec, but within the de-facto standard of common browser behavior as long as your keys don't parse as integers.
UPDATE
Short answer is axios doesn't sort keys of an object
https://jsfiddle.net/zabq841t/
axios.get('/echo/js/?js={a2: 1, a1: 0}')
.then((res) => {
//res.data is {a2: 1, a1: 0}
})
You can get sorted version because of old browser or your server. Take a look fiddle if it works for you then probably you have 'issue' on server side. You need to provide more details about you server app.
This is an expected behavior for objects in JavaScript.
If you want to have the order intact, use Arrays, So your example would turn out like this,
const obj = [{name:"two"},{name:"three"},{name:"one"}];
If you need to pass keys, then reorder it in this way,
Edited
Back to your edited version, say you want to update your object based on ID and this is your provided json,
{
a1:{"id":1,"name":"sant"},
a2:{"id":2,"name":"anil"},
a3:{"id":3,"name":"vino"}
}
Nothing will stop you from doing so, if you want to change details for an object with id:2, you can do the following to get the key a2,
const key = Object.entries(obj).find(entry => entry[1].key === 2)[0];
const desiredElement = obj(key);
Breakdown of the code,
Object.entries(obj) // get entries from object
.find(entry) //where entry[0] is key, entry[1] is value/object
entry[1].id=== 2 // return the element that has id === 2
[0] // since entry[0] is key, then it would hold a2 here
Now we can use the key as we want like, Obj[key], and update it as well.
I want to add attribute to a JS object, but in a custom place, After a given attribute.
var me = {
name: "myname",
age: "myage",
bday: "mybday"
};
me["newAt"] = "kkk"; //this adds at the end of the object
Is there a way to specify the object (me), an attribute(age) in it and add a new attribute(newAt) right after the specified one? A better way than doing string operations?
var newMe = {
name: "myname",
age: "myage",
newAt: "newAttr",
bday: "mybday"
}
UPDATE: (Since people are more focused on why I'm asking this than actually answering it)
I'm working on a drawable component based on user input - which is a JS object. And it has the ability to edit it - so when the user adds a new property based on "add new node" on the clicked node, and I was thinking of adding the new node right after it. And I want to update the data accordingly.
JavaScript object is an unordered list of properties. The order is not defined and may vary when using with an iterator like for in. You shouldn't base your code on the order of properties you see in debugger or console.
JavaScript objects do, as of ES2015, have an order to their properties, although that order is only guaranteed to be used by certain operations (Object.getOwnPropertyNames, Reflect.ownKeys, etc.), notably not for-in or Object.keys for legacy reasons. See this answer for details.
But you should not rely on that order, there's no point to it, it's more complicated than it seems initially, and it's very hard to manipulate (you basically have to create a new object to set the order of its properties). If you want order, use an array.
Re your edit:
I'm working on a drawable component based on user input - which is a JS object. And it has the ability to edit it - so when the user adds a new property based on "add new node" on the clicked node, and I was thinking of adding the new node right after it. And I want to update the data accordingly.
The best way to do that is, if you want a specific order, keep the order of keys in an array and use that to show the object.
While you could use ES2015's property order for it, to do so you'd have to:
Require your users use a truly ES2015-compliant browser, because this cannot be shimmed/polyfilled
Destroy the object and recreate it adding the properties in the specific order you want each time you add a property
Forbid properties that match the specification's definition of an array index
It's just much more work and much more fragile than keeping the order in an array.
The simplest solution I could find was to iterate through the keys of the parent and keep pushing them to form a clone of the parent. But to additionally push the new object if the triggered key is met.
var myObj = {
child1: "data1",
child2: "data2",
child3: "data3",
child4: "data4"
};
var a = (function addAfterChild(data, trigChild, newAttribute, newValue) {
var newObj = {};
Object.keys(data).some(function(k) {
newObj[k] = data[k];
if (k === trigChild) {
newObj[newAttribute] = newValue;
}
});
return newObj;
})(myObj, "child3", "CHILD", "VALUE");
document.getElementById("result").innerHTML = JSON.stringify(a);
<p id="result"></p>
I have a js 'associative' array, with
array['serial_number'] = 'value'
serial_number and value are strings.
e.g. array['20910930923'] = '20101102'
I sorted it by value, works fine.
Let's say I get back the object 'sorted';
Now I want to access the first KEY of the 'sorted' array.
How do I do it? I can't think I need an iteration with
for (var i in sorted)
and just stop after ther first one...
thanks
edit: just to clarify, I know that js does not support associative arrays (that's why I put it in high commas in the Title).
2021 Update
Since ES6, properties with string keys are enumerated in insertion order. Here's a nice summary. My original answer from 2010 was correct at the time and is preserved below:
Original answer
JavaScript object properties are specified to have no order, much though many people wish it were different. If you need ordering, abandon any attempt to use an object and use an Array instead, either to store name-value objects:
var nameValues = [
{name: '20910930923', value: '20101102'},
{name: 'foo', value: 'bar'}
];
... or as an ordered list of property names to use with your existing object:
var obj = {
'20910930923': '20101102',
'foo': 'bar'
};
var orderedPropertyNames = ['20910930923', 'foo'];
Try this:
// Some assoc list
var offers = {'x':{..some object...}, 'jjj':{...some other object ...}};
// First element (see attribution below)
return offers[Object.keys(offers)[0]];
// Last element (thanks to discussion on finding last element in associative array :)
return offers[Object.keys(offers)[Object.keys(offers).length - 1]];
Actually JavaScript doesn't support associative arrays, so you can't loop through it in an implied order (e.g. you can't access it via the indexer property array[0] won't access the first element in your object). The syntax is what makes it look like it does, but in reality it doesn't. So you have no "Order" to your objects.
http://www.hunlock.com/blogs/Mastering_Javascript_Arrays
Javascript does not have, and does not
support Associative Arrays. However…
All arrays in Javascript are objects
and Javascript's object syntax gives a
basic emulation of an associative
Array. For this reason the example
code above will actually work. Be
warned that this is not a real array
and it has real pitfals if you try to
use it. The 'person' element in the
example becomes part of the Array
object's properties and methods, just
like .length, .sort(), .splice(), and
all the other built-in properties and
methods.
Just thinking off the top of my head, but could you have another array with the key value pairs swapped?
So the answer would be arrayKeyValueReversed['20101102'] = '20910930923';
When you sort the array, use the first item (array[0]) as the key to get the value in the arrayKeyValueReversed.