Javascript for-in loop issue - javascript

I'm doing codecademy right now and I'm having an issue with one lesson involving for-in loops. The requirement for thi exercise is to log "bill" and "steve to the console. However, I'm getting the entire array except those two strings logged instead. What's going on here?
var friends = {
bill: {firstName: "Bill",
lastName: "Ferny",
number: "452-556-5412",
address: ['One Bree Hill', 'Bree', 'Middle Earth', '00000']
},
steve: {firstName:"Steve",
lastName:"Rogers",
number:"805-223-5568",
address: ['1500 Settlers Court', 'Paso Robles', 'CA', '93446']
}
};
var list = function (friends) {
for (var p in friends) {
console.log(friends[p]);
}
};
list(friends);

change console.log(friends[p]); into console.log(friends[p].firstName);.

In a for-in loop, the variable is set to the property names. So if you want to log the property name, use console.log(p). friends[p] is the value that the property name maps to in the object.

You need to specify what you want even further.
This:
console.log(friends[p]);
should be changed to this:
console.log(friends[p].firstName);
Your code is only getting you all of the properties associated with friends[bill] and friends[steve]. You want their first names, so you have to use dot notation and add .firstName to the end of your console.log() statements.
As other people have noted, you can also use console.log(p) which logs the property name (so bill and steve), but since you are on Codecademy, I think they'll want you to use the first method I mentioned.

Related

How to limit the usage of "===" operator in javascript for specific object property

For example, the following two javascript object have properties include "name", "age" and "phoneNumber".
const personA = {
name: Andy,
age: "24",
phoneNumber: "28173516374"
}
const personB = {
name: "Amy",
age: 25,
phoneNumber: "+85 28173516374"
}
For the property "phoneNumber", I don't want others use it with operator "===" to compare with other string like personA.phoneNumber === personB.phoneNumber, because for the value of a phoneNumber, it should be the same either with or without a prepended country code. For other developers who don't have this knowledge background, they possibly use === to do the compare between two variable with value of a phone number and it will raise some bugs.
So I need a way to limit the usage of === on specific property. I have came up with several solutions, but they still have more or less disadvantage.
Solution 1: Transform the type of all properties which represents a phone number from string to an class PhoneNumber, this class will handle all the comparation and value formatting. However, I have to use new to create that object and should modify many places. Because this property is used everywhere in my project. After trying several times, I forgave applying this solution.
Solution2: Use a common function to compare two phone number. As I have said before, not all developers and reviewers know that function. Even if I address it in document, still have someone forget that.
Now I am trying to develop an eslint rules to limit the usage of === on specific property. Do you have other idea?
Sorry for my weak English.
If the task is to control who can read the field value and who cannot, then this can be solved in several ways.
If you can change the structure of the Object, then getters and setters are suitable for you.
MDN: Getter MDN: Setter
A simplified example solution would look like this:
{
let admin;
const personA = {
age: "24",
sex: "man",
privateName: "Jhon",
get name() {
return (admin === true ? this.privateName : "***");
},
set name(v) {
return (admin === true ? this.privateName = v : "***")
}
}
admin = false;
personA.name = "Mary"
console.log(personA.name)
admin = true;
console.log(personA.name)
personA.name = "Mary"
console.log(personA.name)
}
Instead of outputting ***, we can return an exception.
If you cannot change the structure, then the same can be done using a proxy.
MDN: Proxy
If you cannot use a proxy, then you can change the behavior of the object's properties using
Object.defineProperty. That is, set the same getters and setters on an already existing object.
MDN: Object.defineProperty

Simple object properties access in a for in JS loop

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.

JavaScript remove string from a value within an object

I have an object:
let Data = {name: 'Flomo', age: 25, address: 'Sinkor', id: 'NMF25'}
I want to console log the entire object but the id value should only contain the last three characters.
Like this:
{name: 'Flomo', age: 25, address: 'Sinkor', id: 'F25'}
I'm doing this:
console.log(Data.replace(/NM/g, ''))
But I got:
TypeError: Data.replace is not a function
Is there an easy way to achieve this?
replace is a method that operates on String, and doesn't change the string in-place.
If you're not worried about changing the original data, you can do this:
let Data = {name: 'Flomo', age: 25, address: 'Sinkor', id: 'NMF25'}
Data.id = Data.id.replace('NM', '')
console.log(Data);
Alternatively, if you're not sure what the first characters of the id will be (or how many there could be), you could do this:
let Data = {name: 'Flomo', age: 25, address: 'Sinkor', id: 'NMF25'}
Data.id = Data.id.substring(Data.id.length-3)
console.log(Data);
If you need to keep the original data intact, you can copy the object, however this can be complicated depending on the data that might be in the object: How do I correctly clone a JavaScript object?
The replace function works on a String. Youre calling that function on an Object.
You probably intended to call replace on the value of the property id. The terms I just used should help you mentally step thru problems like this in the future!
If you look at MDN's documentation for JavaScript, you'll see which functions you can call on which Types and other objects.

Understanding for in loop (javascript)

Im kinda new to JS and I'm trying to understand how for/in loop really works, here's some sample code:
phoneBook = {};
phoneBook.bill = { name : "bill", lastName "hayder" };
phoneBook.steve = { name : "steve", lastName "garcia" };
for ( obj in phoneBook )
{
console.log(obj);
};
When I run this code I get bill and steve as an output, my question is if that's what the iterator holds why I am allowed to do phoneBook[obj] and work with that?? If I type manually phoneBook[bill] I get an error, I can only phoneBook.bill or phoneBook["bill"].
Thanks for helping.
When you write phonebook[something] it means that something should be an expression that returns a string, and it should find the property whose name is that string.
In the case of phonebook[obj], the value of the variable obj will be the string "bill" or "steve", and it will then look up the corresponding property.
If you write phonebook[bill], it tries to use bill as a variable name, and expects it to contain a string that names a property. But there is no variable named bill, so this gets an error.
Javascript objects are simply key-value pairs.
phoneBook = {};
phoneBook.bill = { name : "bill", lastName: "hayder" };
phoneBook.steve = { name : "steve", lastName: "garcia" };
In this example, the phoneBook object has two key-value properties, bill and steve. But the properties themselves are objects, each containing the properties name and lastName.
Key-value pairs can be accessed via two ways: the object way and the dictionary way. Object way means accessing via phoneBook.bill, and dictionary way means accessing via phoneBook['bill']. Notice that using a dictionary way means simply passing the property name to the object.
Now, phoneBook[bill] is invalid because JS thinks that bill is a variable, and tries to find this. That's why you should use phoneBook['bill'] or phoneBook["bill"]. You can use this dictionary form, but I suggest you use the phoneBook.bill method.
I hope I answered your question. :)
some syntax errors fixed
phoneBook = {};
phoneBook.bill = { name: "bill", lastName: "hayder" };
phoneBook.steve = { name: "steve", lastName: "garcia" };
for (obj in phoneBook)
{
console.log(obj);
};
Javascript basics
phoneBook has a property bill
In javascript this property bill can be referenced using
phoneBook.bill
phoneBook['bill']
when you reference phoneBook[bill] you will recieve an error because javascript is looking for a variable that contains the string bill
what you can do is try it this way
var bill = 'bill';
phoneBook[bill]

Retrieving JS' Object value without knowing it's name

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.

Categories

Resources