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();
Related
I am learning Javascript, and am making a simple user verification object. I need a function that will console.log only users who have "isVerified" set to true.
I have tried numerous ways including loops and if statements. The function name is "showVerified" below.
var person = {
info: [],
displayPerson: function() {
console.log('People', this.info);
},
addPerson: function(age, firstName, lastName) {
this.info.push({
age: age,
firstName: firstName,
lastName: lastName,
isVerified: false
});
this.displayPerson();
},
deletePerson: function(position) {
this.info.splice(position, 1);
this.displayPerson();
},
verifyPerson: function(position) {
this.info[position].isVerified = true;
this.info[position].firstName = this.info[position].firstName.toUpperCase();
this.displayPerson();
},
showVerified: function() {
for (var key in this.info) {
if (this.info.isVerified = true) {
console.log(this.info.isVerified[key]);
}
}
}
}
What I want to happen when running showVerified on my person object, is for it to print out ONLY the age, first name, and last name of any person who is verified.
I suggest trying to change the way you're naming your properties, so the code is a bit clearer.
Try
showVerified: function() {
this.info.filter(x => x.isVerified).forEach(v => console.log(v))
}
if you don't want to use filter, you can try this as well
this.info.forEach(person => {
if(person.isVerified){
console.log(person);
}
});
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 recently started to learn JavaScript and would like to know if it is possible to use a object variable in a function directly within the same object. Here is my code so far.
var user = {
name: 'Example',
age: 687,
address: {
firstLine: '20',
secondLine: 'St Fake',
thirdLine: 'Fakeland'
},
logName: function(inputName, inputAge){
console.log(user.name);
console.log(user.age);
console.log(inputAge);
console.log(inputName);
}
};
user.logName('Richard', 20);
How is it possible to link to the name and age variables of user in the function without needing to prefix the object name onto the variable?
In most cases, you can just use the this keyword to get the object on which your function was called as a method upon. In your example:
var user = {
name: 'Example',
age: 687,
address: {
firstLine: '20',
secondLine: 'St Fake',
thirdLine: 'Fakeland'
},
logName: function(inputName, inputAge) {
console.log(this.name);
// ^^^^
console.log(this.age);
// ^^^^
console.log(inputAge);
console.log(inputName);
}
};
user.logName('Richard', 20); // method call on `user`,
// so `this` will become the `user` in the function
Welcome to the "this" key word!
Just reference it by this.value
You can use the this keyword . You can better understand this keyword using this article
The code will be like this
var user = {
name: 'Example',
age: 687,
address: {
firstLine: '20',
secondLine: 'St Fake',
thirdLine: 'Fakeland'
},
logName: function (inputName, inputAge) {
console.log(this.name);
console.log(this.age);
console.log(inputAge);
console.log(inputName);
}
};
user.logName('Richard', 20);
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.
I'm really not sure if this is possible in Javascript. Here's my function:
var tree = function(name, callback) {
if (this.name) {
this.name.push(name)
print(this.name)
} else {
this.name = []
}
callback()
}
I'd like to use it as follows and print out the hierarchy:
tree("john", function() {
tree("geoff", function() {
tree("peter", function() {
tree("richard", function() {
})
})
})
tree("dave", function() {
})
})
Here's the desired output:
// ['john']
// ['john', 'geoff']
// ['john', 'geoff', 'peter']
// ['john', 'geoff', 'peter', 'richard']
// ['john', 'dave']
but unfortunately I'm getting
// ['john', 'geoff', 'peter', 'richard', 'dave']
for the last function call. Is there a way to get the desired outcome?
Kind regards
Adam Groves
The reason why the last line is printing all the names is because this.names is never removing the names that are being added to it. You're just appending names onto it. So when the function call is made
callback()
with the value
function() {
tree("richard", function() {
})
this.names = ['john', 'geoff', 'peter'] and after the call this.names = ['john', 'geoff', 'peter', 'richard']. So now when you call
tree("dave", function() {
});
this.names is still ['john', 'geoff', 'peter', 'richard'].
Try the following instead, and notice I changed this.name to this.names to make is easier to read.
var tree = function(name, callback) {
if (!this.names) {
this.names = [];
}
this.names.push(name);
print(this.names);
callback();
this.names.pop();
}
I'm not certain what callback does, but you should probably use apply() or call() when you invoke it.
callback.apply( this, arguments );