Difference between named and indexed arrays - javascript - javascript

When using an array constructor and pushing a few values into it as well as adding named values there are some interesting differences.
let arr = []
arr.push('a')
arr.push('b')
arr.push('c')
arr.foo1 = 'bar1'
arr.foo2 = 'bar2'
arr.forEach and for of iterates only over the indexed values, while for in iterates of the indexes/keyed values.
I guess what I'm wondering is why would anyone use this?
One thing that would be cool to have from both objects and array would be a guaranteed order of key-value pairs
(not just [{key:'value'}, {key2: 'value2'] but something where you could use for of on an object where the order would be based on the order in which the keys of the object were set. I know that's not possible but just suggesting something that would be nice to gain between both objects and arrays)
but It seems as though the order of keyed values is not able to be iterated over, so the order is not guaranteed (unless I'm wrong)
Doing this seems like it is a mix between an object and an array, but why would you mix when you can just create an object or array in a common manner?

Arrays are JavaScript objects like any other that you create. (Almost) everything in JavaScript inherits its prototype from Object.
Now the specification of array is such that the indexes are basically just specifically named properties. a[1] and a['1'] are pointing the same property. The only extra thing is that you have to have a length numeric property. In words of ECMAScript language specification, "Array objects are exotic objects that give special treatment to a certain class of property names".
Now, forEach is defined as a function that will only loop through those "special" properties that an Array instance has. It starts with 0 and finishing with length - 1, and it skips undefined values. It doesn't look at other props. So you only get fields in the array.
for of is an iterator - if you have an iterable object, you basically get its iterator function and then loop over values that it gives you. And an array iterable is giving only those indexed property names. You can read a bit more over at MDN.
Once again, an array is object like any other, but we give some of it's properties special meaning, and it inherits some functions from Array prototype that can deal with those properties.
But for in does not care if this object is special or not. It will simply loop over ALL properties of any object you give it, including an array. That's why when you for in loop the object, you're looping the object's properties, and array indexes are included into this.
Note: usage of for ... in ... is not recommended. E.g in a sparse array, (where you set, e.g. a[0] = 1, a[10] = 1, and leave all other indexes undefined), a for in would just log out those two properties.
So if somebody gives you an object that has properties called 0 and 10, would you call it an array? Nope. Another bad thing is that it will also go over the object's prototype and list out the properties of all the objects this array might have inherited from - and you likely do not want that.

Short answer: there is no such thing as a "named array" in JS.
JS's datatype model is based on objects, which are key/value pair containers, and arrays are a special kind of object with additional (native) logic for dealing with numerical keys.
As such, anything you can do to an object, you can do to an array, but you shouldn't: if you need named keys, use an object. If you need numerical keys with derived properties like length and a utility API like push/pop/shift/unshift, forEach, map, etc. use an array.
Also note that the length property says nothing about the actual array footprint in memory: arrays are not like C/Java/etc arrays at all, behaving more like vectors/arraylists instead: they're just JS objects with numerical key/pair bindings, so if you set an array[0] and then you set an array[99], the length will claim "100" and that number will mean nothing at all: your array, in memory, is just an object with a key/value pair keyed on the string 0 and a key/value pair keyed on the string 100.
This quora answer is pretty good further reading, explaining all of this based on the actual ECMAScript spec definitions.

Related

What is happening under the hood in javascript when using the Array brackets notation

I have generally found javascript to be transparent, in that there are very few black boxes where "magic" just happens and you should just accept and look the other way, however I have not found any answer to how the Array brackets [] notation actually works under the hood.
let arr = [4, 5, 6, 7]
console.log(arr[3]) // <- How does this work?
What is javascript doing to access the item at index 3. Does it internally call some method on the Array.prototype?
With an object, the [] is a shortcut for a property accessor.
let obj = {
a: 'hello',
b: 'world'
}
obj['a'] === obj.a // true
Is an array then just an object with a long list of integer based properties?
let objArray = {
0: 'hello',
1: 'world'
}
let realArray = ['hello', 'world']
objArray[0] === 'hello' // true
realArray[0] === 'hello' // true
objArray.0 // SyntaxError: Unexpected number
realArray.0 // SyntaxError: Unexpected number
I have seen many many online discussions that all come to the conclusion that you cannot overload the brackets notation to truly subclass an Array but I have never seen an explanation on what magic is happening under the hood that allows the Array to work the way it does.
The obvious follow up question is whether there is any way to intercept the bracket notation access to define your own behavior, but I think I already know the answer to that.
You'd probably have to look at the implementation code to know precisely what's going on, but the basic idea is that arrays are actually layered atop objects.
This is backwards:
With an object, the [] is a shortcut for a property accessor.
The bracket notation is more fundamental. Thus, obj['foo'] and obj.foo work the same, but there is no equivalent for obj['foo & bar'], which is perfectly legitimate, and will respond with a value if obj has a key named "foo & bar".
Is an array then just an object with a long list of integer based properties?
Not quite, but you're not far off. Arrays are objects with the Array prototype, and with a little bit of additional magic to set the length property when new keys are added, or remove keys when that length is set.
And no, you cannot override the [] operator for your own purposes.
Is an array then just an object with a long list of integer based properties?
Yes, in it's simplest form, an Array is an Object with a list of integer base properties that is based on the Array prototype (which gives access to all the array methods like map, forEach, etc.)
As for intercepting the bracket notation, no, I have not seen anything that would allow that besides creating your own Object that has the methods you need (and then only access that object via the appropriate methods).
More info from MDN:
Arrays are list-like objects whose prototype has methods to perform traversal and mutation operations. Neither the length of a JavaScript array nor the types of its elements are fixed. Since an array's length can change at any time, and data can be stored at non-contiguous locations in the array, JavaScript arrays are not guaranteed to be dense; this depends on how the programmer chooses to use them. In general, these are convenient characteristics; but if these features are not desirable for your particular use, you might consider using typed arrays.
Arrays cannot use strings as element indexes (as in an associative array) but must use integers. Setting or accessing via non-integers using bracket notation (or dot notation) will not set or retrieve an element from the array list itself, but will set or access a variable associated with that array's object property collection. The array's object properties and list of array elements are separate, and the array's traversal and mutation operations cannot be applied to these named properties.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#Array_object

Json length is always undefined in node js

I am trying to iterate simple json array, but it always return the length of the array is undefined.
var chatmessage = {};
...................
...................
socket.on('listmessage', function(mesg){
chatmessage={"message":"Hello", "to":"sjdfjhsdf"};
});
socket.on('private', function(mesg){
console.log(chatmessage.length+' - '+chatmessage.message +' - '+ chatmessage.to);
});
when private event get trigger it returns
undefined - Hello - sjdfjhsdf
I think it consider length key word as a json array key like {"length":40}.
I have tried Object.keys(chatmessage).length but it returns the total number key value(2) but I have only one record.
What is the right way to iterate json in node js
I am trying to iterate simple json array
Two issues there:
That's not JSON. JSON is a textual notation for data exchange. If you're dealing with JavaScript source code, and not dealing with a string, you're not dealing with JSON. It's a JavaScript object initializer.
It doesn't define an array, it defines an object.
Objects don't have a length property. If you want your chatmessage to say how many properties it has, you'll have to add a third property explicitly (which then raises the question of whether the value should be 2 or 3 :-) ). Or alternately, you could make it an array of objects with "key" and "value" properties, but that would be awkward to work with.
If you need to, you can determine how many properties an object has in a couple of ways:
Object.keys(obj).length will tell you how many own, enumerable properties the object has (ignoring any with Symbol names, if you're using ES2015). The number will not include any inherited properties or any non-enumerable properties. The answer in your example would be 2.
Object.getOwnPropertyNames(obj).length) will tell you how many own properties the object, has regardless of whether they're enumerable (but again ignoring any with Symbol names). The number will not include any inherited properties or any non-enumerable properties. The answer in your example would again be 2 as your object has no non-enumerable properties.
I have tried Object.keys(chatmessage).length but it returns the total number key value(2) but I have only one record.
As I said above, Object.keys will tell you how many own enumerable properties the object has. If you're trying to find out how many objects there are, the answer is 1.
If your goal is to send an array of chat messages, then you want to create that like this:
var chatmessages = [
{"message":"Hello", "to":"sjdfjhsdf"}
];
That defines an array with one entry: A single object representing a chat message. Multiple ones would be separated with ,:
var chatmessages = [
{"message":"Hello", "to":"sjdfjhsdf"}, // First message
{"message":"Hello again", "to":"sjdfjhsdf"} // Second message
];
Note that if you're doing that, your verb should probably be listmessages (plural), not listmessage. (I mention this in case your native language handles plurals differently from English; there are a lot of different ways plurals are handled in the various human languages around the planet. :-) )

Create an associative array with integer keys

I need to create an associative array in javascript with an integer key as follows;
a["10"] = "ten";
but when i create an array, it puts the value to the 10th index of the array and it creates an array with the length 11. I want it to be a key value pair. I know this can be done by using objects but i need an array only.
JavaScript does not have associative arrays. The only way to do this in JavaScript is to use objects:
var a = {
'10': 'ten'
};
ECMAScript does have Associated Arrays1 - Objects (and by extension, Arrays) are an example
However, some properties of Arrays are treated specially:
Array objects give special treatment to a certain class of property names. A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P ..
.. Specifically, 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 ..
Thus, given arr = [], the expressions arr["1"] and arr[1] refer to the same property name. Since P (the property name) is "1" and length is 0 from above, then assignment to such property will set arr.length to ToUint32(P)+1, or 2.
It is not possible to change this behavior. If you wish to not have a special length property, then use a "normal" Object instead of an Array. However, many of the Array.prototype functions can be used with arbitrary objects (with some implementation quirks aside) that have a length property and an Object can be created such that it uses Array.prototype as its own prototype.
All that being said, the post does not say what the real issue is. Instead of supposing that it must be done in that particular manner, consider explaining what the intent is: e.g. why a["10"]? And what is wrong if there are "11 items" if the object will be used in a List?
1 Please read the article before debating this statement: the term "Array" in the name does not imply an ordered sequence nor does it preclude an additional notion of a Length or the use of Hashing, etc. If you are going by a different definition, make sure to specify what it is and what the desired behavior is for a given operation.

What's the difference between objects and associated array in javascript?

The Confusing discussion
In this question, there is a discussion on the concepts of associated array and object in javaScript which I got a bit confused.
In this example code:
var check = {
pattern : {
name: /^[a-zA-Z-\s]{1,20}$/,
email: /^[a-zA-Z0-9._(-)]+#[a-zA-Z0-9.(-)]+\.[a-zA-Z]{1,4}$/,
pass: /.{6,40}/,
url: /^[(-)\w&:\/\.=\?,#+]{1,}$/,
aml: /<(.+)_([a-z]){1}>$/
}
};
Here is the discussion makes me confused:
#steven.yang the outer object is not an associative array in your sample, but that is what is being asked for
#sissonb what do you mean by 'outer object is not an associative array'? I think associated array is expressed as object in javascript. The difference is in the notation - either through foo.bar or foo[bar]
#steven.yang associated array means key => value. http://en.wikipedia.org/wiki/Associative_array Your inner object has a key of pattern, the object containing this associative array has no key.
My Understanding of Associated Array and Objects in JS
Associated array is defined as key-value pairs which is expressed as the object in JavaScript.
The outer object assigned to check has a key pattern and an value of another object. The inner object has keys of name, email ... and corresponding values of regular expression objects.
Could both objects be counted as associative arrays?
Not really, here's why:
var arr = new Array();
arr["foo"] = 100;
arr["bar"] = 200;
console.log(arr.length); // Prints 0.
Adding elements to an associative array should increase its length (IMO).
It looks and acts (somewhat) like an associative array because of syntactic sugar. What appear to be "array entries", however, are (just) object properties.
If you define "associative array" as a data structure that stores information as a collection of key-value pairs, then yes, JavaScript objects are associative arrays.
However, the phrase "associative array" is not generally used in the context of JavaScript, rather, we say "object". I'd suggest sticking to standard JS terminology to avoid misunderstandings.
Note that JS also has (non-associative) arrays, with elements accessed via numeric indexes. These are also objects and so allow non-numeric key properties, but this is generally considered bad practice.
There are no associative-arrays in JavaScript. Everything is object.
Certainly they are similar but associative-arrays in JavaScript are just objects.
Associative Array
In computer science, an associative array (also called a map or a dictionary) is an abstract data type composed of a collection of (key,value) pairs, such that each possible key appears at most once in the collection.
As far as I know objects in JavaScript match that definition.
Of course there is no unique "Associative Array" object, that's any different then any other normal object. So if you want associative array functionality use a javascript object.
However the following is a common piece of misinformation
There is no associative array in JavaScript
You should simply ignore these people, maybe try to convince them they are wrong.
My response is coming late, but I hope this can help people to understand this difference. I was reading this post and there isn't a satisfactory definition of an associative array.
JavaScript doesn't have Associative Arrays. These are just objects that you can treat as associative arrays for convenience. In objects you store values as named properties, very similar to associative arrays in other programming languages. That's why you can access the properties like an associative array, but with methods associated to objects. You can test creating an object and try all the things you can do with an associative array, but you can't do all the methods of an array.

How do I access the first key of an ‘associative’ array in JavaScript?

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.

Categories