The search function in the following code is not working and I believe it has something to do with the For...In loop but I am new to JS and unsure why:
var friends = {
bill: {
firstName: "bill",
lastName: "smith",
number: 1,
address: ["1"]
},
steve: {
firstName: "steve",
lastName: "smith",
number: 2,
address: ["2"]
}
};
var list = function(list) {
for(var item in list) {
console.log(item);
}
};
var search = function(name) {
for(var friend in friends) {
if(friend.firstName === name) {
console.log(friend);
return friend;
}
}
};
search("steve");
The for in loop iterates over keys, not values.
friend is a string holding the name of each property.
To get the value, use friends[friend].
Great documentation of the for..in loop can be found on mdn. Where variable is assigned through each iteration to "a different property name".
You also may not need to loop through each friend. What if you changed your search function to use hasOwnProperty on the object:
var search = function(name) {
if(friends.hasOwnProperty(name)){
return friends[name];
}
};
This would check that you have a property of name in the object friends and return it. Here's a quick EXAMPLE.
Related
I have an array of objects that needs sorting by last name, however the object only has firstname and fullname parameters, so for last name I have to use fullname.replace((firstname + " "), ""). Example array below.
const names = [
{
firstname: "John",
fullname: "John Doe"
},
{
firstname: "Amber",
fullname: "Amber Smith"
},
{
firstname: "Michael",
fullname: "Michael Smith"
},
{
firstname: "Jessica",
fullname: "Jessica Kelly Charles"
}
]
While I can use the "replace" every time inside a sort compare function, I'd much rather have something like this:
names.sort(function(a, b) {
const lastname = fullname.replace((firstname+ " "), "");
if (a.lastname < b.lastname) {
return -1;
} else if (a.lastname > b.lastname) {
return 1;
}
return 0;
});
Obviously lastname comes up as undefined.
This has been rather hard to google for, and I think I'm missing some JavaScript basics here, but would greatly apprecite your help in helping me learn to write better code.
Your best bet is to modify the source of the array so it stores lastname upon collection.
If you can't do that:
Unless you do a prep pass through your array adding a lastname property, you'll have to compute it each and every time your sort callback is called, for both a and b.
names.sort((a, b) => {
const alast = a.fullname.replace(a.firstname + " "), "");
const blast = b.fullname.replace(b.firstname + " "), "");
return alast.localeCompare(blast);
});
(Note I used localeCompare, which is always a better choice for names and other natural language strings than < and >. For instance, ask the French whether รง should really come after z as it does with < and >. ;-) )
That will recompute the lastname for the same object repeatedly, though, since the same object may be passed to sort (as either a or b) repeatedly. If you think that may be a problem, you could do that prep pass I mentioned:
// Build a map of entry to last names
const lastnames = new Map(names.map(entry => {
const lastname = entry.fullname.replace(entry.firstname + " ", "");
return [entry, lastname];
}));
// sort
names.sort((a, b) => {
return lastnames.get(a).localeCompare(lastnames.get(b));
});
You are just declaring a new variable trying to access it via object's property. You should map your data in the first place like:
const names = [
{
firstname: "John",
fullname: "John Doe"
},
{
firstname: "Amber",
fullname: "Amber Smith"
},
{
firstname: "Michael",
fullname: "Michael Smith"
},
{
firstname: "Jessica",
fullname: "Jessica Kelly Charles"
}
].map(person => ({
...person,
lastName: person.fullName.replace(person.firstName + ' ', '')
}));
After mapping your data like that, you can use .lastName in the place you need.
names.sort(function(a, b) {
if (a.lastName < b.lastName) {
return -1;
} else if (a.lastName > b.lastName) {
return 1;
}
return 0;
});
I'm trying to figure out the most terse way to return an array of objects from a ts function. The following function works as expected:
getAuthors1(): Author[]
{
var authors: Author[] =
[
{
FirstName: "John";
MI: "J";
LastName: "Smith";
}
];
return authors;
}
The following function errors out b/c it appears that ts won't let me return an object array directly as opposed to as a variable:
getAuthors2(): Author[]
{
return Author[] =
[
{
FirstName: "John";
MI: "J";
LastName: "Smith";
}
];
}
The following function errors out b/c a value isn't provided for MI:
getAuthors3(): Author[]
{
var authors: Author[] =
[
{
FirstName: "John";
LastName: "Smith";
}
];
return authors;
}
Questions:
Are values required for all object properties when creating an object initialized array?
1a. If this is the case do developers typically initialize property values in the class?
Is there a way to return an object array directly, similar to my getAuthors2() example above, as opposed to having to assign this to a variable and then return the variable?
If you have an interface defined and you create an object where you tell TypeScript that it should be of that type, it will complain for any missing property, as it should.
One way to get around this is to use a mapped type where you state that each property of the object is optional, and use it like Partial< Author >. See the official documentation for more info.
You can return the array right away, just remove the type that you've added after return:
getAuthors2(): Author[] {
return [
{
FirstName: 'John',
MI: 'J',
LastName: 'Smith',
}
];
}
Also wherever possible you should remove the manually defined types, like the return Author[] from your functions. TypeScript will use type inference to figure it out by itself.
In your specific example either you leave the return type defined, and typescript will make the required checks or use something similar to what you have in getAuthors3. If you get or have the objects already typed just place them in the array and TypeScript will do the rest:
getAuthors() {
const author: Author = {
FirstName: 'John',
MI: 'J',
LastName: 'Smith',
};
return [author];
}
Return the array, not the result of an array assignment.
function getAuthors() {
return [{
FirstName: "John",
MI: "J",
LastName: "Smith"
}];
}
console.log(getAuthors());
I have a JavaScript array of objects. Something like this:
var people = [
{ id:1, firstName: 'Joe', lastName: 'Smith' },
{ id:2, firstName: 'Bill', lastName: 'Smith' }
];
I am iterating through the people using forEach. Here is my code:
function doSomething() {
people.forEach(function(person, self) {
self.helpPerson(person);
}, this);
}
function helpPerson(person) {
alert('Welcome ' + person.firstName);
}
I am trying to call helpPerson from within the forEach loop. However, when I attempt to call it, I get an error that says:
TypeError: self.helpPerson is not a function
If I add console.log(self);, "0" gets printed to the console window. This implies that I'm not passing in my parameter correctly. Or, I'm misunderstanding closures (just when I thought I fully understood it :)).
So, why doesn't self exit?
You don't need to invoke helpPerson with a this, self, or any other context. Just invoke it directly:
var people = [
{ id:1, firstName: 'Joe', lastName: 'Smith' },
{ id:2, firstName: 'Bill', lastName: 'Smith' }
];
function doSomething() {
people.forEach(function(person) {
helpPerson(person);
});
}
function helpPerson(person) {
alert('Welcome ' + person.firstName);
}
When you log self to the console you are seeing "0" because it is printing the index of the loop iteration.
See the documentation for forEach to see what callbacks are passed to it's forEach function.
Typically, self is used to capture a context in a closure (var self = this;). Please see the related links to this question because that is a very important concept.
helpPerson is a global variable, not a property of the array.
self.helpPerson(person); should be helpPerson(person);
forEach passes two arguments to the callback: the item being iterated and its index. That's why console is logging 0.
You are expecting this to pass as an argument, when it's actually more magical than that. You can use this inside the callback and it will use the context of whatever this you passed as an argument to the forEach
function doSomething() {
people.forEach(function(person, index) {
this.helpPerson(person); //Or for brevity, you can just remove `this` here
}, this);
}
function helpPerson(person) {
alert('Welcome ' + person.firstName);
}
forEach takes 2 parameters : a function(val, index, arr) and a this binding argument .
people.forEach(function(person, self) {
self.helpPerson(person); // self here would be array index number
}, this);
the way you've defined helpPerson() you can call it directly like helpPerson(person);
Please see comments
var people = [
{ id:1, firstName: 'Joe', lastName: 'Smith' },
{ id:2, firstName: 'Bill', lastName: 'Smith' }
];
function doSomething() {
people.forEach(function(person) { // no parameter for index required
helpPerson(person); // just call the function
}); // no other parameter is required
}
function helpPerson(person) {
alert('Welcome ' + person.firstName);
}
doSomething();
Codecademy code
I have successfully completed a JavaScript exercise in Codecademy entitled 'contact list' with the code:
var friends = {};
friends.bill = {
firstName: "Bill",
lastName: "Gates",
number: "(206) 555-5555",
address: ['One Microsoft Way','Redmond','WA','98052']
};
friends.steve = {
firstName: "Steve",
lastName: "Jobs",
number: "(408) 555-5555",
address: ['1 Infinite Loop','Cupertino','CA','95014']
};
var list = function(obj) {
for(var prop in obj) {
console.log(prop);
}
};
var search = function(name) {
for(var prop in friends) {
if(friends[prop].firstName === name) {
console.log(friends[prop]);
return friends[prop];
}
}
};
list(friends);
search("Steve");
This outputs:
bill
steve
{ firstName: 'Steve',
lastName: 'Jobs',
number: '(408) 555-5555',
address: [ '1 Infinite Loop', 'Cupertino', 'CA', '95014' ] }
{"firstName":"Steve",
"lastName":"Jobs",
"number":"(408) 555-5555",
"address":["1 >Infinite Loop","Cupertino","CA","95014"]}
I then changed the list and search functions slightly so that it outputs in chrome correctly:
var list = function(obj) {
for(var prop in obj) {
document.write(prop + "<br>");
}
};
var search = function(name) {
for(var prop in friends) {
if(friends[prop].firstName === name) {
document.write(friends[prop]);
return friends[prop];
}
}
};
This returned the output:
bill
steve
[object Object]
Question:
Where does this [object Object] output come from?
How can I return the correct output from search function?
Note:
The list function is working fine, but there is a problem with the search function. The friends[prop].firstName in the for loop is not returning anything.
Thanks in advance for the help
The string [object Object] is the default string representation of a Javascript object. You will get that when you try to write out any object. In your example, console.log does a bit of magic that converts for you automatically:
document.write({});
document.write({ a: 'b' });
What you can do to output a more helpful version of a JS Object is using JSON. Thankfully, JS provides a nice little function for converting objects into strings:
document.write(JSON.stringify({}));
document.write(JSON.stringify({ a: 'b' }));
document.write(friends[prop]) shows oupput as [object Object], access property by property name.
var search = function (name) {
for (var prop in friends) {
if (friends[prop].firstName === name) {
//document.write(friends[prop]);
var oProp = friends[prop]
document.write(oProp.address + "<br/>" + oProp.firstName);
//return friends[prop] - as an object
//return oProp.address - as a single property
//return JSON.stringify(oProp) - as a JSON string
return friends[prop];
}
}
};
i'm doing the codeacademy class section "building a contact list" .. what is wrong here? keep getting error "Oops, try again. It looks like your search function doesn't return contact information for Steve."
(http://www.codecademy.com/courses/javascript-beginner-en-3bmfN/0/7)
var friends = {};
friends.bill = {
firstName: "Bill",
lastName: "Gates",
number: "(206) 555-5555",
address: ['One Microsoft Way', 'Redmond', 'WA', '98052']
};
friends.steve = {
firstName: "Steve",
lastName: "Jobs",
number: "(556) 555-5555",
address: ['178 martio', 'cocoa', 'CA', '95074']
};
var list = function(friends) {
for (var key in friends) {
console.log(key);
}
};
var search = function(friends) {
for (var key in friends) {
if (friends[key].firstName === "Bill" || friends[key].firstName === "Steve") {
console.log(friends[key]);
return friends[key];
} else {
console.log("couldn't find them");
}
}
};
The error is in the search function:
The instructions tell you:
Define a function search that takes a single argument, name. If the
argument passed to the function matches any of the first names in
friends, it should log that friend's contact information to the
console and return it.
In a nutshell, it is asking you to create a function where you provide the name of the person you are searching, while you are providing friends which is also a global variable.
The goal of the exercice seems to be that by using:
search("steve");
you should get as a result:
Object :
{ firstName: 'Steve',
lastName: 'Jobs',
number: '(556) 555-5555',
address: [ '178 martio', 'cocoa', 'CA', '95074' ] }
In your (current) search function you will get a result not from the needle (the search parameter) but from your own preferences, defined in your if condition:
if (friends[key].firstName === "Bill" || friends[key].firstName === "Steve")
Hence, what we are going to do, is:
set name as parameter
loop the friends global variable
check if friends[key].firstName is equal to the needle provided (name).
if so, we log it and return it.
Put all together:
var search = function(name) { // <-- note the name instead of friends.
for (var key in friends) {
if (friends[key].firstName === name) { // <-- note that if
console.log(friends[key]);
return friends[key];
} else {
console.log("couldn't find them");
}
}
};
And you're done!
http://prntscr.com/7kth5t
Good try anyway, you were pretty close to the solution.
If you still have any problem or need any clarification feel free to comment.
Use for listing:
list(friends);
and for search:
search(friends);