how to loop through an array with nested objects using jquery? - javascript

if I have an array like this:
var msg = [ {name: ["a1", "a2"], value: "this is A"},
{name: ["b1", "b2"], value: "this is B"},
...
]
The array contains global errors messages for client-side form validations. I have managed to pass in faulty inputs (e.g. "a1") and now am wondering how to get the corresponding message out of my ill-constructed array.
Question
What would be the best way to loop through this array? for example, if I have "a1" as parameter passed into my function, how do I extract "this is A" as corresponding message?
inArray doesn't really help, because I need the corresponding message and not the position of a1. I'm also not sure if this is the best way to store my error messages... ideas welcome!
Thanks for help!

Re-arrange your data structure:
var my_param = 'b1';
// This is an object, so we can have key/value pairs
var error_codes =
{
'a1': 0,
'a2': 0,
'b1': 1,
'b2': 1
};
// This is an array because we only need values
var error_messages =
[
'This is A',
'This is b'
];
alert(error_messages[error_codes[my_param]]);
This makes it really easy to set up new error codes and messages, and is extremely easy to understand. The only gotcha is error_codes[my_param] - it's an object, but we can't do error_codes.my_param because it'll look for the element called 'my_param', so using array notation, we can look up the object key.
The only other potential trap is making sure you don't have any trailing commas:
var error_codes = { 'a1': 1, }; // NO!
Also knows as the trailing comma of death!

This would be how I'd do it
var myMsg = findMsg('a1')
function findMsg(msgType){
msg.forEach(function(obj){
if(inArray(msgType, obj.name) !== -1){
return obj.value
}
})
}
function inArray(key, obj){
return obj.join().indexOf(key)
}

$.each is the jQuery way for taking action on each element of an array or each enumerable property of an object.
var value;
$.each(msg, function (i, el) {
if (el.name.indexOf(name) >= 0) {
value = el.value;
return false; // Stops iteration.
}
});
If name is "a1" then after running the above, value === "this is A".

Nice and simple:
var getMessage = function (name)
{
var msg = [ ... ];
for(var i = 0; i < msg.length; ++ i)
if (msg [i].name.indexOf (name) != -1)
return msg [i].value;
}
Returns either the corresponding message or undefined if the name wasn't found.
You may need a shim for indexOf depending on which browsers you want to support:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf

Related

Is there a fast way to select item from array of objects in Javascript?

I have an array:
[
{
key: 'some key',
value: 'some value'
}, {
...
}, ...
]
Is there any simple way to get a certain element of this array without iterating through it and comparing each actual key with desired one?
I currently have a function
var select = function(what, from) {
for (var i in from) {
if (from[i].key == what) {
return from[i];
}
}
return null;
};
I believe there's a better way to handle it.
The short answer is no. There are lots of options to make your code cleaner - like all of the above - but you are still going to have to iterate through them one by one.
You can do 2 things to make it better:
Convert to Map
If you are going to do the search more than once or twice, then convert it to a map of the keys, so at least each subsequent lookup is O(1) instead of O(n). A number of answers suggested that - I use it a lot in my own code - but here is a basic version (there is a shorthand un underscore/lodash):
var i, hash = {};
for (i = 0; i < arr.length; i++) {
hash[arr[i].key] = arr[i].value;
}
Then for all future lookups it is a simple:
var value = hash[key];
Search Algorithms
If it needs to stay as an array for whatever reason, and you have some knowledge about what that array's values will be like, you can use all sorts of search algorithms. Cycling through them one by one is good for an even distribution, but will still be O(n), which will, on average require cycling through half the array (n/2) each time.
But search algorithms are beyond this post...
You were close. This would be the fastest form in this particular case:
var select = function(key, expected, from) {
var i;
for (i = 0; i < from.length; i += 1) {
if (from[i][key] === expected) {
return from[i];
}
}
return null;
};
select('thing', 'foo', [{thing: 'foo'}]);
// => {thing: 'foo'}
But do you require maximum speed? Or would a more elegant, general-purpose solution suit you? If so, use a predicate:
var find = function (array, predicate) {
var i;
for (i = 0; i < array.length; i += 1) {
if (predicate(array[i])) {
return array[i];
}
}
return null;
};
// Find, in an array, an item which passes the following truth test.
find([{thing: 'foo'}], function (item) {
return item.thing === 'foo';
});
// => {thing: 'foo'}
If you don't like writing boilerplate utility code like this, I recommend leveraging a library like lodash. It has a find method already and it's faster and more powerful than anything we could come up with.
Unfortunately not, however, if you alter your structure to use properties it will be much faster. Any other approach will require iteration over the array and will therefore always be less efficient than the below.
var keyValueObj = {
someKey: 'someValue',
nextKey: 'nextValue'
}
// represents 'someValue'
keyValueObj['someKey']
If you're using modern browsers, this should do the magic:
function include(arr,obj) {
return (arr.indexOf(obj) != -1);
}
or in jquery
$.inArray(value, array)
In response to your comment, check this link, this will also address your problem in the comment.
If your keys are strings use them as object properties instead of an array of objects
If your keys are objects use Map()
You can refactor your array into a map, which is, by design, good for quick and effective lookup:
{
'some key': {
value: 'some value'
},
'some other key': {
value: 'some other value'
},
}
Then your select function would be as short as
var select = function(what, from) {
return from[what];
};
If you expect return value of the select() to still have the .key property (which is redundant, as the caller already knows it as what), it is easy to achieve by either keeping the key property in map elements, or auto-adding in in select() before returning.
If you need to run this function very often, I would recommend creating an index:
var yourItemList = [{...}],
select = (function (items) {
var i = 0,
l = items.length,
preparedItems = {};
for (; i < l; ++i) {
preparedItems[items[i].key] = items[i].value;
}
return function (key) {
return preparedItems[key];
};
}(yourItemList));
This way you only iterate once on the item list. After that every select('theKeyYouNeed') just uses the mapped "index".
You can filter array. It is build in Array method so you don't need to declare other helper functions
var arr = [
{
key: 'some key',
value: 'some value'
}, {
key: 'some key1',
value: 'some value'
}
];
arr = arr.filter(function(item) {
return item.key === 'some key'
});
Now arr has only first object (because its key equal to 'some key'). Object that you find is arr[0].
You can use find() instead of filter() when you need just one object. Note, that find() is part of ES6 and has no support in all major browsers

Getting first object from javascript litteral

Lets say I have this object here:
var items = [
{name:"Foo"},
{name:"Bar"},
{name:"foo"},
{name:"bar"},
{name:"foobar"},
{name:"barfoo"}
];
Since it only has one item in each object, I want to just return a list of them.
I tried this:
var getSingle = function(rows){
var items = [];
//This should only return one column
for (var i = 0; i < rows.length; i++) {
var r = rows[i];
var c = 0;
for (var n in r) {
if(c == 0)
items.push(r[n]);
c += 1;
}
}
return items;
}
But it doesn't seem to work. Any thoughts?
PS. name could be anything.
I used a different approach than the others, because I make two assumptions:
1/ you do not know the name of the key, but there is only one key for every item
2/ the key can be different on every item
I will give you a second option, with the second assumption as: 2/ all item have only one key but that's the same for all of them
First Options :
var items = [
{name:"Foo"},
{name:"Bar"},
{name:"foo"},
{name:"bar"},
{name:"foobar"},
{name:"barfoo"}
];
// object keys very simple shim
Object.keys = Object.keys || function(o) {
var result = [];
for(var name in o) {
if (o.hasOwnProperty(name))
result.push(name);
}
return result;
};
// function to get the value of every first keys in an object
// just remember that saying "first key" does not make real sense
// but we begin with the assumption that there IS ONLY ONE KEY FOR EVERY ITEM
// and this key is unknown
function getFirstKeysValues(items) {
var i = 0, len = items.length, item = null, key = null, res = [];
for(i = 0; i < len; i++) {
item = items[i];
key = Object.keys(item).shift();
res.push(item[key]);
}
return res;
}
console.log(getFirstKeysValues(items)); //["Foo", "Bar", "foo", "bar", "foobar", "barfoo"]
Second options will use a map, because we believe that every child possess the same key (I wouldn't use this one, because I do not like .map that much - compatibility):
var items = [
{name:"Foo"},
{name:"Bar"},
{name:"foo"},
{name:"bar"},
{name:"foobar"},
{name:"barfoo"}
];
// object keys very simple shim
Object.keys = Object.keys || function(o) {
var result = [];
for(var name in o) {
if (o.hasOwnProperty(name))
result.push(name);
}
return result;
};
// function to get the value of every first keys in an object
// just remember that saying "first key" does not make real sense
// but we begin with the asumption that there IS ONLY ONE KEY FOR EVERY ITEM
// and this key is unknown but the same for every child
function getFirstKeysValues(items) {
var key = items.length > 0 ? Object.keys(items[0]).shift() : null;
items = items.map(function (item) {
return item[key];
});
return items;
}
console.log(getFirstKeysValues(items));
This is usually accomplished using the map method, see the documentation here.
var justNamesArray = items.map(function(elem) { return elem.name});
The documenation page also includes a useful shim, that is a way to include it in your code to support older browsers.
Accompanying your request in the edit, if you would just like to get those that contain this property there is a nifty filter method.
var valuesWithNamePropert= items.filter(function(elem) { return elem.hasOwnProperty("name")});
You can chain the two to get
var justNamesWhereContains = items.filter(function(elem) { return elem.hasOwnProperty("name")}).
.map(function(elem) { return elem.name});
This approach (mapping and filtering), is very common in languages that support first order functions like JavaScript.
Some libraries such as underscore.js also offer a method that does this directly, for example in underscore that method is called pluck.
EDIT: after you specific that the property can change between objects in the array you can use something like:
var justReducedArray = items.map(function(elem) { for(i in elem){ return elem[i]}});
your var items = [] is shadowing your items parameter which already contains data. Just by seeing your code I thought that maybe your parameter should be called rows
If you're in a world >= IE9, Object.keys() will do the trick. It's not terribly useful for the Array of Objects, but it will help for the iteration of the Array (you would use Array.forEach to iterate the array proper, but then you would use the Object.keys(ob)[0] approach to get the value of the first property on the object. For example:
var someArr = [{ prop1: '1' },{ prop2: '2' },{ prop3: '3' }];
var vals = [];
someArr.forEach( function(obj) {
var firstKey = Object.keys(obj)[0];
vals.push(obj[firstKey]);
});
//vals now == ['1','2','3']
Obviously this isn't null safe, but it should get you an array of the values of the first property of each object in the original array. Say that 3 times fast. This also decouples any dependency on the name of the first property--if the name of the first property is important, then it's a trivial change to the forEach iteration.
You can override the Array.toString method for items, so using String(items) or alert(items) or items+='' will all return the string you want-
var items = [{name:"Foo"}, {name:"Bar"},{name:"foo"},
{name:"bar"},{name:"foobar"},{name:"barfoo"}];
items.toString= function(delim){
delim=delim || ', ';
return this.map(function(itm){
return itm.name;
}).join(delim);
}
String(items)
/* returned value: (String)
Foo, Bar, foo, bar, foobar, barfoo
*/
instead of the default string-'[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]'

Element with largest numeric index

How do I find the last element in a JavaScript object, if by "last" I consider the one with the largest index? I.e. I am receiving an object similar to an array over ajax (as json), but it also has a non-numeric key:
var received = {
0: 'something',
1: 'something else',
2: 'some stuff',
3: 'some more stuff',
'crap' : 'this screws the whole thing'
}
If it were a plain array, I would use array.length. Similarly, I can simply iterate element by element to find it.
Is there a better way? If jQuery is needed for the solution, that's also fine.
This works like the codes from zzzzBov and David Müller, but uses library functions do make it much shorter:
Math.max.apply(null, Object.keys(test).filter(isFinite)) // 3
If you have objects with enumerably-extended prototype objects (which is not the case for JSON.parse results) you might want to use Object.getOwnPropertyNames instead.
This is not an array, it's an object literal. Moreover, the order of items in object literal is not guaranteed to be preserved after creation (although most browsers seem to obey that).
That being said, generally the answer to your question is: you can't. What you can do is iterating over all properties and finding the last one or whichever you are interested in (see: How to Loop through plain JavaScript object with objects as members?). But remember that the order in which the properties are declared does not have to be preserved during iteration.
However, if this was a true array (disregarding the 'crap' key), that's pretty easy:
received = [
'something',
'something else',
'some stuff',
'some more stuff'
];
var last = received[received.length - 1];
With arrays (which are created with [], not {}), the length property is one more than the last index assigned. So:
var a = [];
a[0] = 'something';
a[5] = 'else';
a["foo"] = 'bar';
console.log(a.length);
will print "6", even though there are only two elements of the array and even though the foo property was set to 'bar'. The length property is only affected by numeric indexes.
var received = {
0: 'something',
2: 'some stuff',
3: 'some more stuff',
1: 'something else',
'crap' : 'this screws the whole thing'
};
var prop,
max = -1;
for ( prop in received ) {
if ( Object.prototype.hasOwnProperty.call(received, prop) && !isNaN(prop) ) {
max = Math.max(max, prop);
}
}
console.log(max);
This is of course not the most elegant approach, but you don't have another choice if have to stick to the literal
<script>
var received = {
0: 'something',
1: 'something else',
2: 'some stuff',
3: 'some more stuff',
'crap' : 'this screws the whole thing'
};
var max = null;
for (var i in received)
{
if (received.hasOwnProperty(i) && !isNaN(i))
{
if (max == null || i > max)
max = i;
}
}
if (max)
alert(received[max]); //some more stuff
</script>
If you want to know which item has the greatest numeric index value, you'd have to iterate over all the keys in the object:
(function () {
var i,
o,
temp;
o = getYourObject();
temp = -Infinity; //lowest possible value
for (i in o) {
if (o.hasOwnProperty(i) &&
!isNaN(i) &&
+i > temp) {
temp = +i;
}
}
console.log(temp); //this is the key with the greatest numeric value
}());

Javascript search inside a JSON object

I had a JSON string / object in my application.
{"list": [
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]}
I had a filter box in my application, and when I type a name into that box, we have to filter the object and display the result.
For example, if the user types "name" and hits search, then we have to search full names in the JSON object and return the array, just like a MySQL search ...
My question is to filter the json object with string and return the array....
You could just loop through the array and find the matches:
var results = [];
var searchField = "name";
var searchVal = "my Name";
for (var i=0 ; i < obj.list.length ; i++)
{
if (obj.list[i][searchField] == searchVal) {
results.push(obj.list[i]);
}
}
If your question is, is there some built-in thing that will do the search for you, then no, there isn't. You basically loop through the array using either String#indexOf or a regular expression to test the strings.
For the loop, you have at least three choices:
A boring old for loop.
On ES5-enabled environments (or with a shim), Array#filter.
Because you're using jQuery, jQuery.map.
Boring old for loop example:
function search(source, name) {
var results = [];
var index;
var entry;
name = name.toUpperCase();
for (index = 0; index < source.length; ++index) {
entry = source[index];
if (entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1) {
results.push(entry);
}
}
return results;
}
Where you'd call that with obj.list as source and the desired name fragment as name.
Or if there's any chance there are blank entries or entries without names, change the if to:
if (entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1) {
Array#filter example:
function search(source, name) {
var results;
name = name.toUpperCase();
results = source.filter(function(entry) {
return entry.name.toUpperCase().indexOf(name) !== -1;
});
return results;
}
And again, if any chance that there are blank entries (e.g., undefined, as opposed to missing; filter will skip missing entries), change the inner return to:
return entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1;
jQuery.map example (here I'm assuming jQuery = $ as is usually the case; change $ to jQuery if you're using noConflict):
function search(source, name) {
var results;
name = name.toUpperCase();
results = $.map(source, function(entry) {
var match = entry.name.toUpperCase().indexOf(name) !== -1;
return match ? entry : null;
});
return results;
}
(And again, add entry && entry.name && in there if necessary.)
You can simply save your data in a variable and use find(to get single object of records) or filter(to get single array of records) method of JavaScript.
For example :-
let data = {
"list": [
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]}
and now use below command onkeyup or enter
to get single object
data.list.find( record => record.name === "my Name")
to get single array object
data.list.filter( record => record.name === "my Name")
Use PaulGuo's jSQL, a SQL like database using javascript. For example:
var db = new jSQL();
db.create('dbname', testListData).use('dbname');
var data = db.select('*').where(function(o) {
return o.name == 'Jacking';
}).listAll();
I adapted regex to work with JSON.
First, stringify the JSON object. Then, you need to store the starts and lengths of the matched substrings. For example:
"matched".search("ch") // yields 3
For a JSON string, this works exactly the same (unless you are searching explicitly for commas and curly brackets in which case I'd recommend some prior transform of your JSON object before performing regex (i.e. think :, {, }).
Next, you need to reconstruct the JSON object. The algorithm I authored does this by detecting JSON syntax by recursively going backwards from the match index. For instance, the pseudo code might look as follows:
find the next key preceding the match index, call this theKey
then find the number of all occurrences of this key preceding theKey, call this theNumber
using the number of occurrences of all keys with same name as theKey up to position of theKey, traverse the object until keys named theKey has been discovered theNumber times
return this object called parentChain
With this information, it is possible to use regex to filter a JSON object to return the key, the value, and the parent object chain.
You can see the library and code I authored at http://json.spiritway.co/
If you are doing this in more than one place in your application it would make sense to use a client-side JSON database because creating custom search functions that get called by array.filter() is messy and less maintainable than the alternative.
Check out ForerunnerDB which provides you with a very powerful client-side JSON database system and includes a very simple query language to help you do exactly what you are looking for:
// Create a new instance of ForerunnerDB and then ask for a database
var fdb = new ForerunnerDB(),
db = fdb.db('myTestDatabase'),
coll;
// Create our new collection (like a MySQL table) and change the default
// primary key from "_id" to "id"
coll = db.collection('myCollection', {primaryKey: 'id'});
// Insert our records into the collection
coll.insert([
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]);
// Search the collection for the string "my nam" as a case insensitive
// regular expression - this search will match all records because every
// name field has the text "my Nam" in it
var searchResultArray = coll.find({
name: /my nam/i
});
console.log(searchResultArray);
/* Outputs
[
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]
*/
Disclaimer: I am the developer of ForerunnerDB.
Here is an iterative solution using object-scan. The advantage is that you can easily do other processing in the filter function and specify the paths in a more readable format. There is a trade-off in introducing a dependency though, so it really depends on your use case.
// const objectScan = require('object-scan');
const search = (haystack, k, v) => objectScan([`list[*].${k}`], {
rtn: 'parent',
filterFn: ({ value }) => value === v
})(haystack);
const obj = { list: [ { name: 'my Name', id: 12, type: 'car owner' }, { name: 'my Name2', id: 13, type: 'car owner2' }, { name: 'my Name4', id: 14, type: 'car owner3' }, { name: 'my Name4', id: 15, type: 'car owner5' } ] };
console.log(search(obj, 'name', 'my Name'));
// => [ { name: 'my Name', id: 12, type: 'car owner' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan
You can filter json object using any value from any property using this library
Js-Search
You can try this:
function search(data,search) {
var obj = [], index=0;
for(var i=0; i<data.length; i++) {
for(key in data[i]){
if(data[i][key].toString().toLowerCase().indexOf(search.toLowerCase())!=-1) {
obj[index] = data[i];
index++;
break;
}
}
return obj;
}
console.log(search(obj.list,'my Name'));

Is array both associative and indexed?

Can an array in JavaScript be associative AND indexed?
I'd like to be able to lookup an item in the array by its position or a key value.
There are no such things as associative arrays in Javascript. You can use object literals, which look like associative arrays, but they have unordered properties. Regular Javascript arrays are based on integer indexes, and can't be associative.
For example, with this object:
var params = {
foo: 1,
bar: 0,
other: 2
};
You can access properties from the object, for example:
params["foo"];
And you can also iterate over the object using the for...in statement:
for(var v in params) {
//v is equal to the currently iterated property
}
However, there is no strict rule on the order of property iteration - two iterations of your object literal could return the properties in different orders.
After reading the Wikipedia definition of associative array, I'm going to break with traditional JavaScript lore and say, "yes, JavaScript does have associative arrays." With JavaScript arrays, you can add, reassign, remove, and lookup values by their keys (and the keys can be quoted strings), which is what Wikipedia says associative arrays should be able to do.
However, you seem to be asking something different--whether you can look up the same value by either index or key. That's not a requirement of associative arrays (see the Wikipedia article.) Associative arrays don't have to give you the ability to get a value by index.
JavaScript arrays are very closely akin to JavaScript objects.
arr=[];
arr[0]="zero";
arr[1]="one";
arr[2]="two";
arr["fancy"]="what?";
Yes, that's an array, and yes, you can get away with non-numeric indices. (If you're curious, after all this, arr.length is 3.)
In most cases, I think you should stick to numeric indices when you use arrays. That what most programmers expect, I think.
The link is to my blog post about the subject.
Native JS objects only accept strings as property names, which is true even for numeric array indices; arrays differ from vanilla objects only insofar as most JS implementations will store numerically indexed properties differently (ie in an actual array as long as they are dense) and setting them will trigger additional operations (eg adjustment of the length property).
If you're looking for a map which accepts arbitrary keys, you'll have to use a non-native implementation. The script is intended for fast iteration and not random-access by numeric indices, so it might nor be what you're looking for.
A barebones implementation of a map which would do what you're asking for could look like this:
function Map() {
this.length = 0;
this.store = {};
}
Map.prototype.get = function(key) {
return this.store.hasOwnProperty(key) ?
this.store[key] : undefined;
};
Map.prototype.put = function(key, value, index) {
if(arguments.length < 3) {
if(this.store.hasOwnProperty(key)) {
this.store[key].value = value;
return this;
}
index = this.length;
}
else if(index >>> 0 !== index || index >= 0xffffffff)
throw new Error('illegal index argument');
if(index >= this.length)
this.length = index + 1;
this[index] = this.store[key] =
{ index : index, key : key, value : value };
return this;
};
The index argument of put() is optional.
You can access the values in a map map either by key or index via
map.get('key').value
map[2].value
var myArray = Array();
myArray["first"] = "Object1";
myArray["second"] = "Object2";
myArray["third"] = "Object3";
Object.keys(myArray); // returns ["first", "second", "third"]
Object.keys(myArray).length; // returns 3
if you want the first element then you can use it like so:
myArray[Object.keys(myArray)[0]]; // returns "Object1"
The order in which objects appear in an associative javascript array is not defined, and will differ across different implementations. For that reason you can't really count on a given associative key to always be at the same index.
EDIT:
as Perspx points out, there aren't really true associative arrays in javascript. The statement foo["bar"] is just syntactic sugar for foo.bar
If you trust the browser to maintain the order of elements in an object, you could write a function
function valueForIndex(obj, index) {
var i = 0;
for (var key in obj) {
if (i++ == index)
return obj[key];
}
}
var stuff = [];
stuff[0] = "foo";
stuff.bar = stuff[0]; // stuff.bar can be stuff["bar"] if you prefer
var key = "bar";
alert(stuff[0] + ", " + stuff[key]); // shows "foo, foo"
I came here to wanting to know if this is bad practice or not, and instead found a lot of people appearing not to understand the question.
I wanted to have a data structure that was ordered but could be indexed by key, so that it wouldn't require iteration for every lookup.
In practical terms this is quite simple, but I still haven't read anything on whether it's a terrible practice or not.
var roygbiv = [];
var colour = { key : "red", hex : "#FF0000" };
roygbiv.push(colour);
roygbiv[colour.key] = colour;
...
console.log("Hex colours of the rainbow in order:");
for (var i = 0; i < roygbiv.length; i++) {
console.log(roygbiv[i].key + " is " + roygbiv[i].hex);
}
// input = "red";
console.log("Hex code of input colour:");
console.log(roygbiv[input].hex);
The important thing is to never change the value of array[index] or array[key] directly once the object is set up or the values will no longer match. If the array contains objects you can change the properties of those objects and you will be able to access the changed properties by either method.
Although I agree with the answers given you can actually accomplish what you are saying with getters and setters. For example:
var a = [1];
//This makes a["blah"] refer to a[0]
a.__defineGetter__("blah", function(){return this[0]});
//This makes a["blah"] = 5 actually store 5 into a[0]
a.__defineSetter__("blah", function(val){ this[0] = val});
alert(a["blah"]); // emits 1
a["blah"] = 5;
alert(a[0]); // emits 5
Is this what you are looking for? i think theres a different more modern way to do getters and setters but cant remember.
The tide has changed on this one. Now you can do that... and MORE! Using Harmony Proxies you could definitely solve this problem in many ways.
You'll have to verify that your targeted environments support this with maybe a little help from the harmony-reflect shim.
There's a really good example on the Mozilla Developer Network on using a Proxy to find an array item object by it's property which pretty much sums it up.
Here's my version:
var players = new Proxy(
[{
name: 'monkey',
score: 50
}, {
name: 'giraffe',
score: 100
}, {
name: 'pelican',
score: 150
}], {
get: function(obj, prop) {
if (prop in obj) {
// default behavior
return obj[prop];
}
if (typeof prop == 'string') {
if (prop == 'rank') {
return obj.sort(function(a, b) {
return a.score > b.score ? -1 : 1;
});
}
if (prop == 'revrank') {
return obj.sort(function(a, b) {
return a.score < b.score ? -1 : 1;
});
}
var winner;
var score = 0;
for (var i = 0; i < obj.length; i++) {
var player = obj[i];
if (player.name == prop) {
return player;
} else if (player.score > score) {
score = player.score;
winner = player;
}
}
if (prop == 'winner') {
return winner;
}
return;
}
}
});
console.log(players[0]); // { name: 'monkey', score: 50 }
console.log(players['monkey']); // { name: 'monkey', score: 50 }
console.log(players['zebra']); // undefined
console.log(players.rank); // [ { name: 'pelican', score: 150 },{ name: 'giraffe', score: 100 }, { name: 'monkey', score: 50 } ]
console.log(players.revrank); // [ { name: 'monkey', score: 50 },{ name: 'giraffe', score: 100 },{ name: 'pelican', score: 150 } ]
console.log(players.winner); // { name: 'pelican', score: 150 }
The latest MDN documentation makes it quiet clear that Array index must be integers.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
let arr=[];
arr[0]="zero";
arr[1]="one";
arr[2]="two";
arr["fancy"]="what?";
//Arrays cannot use strings as element indexes (as in an associative array) but must use integers.
//Setting non-integers using bracket notation will not set an element to the Array List itself
//A non-integer will set a variable associated with that ARRAY Object property collection
let denseKeys = [...arr.keys()];
console.log(denseKeys);//[ 0, 1, 2 ]
console.log("ARRAY Keys:"+denseKeys.length);//3
let sparseKeys = Object.keys(arr);
console.log(sparseKeys);//[ '0', '1', '2', 'fancy' ]
console.log("Object Keys:"+sparseKeys.length);//4
const iterator = arr.keys();
for (const key of iterator) {
console.log(key);//0,1,2
}
Yes.
test = new Array();
test[0] = 'yellow';
test['banana'] = 0;
alert(test[test['banana']]);

Categories