First of all, let me warn you that i am not a javascript guru.
I already found a few questions regarding this topic but almost all of them answer with the same solution.
I have a simple custom javascript object:
var errorMsg ={
msg1 : "x",
msg2 : "y",
msg3 : "z",
msg4 : "t"
}
and i want to get all the properties names from the object like ["msg1","msg2","msg3","msg4"].
Like i told almost solution point to the use of the for/in loop to iterate over all properties name. But my app will run in IE6 and above, and i research that IE does not support this loop or at least the IE6. So what can i do ?
The last question is , where can i find a good javascript reference ? I saw that the Object have a method that returns keys like Object.keys() , where can i find a good reference that gives me all the properties and method related with javascript built in objects ?
You could define a generic method for returning an array of keys from any object,
and use the function's call method to operate on the errorMsg object:
var errorMsg={
msg1:"x",
msg2:"y",
msg3:"z",
msg4:"t"
}
function keyArray(){
var A= [];
for(var p in this){
if(this.hasOwnProperty(p)) A.push(p);
}
return A;
}
keyArray.call(errorMsg)
/* returned value: (Array)
msg1,msg2,msg3,msg4
*/
First, see Does Javascript have an enhanced for loop syntax similar to Java's where we were just discussing this. But since you are using an object instead of an Array here, not all of the answers will apply. Here you will want to be sure that you're using a solution that involves hasOwnProperty.
In terms of a reference, I always use https://developer.mozilla.org/en/JavaScript/Reference. Everything that is listed there is of very high quality. Just beware that not everything listed will apply equally to all browsers.
If for-in is no option, you could use an array containing message objects. You can use a standard for loop this way.
var errorMsg = [
{ name : "msg1", value : "x" },
{ name : "msg2", value : "y" },
{ name : "msg3", value : "z" },
{ name : "msg4", value : "t" }
];
You can't access the messages by name any more though - mapping message name to an index in errorMsg might be a workaround for this.
Related
This is a fairly common question here in SO, and I've looked into quite a few of them before deciding to ask this question.
I have a function, hereby called CheckObjectConsistency which receives a single parameter, an object of the following syntax:
objEntry:
{
objCheck: anotherObject,
properties: [
{
//PropertyValue: (integer,string,double,whatever), //this won't work.
PropertyName: string,
ifDefined: function,
ifUndefined: function
}
,...
]
}
What this function does is... considering the given parameter is correctly designed, it gets the objCheck contained within it (var chk = objEntry.objCheck;), It then procedes to check if it contains the properties contained in this collection.
Like this
for(x=0;x<=properties.length;x++){
if(objCheck.hasOwnProperty(properties[x].PropertyName)){
properties[x].ifDefined();
}
else{
properties[x].ifUndefined();
}
What I want is... I want to bring it to yet another level of dynamicity: Given the propositions that IfDefined and IfUndefined are functions to be called, respectively, if the currently-pointed PropertyName exists, and otherwise, I want to call these functions while providing them, as parameters, the very objCheck.PropertyName's value, so that it can be treated before returning to the user.
I'll give a usage example:
I will feed this function an object I received from an external provider (say, a foreign JSON-returning-WebService) from which I know a few properties that may or may not be defined.
For example, this object can be either:
var userData1 = {
userID : 1
userName: "JoffreyBaratheon",
cargo: "King",
age: 12,
motherID : 2,
//fatherID: 5,--Not defined
Status: Alive
}
or
var userData2 = {
userID :
userName: "Gendry",
cargo: "Forger Apprentice",
//age: 35, -- Not Defined
//motherID: 4,-- Not Defined
fatherID: 3,
Status: Alive
}
My function will receive:
var objEntry=
{
objCheck: userData1,
properties: [
{
PropertyName: "age",
ifDefined: function(val){alert("He/she has an age defined, it's "+val+" !");},
ifUndefined: function(){alert("He/she does not have an age defined, so we're assuming 20.");},
},
{
PropertyName: "fatherID",
ifDefined: function(val){alert("He/she has a known father, his ID is "+val+" !");},
ifUndefined: function(){alert("Oh, phooey, we don't (blink!blink!) know who his father is!");},
}
]
}
CheckObjectConsistency(objEntry); // Will alert twice, saying that Joffrey's age is 12, and that his father is supposedly unknown.
ifDefined will only actually work if, instead of properties[x].ifDefined();, I somehow provide it with properties[x].ifDefined(PropertyValue);. And here, at last, lies my question.
Being inside the consistency-checking-function, I only know a given property's name if it's provided. Being inside it, I can't simply call it's value, since there is no such function as properties[x].ifUndefined(properties[x].GetValueFromProperty(properties[x].PropertyName)) ,... is there?
I'm sorry. Not being a native english speaker (I'm brazilian), I can't properly express my doubts in a short way, so I prefer to take my time writing a long text, in an (hopefully not wasted) attempt to make it clearer.
If, even so, my doubt is unclear, please let me know.
I think you're looking for the bracket notation here. It allows you to provide an arbitrary value as key to access the object. Also, you know its name. You have your properties object right?
objEntry.properties.forEach(function(property){
// Check if objCheck has a property with name given by PropertyName
if(!objEntry.objCheck.hasOwnProperty(property.PropertyName)){
// If it doesn't, call isUndefined
property.isUndefined();
} else {
// If it does, call isDefined and passing it the value
// Note the bracket notation, allowing us to provide an arbitrary key
// provided by a variable value to access objCheck which in this case is
// the value of PropertyName
property.isDefined(objEntry.objCheck[property.PropertyName]);
}
});
Oh yeah, forEach is a method of arrays which allows you to loop over them. You can still do the same with regular loops though.
I'm trying to retrieve a nested object based on a nested nested id.
So my object is as follows
object = {
1: {
feature: {id:"1012"},
}
2: {
feature: {id:"3032"}
}
}
I have an id and I need to retrieve the corresponding object or to be more specific the object id. The object is a lot more complex but above shows the values that I need to retrieve.
I don't have much experience in JavaScript so am unsure how to achieve this. I've tried using Jquery's attribute selectors but have not been successful.
Any help would be appreciated.
Thanks.
if your "id" is mean like 1 or 2
do it like this:view it in JSFiddle
var obj = {
1: {
feature: {id:"1012"}
},
2: {
feature: {id:"3032"}
}
}
var getById = function(id){
return obj[id];
}
alert(getById(1).feature.id);
another way,if your id means like '1012','3032'
do it like this:view it in JSFiddle
my post about the Map in js
If I'm understanding the question correctly you are trying to use the id property of the object in each feature property to get the key (1, 2, etc) from object? So if you entered "1012" you would get back 1, if you entered "3032" you would get 2, etc?
If so this would do it:
var object = {
1: {
feature: {id:"1012"}
},
2: {
feature: {id:"3032"}
}
},
getIdByFeatureId = function (featureId) {
var id,
subObject;
// loop through each property of the object
for (id in object) {
// protect ourselves in case someone has tampered with Object.prototype
if (object.hasOwnProperty(id)) {
subObject = object[id];
if (subObject.feature.id === featureId) {
return id;
}
}
}
// none found? return null.
return null;
};
getIdByFeatureId("3032"); // returns 2
getIdByFeatureId("1012"); // returns 1
getIdByFeatureId("90210"); // returns null
You can play with the code in this fiddle.
Numbers stored as strings can be a pain, and often lead to confusion in how one need to call a function like this. One thing you might notice is I used the === strict equal operator. This only returns true if both values are exactly the same, including their type. It's good practice to use strict comparison operators unless you absolutely can't. It is also slightly faster since it doesn't have to coerce the values into a like type. But that means that you must pass a string into the function in order for it to match. You could use the non-strict equals == if you need it to be more flexible. If all of the feature ids are numeric (and none of them have leading zeros) and you have the ability to, I would change the feature ids to be actual numbers so you can keep it more intuitive by just passing in a number instead of a string representation of a number: getIdByFeatureId(3032); while keeping the strict comparison.
I have this code:
var string = {
nameString : "nameValue",
nameString2 : "nameValue2",
nameString3 : "nameValue3",
datathing : 0,
};
var data = {
data : 1,
dataNum2 : 2,
dataNum3 : 3,
dataNum4 : 4,
};
var thing = {
datathing1 : 10,
datathing2 : 20,
datathing3 : 30,
datathing4 : 40,
};
var object = {
object1 : string,
data1 : data,
thing1 : thing,
};
Why do neither of these means to access the data work:
alert("testReference= " + object['object1']['string']['nameString']);
alert("testReference= " + object.object1.string.nameString);
I cannot understand it, even though similar examples found below and textbooks state explicitly that they should work:
Accessing nested JavaScript objects with string key
Thanks in advance for any input!
I am currently constructing an object and passing it around, a 'for in' will bring up the values but a 'typeof' test or any other way I try and access will not work, either I will encounter an error (which breaks the program, I think) or I get 'undefined'....
One last thing if this gets solved, is it ok to nest a key that is the same name value as its parent, such as data.data - this leads to the possibility of further nesting such as data.data.data...
Let's look at what's wrong with each example, then take a look at the way that works right.
Example 1
object['object1']['string']['nameString']
We expect object['object1'] to return the object string, right? So lets simplify the big expression by replacing that part of it. That'll make it easier for us to understand.
So now we have string['string']['nameString'].
But string has no member called 'string', so string['string'] returns undefined.
And when you try to treat undefined as an object, you get an error!
Example 2
object.object1.string.nameString
We expect object.object1 returns the object string, right? So lets simplify the big expression by replacing that part of it. That'll make it easier for us to understand.
So now we have string.string.nameString.
But string has no member called 'string', so string.string returns undefined.
And when you try to treat undefined as an object, you get an error!.
What You Want
object.object1.nameString (or object['object1']['nameString'])
We expect object.object1 returns the object string, right? So lets simplify the big expression by replacing that part of it. That'll make it easier for us to understand.
So now we have string.nameString, and we expect that to return "nameValue".
And it does!
I have an object (returned from jQuery ajax) that looks like this:
data:{
materials:{
1:{
id:1,
name:"jacob"
}//1 (some integer)
}//materials
}//data
I'm trying to access name, but I can't get passed the object 1. I tried using makeArray() like this
var m = $.makeArray(data.materials);
var m0 = m.shift();
console.log(m);
console.log(m0);
$isArray(m) & $.isArray(m0) return true, but m and m0 both return:
1:{
id:1,
name:"jacob"
}//1 (some integer)
I expect that shift() to return the object that's inside of 1.
When I try to access m0.name it returns undefined, and when I try to access m[1] it returns undefined.
btw data.materials["1"].name works. the problem is 1 is variable (I don't know what it will be, so I wanted to use shift() which doesn't work on an object).
EDIT: So it seems that there is a limitation within makeArray(): since an object property is not supposed to be named with a number, that function does not convert the rest of the object and the output is some kind of object-array hybrid (on which you cannot use array functions like shift()), so the quick-n-dirty solution I came to was to loop thru it like this:
var m = data.materials,
id;
for ( key in m ) { id = key; }
console.log( m[id].name );
It's not all that clean, so if there's a better way, please let me know.
p.s. The 1:{} is there in the first place because the controller returns multiple "materials" under certain conditions (which will never be true when this js is used).
You should use data.materials["1"].name
http://jsfiddle.net/nq4RE/
Jacob, I see you updated your question.
To use a variable, you simply call data.materials[your_variable_here].name
http://jsfiddle.net/nq4RE/1/
Did you try: data.materials[1].name?
But in my opinion using number as property name is misleading.
I have a JavaScript object that is treated as an associative array. Let's call it "fields". It has several elements, e.g.:
fields['element1'] = ...
fields['element2'] = ...
fields['element3'] = ...
Given fields[0], is it possible to obtain the name of the property (which is "element1") instead of its value?
Let's say you have an object oObject. It could be:
var oObject = {} ;
oObject["aaa"] = "AAA" ;
oObject["bbb"] = "BBB" ;
oObject["ccc"] = "CCC" ;
oObject["ddd"] = "DDD" ;
oObject["eee"] = "EEE" ;
Now, let's say you want to know its properties' names and values, to put into the variable strName and strValue. For that you use the "for(x in o)" construct, as in the following example:
var strName, strValue ;
for(strName in oObject)
{
strValue = oObject[strName] ;
alert("name : " + strName + " : value : " + strValue) ;
}
The "for(x in o)" construct will iterate over all properties of an object "o", and at each iteration, will put in variable "x" the current property name. All you have to do, then, to have its value, is to write o[x], but you already knew that.
Additional info
After some thinking, and after seeing the comment of Hank Gay, I feel additional info could be interesting.
Let's be naive (and forget the "in JavaScript, all objects, including arrays, are associative containers" thing).
You will usually need two kind of containers: Maps and Arrays.
Maps are created as in my example above (using the "o = new Object() ;" or the "o = {} ;" notation, and must be accessed through their properties. Of course, maps being maps, no ordering is guaranteed.
Arrays are created differently, and even if they can be accessed as maps, they should be accessed only through their indices, to be sure order is maintained.
Point is:
If you need a map, use a "new Object()" container
If you need an array, une an array, use a "new Array()" container
Don't EVER mix the two, and don't EVER access the map through indices, and for arrays, ALWAYS access its data through its indices, because if you don't follow those principles, you won't get what you want.
No, for two reasons.
fields[0] and fields["element1"] are different properties.
properties in an object are explicitly unordered
You could loop over the properties:
function (obj) {
for (prop in obj) {
if (obj.hasOwnProperty(prop) {
return prop;
}
}
};
…to get the "first" property for some arbitrary value of "first" that could change at any time.
http://ajaxian.com/archives/fun-with-browsers-for-in-loop explains the hasOwnProperty pattern.
There is no fields[0] (unless fields is an Array object, which supports numerical indices), so you can't get its name just like that. But you can simulate it like this:
function getKey(obj, i) {
var j = 0;
for (var p in obj) {
if (j++ == i) return p;
}
return null;
}
for (var p in obj) will loop through every field name in the object obj. By getting the nth field name, you can effectively get the "key" for a certain index.
Note that while it's working its way to become a standard, the order of field names is currently not guaranteed according to the standards, which means that after modifying the object, the same function call could theoretically return a different field name. Same thing goes that different browsers can return different results. Practically, you'll find that just about all the browsers do keep the order of field names so you shouldn't have to worry about it at all.
Just to point out what is implicit in everyone else's answer: "associative arrays" in Javascript are actually just Object instances, e.g.,
var aa = {};
aa.foo = 'argle';
alert(aa['foo']); // Will alert 'argle'
PLEASE don't use an Array instead of an Object—it has the potential to wreak havoc on for key in aa-style iteration.