-
-
Notifications
You must be signed in to change notification settings - Fork 184
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
add tiny-js-world homework #193
Merged
Merged
Changes from 2 commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* Refer to https://github.com/OleksiyRudenko/a-tiny-JS-world for the task details | ||
Complete the below for code reviewers' convenience: | ||
|
||
Code repository: https://github.com/bmukha/a-tiny-JS-world | ||
Web app: https://bmukha.github.io/a-tiny-JS-world/ | ||
*/ | ||
|
||
const dog = { | ||
species: 'dog', | ||
name: 'Beethoven', | ||
gender: 'male', | ||
legs: 4, | ||
hands: 0, | ||
saying: 'woof', | ||
friends: ['Clyde'], | ||
}; | ||
|
||
const cat = { | ||
species: 'cat', | ||
name: 'Grizabella', | ||
gender: 'female', | ||
legs: 4, | ||
hands: 0, | ||
saying: 'meow', | ||
friends: ['Bonnie'], | ||
}; | ||
|
||
const man = { | ||
species: 'human', | ||
name: 'Clyde', | ||
gender: 'male', | ||
legs: 2, | ||
hands: 2, | ||
saying: 'Get rich or die trying!', | ||
friends: ['Bonnie', 'Beethoven'], | ||
}; | ||
|
||
const woman = { | ||
species: 'human', | ||
name: 'Bonnie', | ||
gender: 'female', | ||
legs: 2, | ||
hands: 2, | ||
saying: 'I have the right to not answer a questions!', | ||
friends: ['Clyde', 'Grizabella'], | ||
}; | ||
|
||
const catwoman = { | ||
species: 'human', | ||
name: 'Selina', | ||
gender: 'female', | ||
legs: 2, | ||
hands: 2, | ||
saying: cat.saying, | ||
friends: [], | ||
}; | ||
|
||
const characters = [dog, cat, man, woman, catwoman]; | ||
|
||
const props = [ | ||
'species', | ||
'name', | ||
'gender', | ||
'legs', | ||
'hands', | ||
'saying', | ||
'friends', | ||
]; | ||
|
||
characters.forEach((character) => { | ||
const noZeroHandsOrFriends = props.filter( | ||
(prop) => | ||
!( | ||
(prop === 'hands' && character[prop] === 0) || | ||
(Array.isArray(character[prop]) && character[prop].length === 0) | ||
) | ||
); | ||
const values = noZeroHandsOrFriends.map((prop) => | ||
Array.isArray(character[prop]) | ||
? character[prop].join(', ') | ||
: character[prop] | ||
); | ||
|
||
print(values.join('; ')); | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not change anything yet. At this stage please just answer questions and reflect on statements.
Describe in plain language (any but just plain) what would be the rules to print the value of any particular property?
Do we want to skip printing
0
only forhands
? What if a character has 0 legs and 0 hands but 4 paws? What if I as a peer developer assigned to this project passundefined
instead of0
?Array
methods that return arrays are chainable.map
andfilter
always do.reduce
may return an array, thus chainable by otherArray
methods.This means that we can do
filter(...).map(...).filter(...).map(...)
orfilter(...).filter(...).map(...)
ormap(...).filter(...).filter(...).map(...)
etc.The tinier the job a callback does the more readable and scalable the code is.
e.g.
is cleaner and easier to extend and modify than
arr.filter(v => !(v=== 0 || v === "" || (Array.isArray(v) && v.length))
Probably, we want to discard not only zero values, but also
undefined
,null
and""
(empty strings).Check what
Boolean(v)
does whenv
is either of0
,""
,undefined
,null
,111
,"abc"
,[]
,[1,2,3]
.Check what is the result of
[].join("whatever glue string")
.Check what are the results of the statements below.
Explain.
P.S. You may quote-reply and comment inline or refer to item numbers in your response. Please feel free to answer those one by one in separate comments and in any order.
P.P.S. We won't necessarily implement every learning.
P.P.P.S. Apologies for many updates. Just a really good case to dig deeper into the topic of data processing and validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all, there is no need to apologise. I am here to learn and I appreciate your feedback a lot. Thank you very much for your time and effort.
0 and 1. I derived my decisions on what to filter out from those two rules:
In the first rule, only hands were mentioned as questionable property. As for why I decided to filter them out only if hands === 0, well, I guess I really didn't think it through. From all options "skip it or report 0 or undefined" I've decided to go for the skip. And, in the second rule, if the friends array is empty, I decided to filter it out too for consistency. So, my interpretation was that only hands need to be checked, so that's why I did not go for some generalised solution.
I am aware of chaining methods, but it is still more readable for me as a novice to write code without it. But I got the point, should probably try to get used to it.
This one is really interesting to me. I'm not trying to argue, I'm trying to understand. Your way code loops over the array 3 times, while my way it loops only once. Genuine question: is it worth sacrificing a little bit of performance to achieve better readability? Should I always go with the readability approach, or does it depend on the situation?
Again, I am aware of what Boolean(v) does. But I can't think of a clean and elegant solution from the top of my head to filter everything I need to filter at once. While I can filter out all falsy values with it, the problem is empty array is still a truthy value.
I’ve done some research, and it looks like optional chaining. Totally new concept to me, since when I first tried to learn JS for my personal needs many years ago it wasn't even been introduced yet. I had to even update my Node from version 12 to 16 to make it work in my console, lol ) So, both examples should return undefined. But, if I understood everything correctly, the second one is useful when we need to check if some property exists and only then check its value.
So, to summarize it all: for each character, we need to filter out all the properties with falsy values and properties which are empty arrays. (I still can’t see if it could be done in one clean and concise check, though). Then we need to map through the remaining properties to join them together (and join non-empty array properties in the process). So, I guess, the code should look something like this:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, splitting one complex
filter
condition into consequentfilter
's with a simpler logic each affects performance. So, readability takes it cost (2filters
are slower by 30-50% compared with a singlefilter
).Consider logic as complex as
(a || !(b[i] || c) && d[i][j]) || (e ? f[i+1]:g)
. Same refers to nestedif/else
's. Quite easy to make a mistake when need to change anything and a nightmare to debug.If we can improve readability by other means we should do.
Your latest example contains two simple conditions, so we can already combine them both in a single
filter
condition with not much impact on performance and yet quite clean and readable.One important observation is that now your code works with values only, as we do not need property checks anymore. Makes sense to convert property names into values on some very early stage and you need arrays converted to strings anyway. Check
[].join('any delimiter')
. The benefit: you reduce a number of data types to analyze and work with further down. A good chance to simplify value checks even further.We also get rid of
character[prop]
on early stage and may use simplevalue
further down the chain. Not much to save in this case but think of it as of a pattern for more complex cases.In few words, simplify, minimize, reduce complex data structures and logic as early as possible.
If you feel confident as to the next code improvement iteration then go ahead. Feel free to ask further questions and sharing your ideas.
P.S. Do not use
x?.prop
here, stick toArray.isArray
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, that was really helpful. By mapping first I can convert possible truthy empty arrays into falsy empty strings and then get rid of all the falsy values with one filter. Thank you very much for this suggestion! I just submitted refactored version, please, take a look.