I'm learning OOP and am curious to discover why my code isn't looping through all the object instances and logging out the 'firstName' property - check out my demo below:
var people = {
"person1" : {
"firstName": "John"
, "lastName": "Smith"
, "age" : 25
, "checkedin" : true
},
"person2" : {
"firstName": "Nick"
, "lastName": "Debruyne"
, "age" : 24
, "checkedin" : false
}
}
// console.log(people); // works correctly
for (let person in people) {
// console.log(person); // works correctly
console.log(person.firstName); // returns undefined
}
Codepen: https://codepen.io/ns91/pen/VwZoegw?editors=1111
This code should just run through each object instance and log the firstName values of each object (being 'John' and 'Nick'). Is there some rookie error I'm doing here?
Also, why does 'undefined' show in the console? I've noticed this happens for other things I log in the console, and even when successful, it still occasionally occurs. Could someone explain the process of what's going on in the browser here, or why it's showing undefined?
And is this JSON or JS? I wonder if it needs to convert into JS to be readable in JS for loops?
Thanks for any advice here.
Your for ... in construct is only giving your loop the keys to each object in the people object, not the values. You need to change the line to console.log(people[person].firstName);.
The reason you were seeing undefined is that you were asking JavaScript to give you the firstName property of the key - which was just the string John or Nick, not the actual person object, and which did not have any such property.
That is going to be because the for(let x in foo) loop iterates over the keys of the object. To access the value you would have to use bracket syntax like so
foo[x]. Hope this helps.
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.
First I am sorry because this possibly will be very simple. But I work a lot in PHP, but that syntax won't work in JS.
I've got the following pieces of code:
var rangeArr = [];
// This piece is inside an loop of adding elements...
rangeArr[row_id] = {"row_x": row_x, "row_y": row_y, "row_name": row_name, "row_dir": row_dir, "row_length": row_length, "row_height": row_height};
row_id++;
I'll get this object for instance (got from Chrome console):
rangeArr
[undefined × 1,
Object
row_dir: "lr"
row_height: "6"
row_length: "5"
row_name: ""
row_x: 45
row_y: 71
__proto__: Object
,
Object
row_dir: "lr"
row_height: "6"
row_length: "6"
row_name: ""
row_x: 95
row_y: 208
__proto__: Object
]
I'm using the following piece of code to loop through the object array:
for (var item in rangeArr) {
if(typeof(item) !== 'undefined'){
console.log(item.row_x);
}
}
But I only get undefined errors... When I look into the console log, the whole item contains only the row_id. That means that only the index is retrieved, not the object itself.
As I said before, I have got little to no knowledge about JS Objects, but I thought that this was the right way to do this.
So how can I get my piece of code working so that I can receive the data when needed?
In your for in loop, item is actually the array key, not the array element value. To get the object, use rangeArr[item].
for (var item in rangeArr) {
var obj = rangeArr[item];
if(typeof(obj) !== 'undefined'){
console.log(obj.row_x);
}
}
That said, for in loops are a bad idea on arrays. A basic incremental for loop, or a forEach is preferred. Refer to this question for more info.
It looks like you're generating the incremental keys manually. Instead of that, you might prefer to use Array.prototype.push():
rangeArr.push({"row_x": row_x, "row_y": row_y, "row_name": row_name, "row_dir": row_dir, "row_length": row_length, "row_height": row_height});
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 am trying to figure out if I JSON.Stringify an object like this:
{"m_id":"xxx","record":
{"USER":"yyy","PWD","zzz","_createdAt":
11111."_updatedAt":00000},"state":"valid"}
and then try to JSON.Parse out only the USER and PWD, not have to just call the object, but go through stringify. how would that work?
thanks.
I'm not sure why you're talking about stringifying your object. You'd stringify it if you needed to send the data across a network or something, not when you need to manipulate it in JS.
...how do I extract the strings in {...USER: "aaa", PWD: "zzz"...}?
Assuming you have a variable referring to the object, something like the following (with or without nice line breaks and indenting to make it readable, and with or without quotes around the property names):
var obj = {
"m_id": "xxx",
"record": {
"USER": "yyy",
"PWD" : "zzz",
"_createdAt": 11111,
"_updatedAt": 00000
},
"state": "valid"
};
Then you can access the properties in the nested record object as follows:
console.log( obj.record.USER ); // outputs "yyy"
console.log( obj.record.PWD ); // outputs "zzz"
// etc.
(Note: in your question you had two typos, a comma that should've been a colon in between "PWD" and "zzz", and a dot that should've been a comma in between 11111 and "_updatedAt". There's no way that JSON.stringify() would have produced the string that you showed with those mistakes.)
If you want the strings "USER", "PWD" etc as an array, then use Object.keys.
If you want to iterate them, just use a normal for-in enumeration.
I might have misunderstood the question, but if I think it is what it is then try using
var tmp = JSON.parse(string_to_convert)
this should suffice to convert your string to a proper Javascript Object
Then you can do
for(var index in tmp){
console.log(tmp[index]);
}
and this should list all the keys on the first set of properties. If you want to do a nested thing, then use recursion on the properties. Hope this makes sense...
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.