I just searched through SO and it looks like everybody agrees with the idea that JavaScript and TypeScript are not supporting using numbers as keys in an object directly. But somehow my fellow developer has used some objects with numeric keys in our Angular project which are working just fine as other objects. This is what they look like.
{
1: 1,
2: 0,
3: 2
}
And calling the value in a form like obj[2] does not have a problem at the moment. Just wondering if it is the right way to do it, and how well this usage is supported?
Its fine, as in - its legal, as its how arrays work, though one thing to watch out for is that arrays will ensure the key is incremental, starting at 0, whereas a numerical key in an object will not, and WILL be misleading for other developers when they cant understand why obj[1] doesnt always live beside obj[2] etc, and by that I mean the use of within loops etc and simply incrementing the index by one each time. So, personally i wouldnt recommend it due to it looking like an array, but it not actually being an array...
Side - If you are trying to mimic an array, but want an index starting at 1, just use an array as normal and have your code just handle the offset each time. Arrays come with many functions, like length, sort, find etc that an object will not
In javascript keys in object are string type and if you have obj[1] it will automatically turn into obj['1'] but not the same in Map
const obj = {}
obj[1] = 'one';
console.log(obj[1]);
// output: "one"
console.log(obj['1']);
// output: "one"
obj['1'] = 'one string';
console.log(obj[1]);
// output: "one string"
console.log(obj['1']);
// output: "one string"
const map = new Map();
map.set(1, 'one');
map.set('1', 'one string');
console.log(map.get(1));
// output: "one"
console.log(map.get('1'));
// output: "one string"
Related
In python, a list, even when it is a class, prohibits its instances from creating more user attributes.
>> x = list()
>> x.new_attribute = 90
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'new_attribute'
This as expected throws error even when classes could possibly accept more attributes through __dict__. This makes sense.
Even though it isn't exactly similar, my questions is that javascript arrays act weirdly when they are given properties.
let x = [1,2,3]
x.foo = "this is unexcpected"
console.log(x)
This would print [1, 2, 3, foo: "this is unexcpected"]. Here is my questions, Aren't arrays supposed to have all their keys to be autogenerated numbers? I mean if I check the length it is still three and it isn't counting foo as part of the array in the usual sense, more over all the methods like pop doesn't apply to the key-value pair. This makes a good sense, but makes me wounder if this (addition of key-value pairs) is allowed so that they could be used to store metadatas about the arrays, after all length is also kind of a property. One more questions, if arrays can store key-value pairs, what makes them different from object except some of the methods like inserting, poping ...?
I know this thread is old, but I find the question interesting...
The main part of the question is what's the difference between an object and an array. As mentioned in the comments, Array.prototype IS an object. Which allows us to do some kind of weird things. Take this code for example:
let y = [0,1,2,3];
y.foo = "Testing";
console.log(y);
y.sample = function(){
console.log("Hello world");
}
y.sample()
Yes, you can add methods to an array, on the console it outputs this:
> (4) [0, 1, 2, 3, foo: 'Testing']
0: 0
1: 1
2: 2
3: 3
foo: "Testing"
sample: ƒ ()
length: 4
[[Prototype]]: Array(0)
> Hello World
Considering the way that Javascript was made, we can do odd things like add methods to arrays and treat them as objects. However, these objects have intended uses and built-in methods provided by the developers (push, pop, etc.). Maybe you could create your own modified datatype in JS by modifying the Array.prototype object. Outside of that, it feels kinda weird to add methods and properties to arrays...at that point just make an object for the sake of readability, but hey, as long as your code is understandable and it works, it's good to me.
This is a question about Javascript(and possibly other languages) fundamentals.
I was developing a project and at some point a realized I had defined the same key more than once in an object but no error appeared on console. After some research I couldn't find a clear/official statement to what happens in this situation or how this affects the program. All I could find out is the output in a simple example:
let obj = {key1:1, key1:2, key1:3};
console.log(obj.key1);// >> output = 3
console.log(Object.keys(obj));// >> output = ['key1']
My question is: The value is just redefined and all previous declarations are erased? Is this a limitation or some kind of error of Javascript?
The value is just redefined and all previous declarations are erased?
Yes. When an object literal contains duplicate keys, only the final key in the object literal will exist on the object after the object is evaluated.
Is this a limitation or some kind of error of Javascript?
It's permitted, but it's nonsense. Like lots of things in programming, there are things which are syntactically allowed but don't make any sense in code.
But you can use a linter to prevent from making these sorts of mistakes, eg ESLint's no-dupe-keys.
There's one case where something very similar to duplicate keys can be common, which is when using object spread, eg:
const obj = { foo: 'foo', bar: 'bar' };
// Now say we want to create a new object containing the properties of `obj`
// plus an updated value for `foo`:
const newObj = { ...obj, foo: 'newFoo' }
This sort of approach is very common when working with data structures immutably, like in React. It's not exactly the same thing as an outright duplicate key in the source code, but it's interpreted the same way - whatever value gets interpreted last in the key-value list (regardless of if the key is spread or static) will be the value that the final object contains at that key.
I am making a small game in JavaScript to help me learn it. The game is based around an array of tiles, each with different values.
When it starts, it puts an object into each cell, then goes on to the next, changing the values.
It always shows the properties of the last cell. Is there any way I can have the cells have different values without making tons of different objects?
Sorry if the question isn't clear. I'm very new to JavaScript.
You don't need to worry about the objects and there is few ways to declare array and work with it. You can follow the javascript doucemntation.
If you are not satisfy the documentation there is some array examples to understand the value changing and objects changing.
JavaScript Array: Explained with uses in different components
JavaScript Pass By Value And Pass By Reference In JavaScript
JavaScript Arrays - tips, tricks and examples
If you have any question comment below.
I think you are pushing the same object over and over into the array. Use the spread operator to essentially clone the object in place while changing the values you need.
const array = []
const obj = { a: 5, b: 6 };
array.push(obj);
array.push(obj);
obj.b = 8;
array.push({ ...obj, b: 10 })
console.log(array[0], array[1], array[2]);
As you see, obj.b=8 affects both the first and second elements of the arrays as they are both referring to the same object. But since the spread (...) operator is cloning the object, only the last element has b=10
When I access arguments from inside called function in nodejs...
echo '!function(){ console.log(arguments) }(1,2,3)' | node
... it outputs an object ...
{ '0': 1, '1': 2, '2': 3 }
... but in google chrome ...
!function(){ console.log(arguments) }(1,2,3)
... outputs ...
[1, 2, 3]
Why is it not consistent? What other js environments have this different behaviour? Is it ok for me to use arguments? How can I ensure it is always an array before I use it?
There are no rules for console output. The output doesn't represent anything that has to do with the language standard.
If you create a program that logs values from within a JS program, you're free to display those values however you want.
The arguments object is the same in both places. Only how it's being displayed is different.
How can I ensure it is always an array before I use it?
It's never an array. It's always an array-like object. In both cases its showing a value at object members 0, 1 and 2. Just uses different display syntax to do it.
In Chrome, try creating an object like this:
var my_obj = {
"0": 1,
"2": 3,
"1": 2,
length: 3,
splice: function(){},
};
And the log it in the console. It'll probably look like an Array literal, though it's obviously not.
It's not an Array in the browser, either. The arguments object has actually been in JavaScript longer than Arrays have, and when Arrays were first added to JavaScript (back in its 1.1 days), they didn't update arguments to be an Array. They haven't done it since then either, because of worries about backward-compatibility. It shows up in some browser consoles as though it were an Array because the debug console knows that most people plan to treat it as one anyway.
But the arguments object is close enough to an Array that it's easy to convert. One way to do it is like this:
var args = Array.prototype.slice.call(arguments, 0);
Array.prototype.slice, like most of Array.prototype's methods, is written to be generic: you can call it on Objects that aren't Arrays, and as long as they have properties with numeric names and a length property that's a Number, it'll work. The arguments object has both of these things, so these functions will work on it.
The slice function returns an Array which is a shallow copy of whatever object was passed into it, starting and ending at whatever numbers you specify. We tell it to start at zero, and because we didn't say where to stop, it assumes we want it to stop at the end, wherever that might be. This way, we copy all of the elements of arguments into a new Array, and now you can do whatever other Array things you want with it.
I have a simple example on python:
programs = {}
if not programs.has_key(( program, time )):
programs[( program, time )] = 0
programs[( program, time )] = programs[( program, time )] + 1
How to use array as key in Javascript ?
This will "work". (but I don't recommend it)
var a = {};
var b = [1,2,3];
a[b] = 'hello';
// a[b] evaluates to 'hello'
// a[[1,2,3]] evaluates to 'hello'
// a['1,2,3'] evaluates to 'hello'
It works because when you pass the array [1,2,3] as the hash (map/associative-array) key, is being converted to the string '1,2,3' before performing the hash lookup. It should suit your needs as long as you don't need two different arrays of the same value to map to different hash values.
var c = [1,2,3]
// a[c] evaluates to 'hello' even though we never executed a[c] = 'hello'
// but b == c evaluates to false
// b & c are two separate objects with the same values, so when they
// get converted to a string for hashing, they return the same value from the hash
As it was mentioned, you'll need more than the standard JavaScript hash if you want to use object references as your keys.
Update
Based on the comment from #speedplane:
I suspect that JS calls toString() on the array when you pass it into a hash key. So you can easily test what you're actually going to get as your key:
["x", "y", "z"].toString(); // 'x,y,z'
["x,y,z"].toString(); // 'x,y,z'
[1,2,3].toString(); // '1,2,3'
[1,2,'3'].toString(); // '1,2,3'
[[1],[2],[3]].toString(); // '1,2,3'
[["x",1], ["y",2], ["z",3]].toString(); // 'x,1,y,2,z,3'
So again, I recommend that you don't do this unless you really understand what is going on. And even then, I wouldn't do it.
JavaScript keys are strings.
You need a WeakMap, or a custom method to map arrays to other objects.
I've written a library called array-keyed-map for doing this robustly in modern JavaScript. Unlike the other answers so far posted, it does not rely on serialising values into strings, but instead uses ES2015 Map objects, which can accept arbitrary values as keys.
I'll quote my answer to a different question for an implementation overview, so the method is preserved posterity in case the library disappears for some reason, or you want to implement it yourself:
Maintain a tree of Map objects. Each tree stores:
Under an internally-declared Symbol key: The value at that point in the tree (if any). The Symbol guarantees uniqueness, so no
user-provided value can overwrite this key.
On all its other keys: all other so-far set next-trees from this tree.
For example, on akmap.set(['a', 'b'], true), the internal tree
structure would be like—
'a':
[value]: undefined
'b':
[value]: true
Doing akmap.set(['a'], 'okay') after that would just change the
value for the path at 'a':
'a':
[value]: 'okay'
'b':
[value]: true
To get the value for an array, iterate through the array while reading
the corresponding keys off the tree. Return undefined if the tree
at any point is non-existent. Finally, read the internally declared
[value] symbol off the tree you've gotten to.
To delete a value for an array, do the same but delete any values
under the [value]-symbol-key, and delete any child trees after the
recursive step if they ended up with a size of 0.
Why a tree? Because it's very efficient when multiple arrays have the
same prefixes, which is pretty typical in real-world use, for working
with e.g. file paths.
Will this do the trick for you?
jsfiddle
<script>
var ary = {person1:'valerie', person2:'alex'};
for (key in ary) {
document.write(key, '<br>')
}
document.write(ary['person2'], '<br>')
</script>