Javascript - How to place a statement inside expression? - javascript

I'm learning javascript and I have a problem I stumbled upon. I have the following javascript code (I'm searching for the name john inside MyArray, which contains class objects):
MyArray.forEach(
(v,i)=>(
v.name == 'john' && return i
)
);
This is not working, because I get the following error for the 3rd line:
SyntaxError: expected expression, got keyword 'return'
My question is, how can I put statement inside an expression?

How can i put statement inside an expression?
You can't, currently. Nor, in that example, do you want to. The return value of the forEach callback isn't used for anything.
See below the horizontal rule for your specific case, but answering the question you actually asked:
On occasion, wanting to do some statement logic and then have an overall expression take the final result of that statement logic does come up. Consequently, there's a proposal for do expressions working its way through the JavaScript proposals process. It's only at Stage 1 of the process, and so it may not progress, or if it progresses the form of it may change, but for now it looks like this:
let x = do { // Using the `do` expression proposal
let tmp = f(); // (currently just Stage 1, do not use!)
tmp * tmp + 1
};
...where x would get the result of that last expression within the {}.
If you really wanted to do that now, you'd probably use an immediately-invoked arrow function:
let x = (() => {
let tmp = f();
return tmp * tmp + 1;
})();
The purpose of do expression proposal is to make that less verbose, when you need to do.
(Please don't mistake this for my offering an opinion on do expressions either way. I'm just noting the proposal exists and is working through the process.)
Your specific case of finding the index of an item:
In your specific case, you're looking for the Array#findIndex function, which returns the index of the entry where the callback returns a truthy value:
const index = MyArray.findIndex(v => v.name == 'john');
(Or you might want Array#find if you want the entry itself instead of its index.)
Note that since that uses a concise arrow function, the return value of the function is the value of the expression forming the function body. We could use a verbose one instead with an explicit return:
const index = MyArray.findIndex(v => { return v.name == 'john'; });

Looks like you want to find the index of the Mr. John? Then use dedicated method findIndex for this:
const john = MyArray.findIndex(
(v,i) => (
v.name == 'john'
)
);

You cant. Just do:
for(const [index, el] of myArray.entries())
if(el.name === "john") return index;
Or more easy:
return myArray.findIndex(el => el.name === "john");

forEach is just a loop of all elements. You can't return anything there like you did. You could use find for example, if you want the object with the name john:
var MyArray = [
{name: 'test', some: 'data'},
{name: 'john', some: 'data'},
];
var obj = MyArray.find(v => v.name == 'john');
console.log(obj);

Related

Problem of best practice with function return

I am new about programming. I have some difficulties to undurstand function.
So I done practice. But, I don't know why use return.
My code work.
In this exemple :
the function name is reverse.
I return in my function an array [1, 2, 5, 8].
Console.log a new array named reversed.
function reverse(array) {
const reversed = [];
for (i = array.length - 1; i > -1; i--) {
reversed.push(array[i]);
}
console.log(reversed);
}
return reverse([1, 2, 5, 8]);
**
But why after validate exercice, it's say me false and send me this solution :**
function reverse(array) {
const reversed = [];
for (let i = array.length - 1; i > -1; i--) {
reversed.push(array[i]);
}
return reversed;
}
Thanks : )
I googling and use chat GPT to teach me why use return in my case. But, nothing about I can understand.. I need your help.
Thank all.
The variable reversed is defined inside the function body so it can only be accessed from inside of the function. In your code you tried to access the variable from outside of the function. return keyword is used inside the function to return a value, using return outside the function has no effect.
Some remarks:
The names reverse and reversed are very similar which can lead to confusion. I see it happening in another answer and in your comments. reverse is defined as a function, and reversed is a local variable that references an array. They are completely different objects.
In your code you have placed a return statement where it is not valid. A return statement can only occur inside a function body.
console.log(reversed) will output the result in the console window, but that is not what the purpose is of the exercise. Although console.log is very useful while you are debugging your code, it is not equivalent to a return value. The caller of your function will get as return value what the function has returned with a return statement, not what console.log has output.
Your code does not define i with let (or var) and so it is implicitly declared as a global variable. This is not good practice. Always define variables explicitly.
Your code calls the reverse function. This is what you typically would do to test your function, but in code challenges, this call is typically made by the person or framework that tests your implementation. And those tests will call it more than once, with different arrays as argument, often including boundary cases, like an empty array, or a very large array.
So when you debug code, you would call the function and print the value that it returns, like so:
function reverse(array) {
const reversed = [];
for (let i = array.length - 1; i > -1; i--) {
reversed.push(array[i]);
}
return reversed;
}
let result = reverse([1,2,3,4]);
console.log(result); // Should be [4,3,2,1]
result = reverse([1]);
console.log(result); // Should be [1]
result = reverse([]);
console.log(result); // Should be []
result = reverse(reverse([1,2,3,4])); // Reversing the result!
console.log(result); // Should be [1,2,3,4]
Maybe I should also mention that reverse is also a native method available for arrays. It will reverse the array itself instead of creating a new array (like above). If the purpose is to always create a new array, you can still make use of it: first create a copy of the given array, reverse the copy and return that:
function reverse(array) {
// The spread syntax creates a copy, and reverse is applied on the copy
return [...array].reverse();
}
let result = reverse([1,2,3,4]);
console.log(result); // Should be [4,3,2,1]
result = reverse([1]);
console.log(result); // Should be [1]
result = reverse([]);
console.log(result); // Should be []
result = reverse(reverse([1,2,3,4])); // Reversing the result!
console.log(result); // Should be [1,2,3,4]

Array methods returning undefined

This is something I still don't quite understand very well, I have the following situation:
// #2) Check if this array includes any name that has "John" inside of it. If it does, return that
// name or names in an array.
const dragons = ['Tim', 'Johnathan', 'Sandy', 'Sarah'];
at first I tried the following:
const name = dragons.forEach(element => {
element.includes("John") ? element : null
});
it returns undefined
then:
const name = dragons.filter(element => {
element.includes("John");
});
it returns an empty array
then:
function name() {
const dragons = ['Tim', 'Johnathan', 'Sandy', 'Sarah'];
dragons.forEach(element => {
if (element.includes("John")) {
return element;
}
});
}
again it returns undefined
but the interesting thing is that if on any of the attempts I change the action to do to console.log(element); then it will show "Johnathan" which is the correct output.
so it means that the logic is working, I just don't understand why it won't return the value if I want to let's say assign it to a variable.
I even tried the following:
const dragons = ['Tim', 'Johnathan', 'Sandy', 'Sarah'];
dragons.forEach(element => {
if (element.includes("John")) {
const name = element;
}
});
but it again returns name as undefined, why is that?
edit: this was my first stack overflow question, really I wasn't expecting someone answering my question, I thought maybe it was a dumb question or that i didn't explained myself well but it was very nice to find such a supportive community, thank you so much to all of you who commented and helped me!
forEach method does return undefined. But filter instead returns the array but filtered. However, the problem is that you are forgetting to return the values inside it.
To fix it try:
const name = dragons.filter(element => {
return element.includes("John");
});
Or:
const name = dragons.filter(element => element.includes("John"));
First, forEach never returns anything. You'd need a map for that, or filter (what are you exactly after?). Second, your callback functions don't return anything, either. You can map or filter your array like that:
const dragonsNamedJohn = dragons.filter(name => name.includes('John'));
or
const dragonsNamedJohn = dragons.filter(name => {
return name.includes('John');
});
or even
function hisNameIsJohn (name) {
return name.includes('John');
}
const dragonsNamedJohn = dragons.filter(hisNameIsJohn);
(You might want to stick toLowerCase() somewhere there, or not, dependent on whether you want the comparison to be case-sensitive. Also, another way of skinning a dragon would be to use a regular expression).

How to declare two actions in ? : format?

My code is as below:
if(existingWishlistItem) {
return wishlistItems.map(wishlistItem =>
wishlistItem.id === wishlistItemToAdd.id
? toast.error('This item is already in your wishlist')
: wishlistItem
)
}
I want this function to check if there are existing wishlist item in the array, then it pop up an error message to user and return back the wishlistItem array. But I find that I just can write one action after the '?', so are there any ways to pop up the message and return back the wishlistItem at the same time?
Thanks for help!
It's possible to do this with the conditional operator, but it's not a good idea. It's hard to read, hard to debug, and easy to get wrong.
Instead, just use an if:
if (existingWishlistItem) {
for (const {id} of wishlistItems) {
if (id === wishlistItemToAdd.id) {
toast.error('This item is already in your wishlist');
break; // I assume the ID values are unique, so you can stop here
// Or: `return wishlistItems;` if you don't need to make a
// copy in this case
}
}
return wishlistItems; // If you don't need to make a copy
// Or: `return wishlistItems.slice()` if you do need to make a copy
}
(Or — again assuming id values are unique — you could use find instead of the for-of loop to find the existing item.)
For completeness, you can use the comma operator to do two things in any expression (including the operands of the conditional operator): (first, second). The comma operator evaluates its left-hand operand, throws away that result, and then evalutes its right-hand operand and takes that value as its result. Applying that to your example:
// DON'T DO THIS
if (existingWishlistItem) {
return wishlistItems.map(wishlistItem =>
wishlistItem.id === wishlistItemToAdd.id
? (toast.error('This item is already in your wishlist'), wishlistItem)
: wishlistItem
);
}
This is not what map or ternaries are for.
Idiomatically, ternaries are used for conditional behavior that does not have side effects. Like return upperCase ? "HELLO" : "hello". This is because complex ternaries are hard to read and so it's hard to tell, at a glance, where the side effect is happening.
Likewise map is for transforming objects in a sequence according to some function. It's best practice for map to have no side effects, because code is easier to read when side-effects are clearly separated from data transformation.
A far more idiomatic implementation of your code would be:
if(existingWishListItem) {
if (wishlistItems.some(x => x.id === wishlistItemToAdd.id) {
toast.error(msg)
}
return wishListItems
}
Your problem is you're using map which populates a new list of data with the same array length. If you want to find an existing item, you just simply use find. For example
if(existingWishlistItem) {
const foundWishlistItem = wishlistItems.find(wishlistItem => wishlistItem.id === wishlistItemToAdd.id)
if(foundWishlistItem) {
toast.error('This item is already in your wishlist')
//TODO: You can return or do whatever after found existing wishlist item
}
return wishlistItems
}
Besides that, if you want to have true/false value instead of finding an existing object, you can use some instead
if(existingWishlistItem) {
const isFoundWishlistItem = wishlistItems.some(wishlistItem => wishlistItem.id === wishlistItemToAdd.id)
if(isFoundWishlistItem) {
toast.error('This item is already in your wishlist')
//TODO: You can return or do whatever after found existing wishlist item
}
return wishlistItems
}
Depends on how you define your action. You can use the || operator, and that way first expression is your alert and second is the value you return:
let x = [1,2,3];
let y = x.map((a) => a%2===0? (alert("XXx") || a) : a+1
);
console.log(y);

What is "el", what relation do these codes have with each other, and how does the fat arrow work?

I need to understand what the code means, or a better break down of how/why it works.
This function should find an object in an array called items by it's id number, and return the objects properties of which there are 9 for each object.
I've googled how the fat arrow works, but the examples given don't match this code very well, or I'm still to ignorant to see the relation. I also don't COMPLETELY understand how el is being used. I assume it's a place holder for "item" or a Boolean. I feel it's on the tip of my tongue.
pantry{
//.. other code of an empty array, and a function that fills the array at run time
getItem: function(id) {
return this.items.find(el => {
return el.id == id
});
}
}
My tutor showed me that this code is equivalent to
for(var i = 0; i < items.length; i++){
let item = items[i];
if(item.id == id){
return item;
}
This code works as is, but I'm just barely not understanding what el does, I've changed it to ed, and do and se, and it still works, but I'm trying to understand deeply.
I'm very new to JavaScript. I've been reading "You Don't Know JavaScript" for a month now, and practicing for 3 months. I don't know if I'm learning in the best way, but I put work into learning every single day --- at any rate I digress.
Thank you for any amount of your time.
el is just a variable. When you pass it into a function like find, it represents the element of the array that you are looking at during that iteration.
The arrow is just another way of defining a function. Broadly speaking, these two functions are equivilant:
(el) => {
return el.id == id
});
function(el) {
return el.id == id
}
You can read more about them and the differences between arrow and normal functions here.
for beginner simple function and arrow function are same it's just the short way of doing stuff i. e
function(param) {} = (param) => {} = param => {}
what array find function (in your case array is items) does is that it pass every item to the function and return only those item which pass the condition or return true i.e its id is equal to the given id e.g
arr = [{id: 2, name: 'temp'}, {id: 1, name: 'other'}]
on first iteration el is equal to {id: 2, name: 'temp'} on second iteration its equal to {id: 1, name: 'other'} now if the given id is 2 it will return {id: 2, name: 'temp'} because it pass the condition or it return true now point to note is the el is just a name of a variable you can replace it with any name like you can replace id with other variable like tempId in getItem: function(id) but you have to give it only one parameter because the find function expect only one argument

Saw an expression. Javascript Error

So, I have a typical problem Expected an assignment or function call and instead saw an expression. I know that there is a lot of such problems and answers here, but no one did not help me.
Please, give a real help, insted of blocking my question.
Thanks!
Object.keys(CDs).map(key => {
parseInt(key) === additionalInfo.currentQueue[0] // Expected an assignment or function call and instead saw an expression
? CDs[key] += 1
: CDs[key]
})
The warning is telling you that you have an orphaned expression there, one that isn't connected to anything. The ternary there will resolve to the value of CDs[key] or CDs[key] + 1, but the value will be ignored - it's like the 5 in
function x() {
5;
}
If you were intending to map the keys of CDs to a new array, use an arrow function's implicit return instead, by surrounding the expression in parentheses rather than brackets:
const result = Object.keys(CDs).map(key => (
parseInt(key) === additionalInfo.currentQueue[0]
? CDs[key] + 1 // were you intending to mutate the original object as well here?
: CDs[key]
));
If you weren't intending to mutate CDs during this map, you might consider Object.entries instead, to give you the key and the value at once:
const result = Object.entries(CDs).map(([key, value]) => (
parseInt(key) === additionalInfo.currentQueue[0]
? value + 1
: value
));

Categories