I’ll certainly try my best!
The main complicated part of this is the “regular expression” (“regex” for short), which is not something exclusive to JavaScript but can actually be used in many languages. The regex is the part enclosed by / (and the “gmi” after that part, which set a few rules for how it behaves, such as the “i” for “case insensitive”). Regexes are sets of rules that find patterns in a string. There’s lots of notation and special characters and whatnot and I always just keep documentation for it open whenever I’m working with them.
So, the pattern that my regex looks for is this: a (non-y) vowel, followed by two of the same consonant, followed by the letter y, followed by the end of the word. It’d find this pattern in words like “bunny”, “fluffy”, and “uncanny”. Also, when it does find one of these patterns, it remembers, in each one, two different “groups”. The first “group” is the vowel at the start, and the second “group” is the first consonant.
The replace() function has two parameters: a regex and a string. It’s also being applied to a string, “str” in this case. Basically, it finds the matches that the regex finds in str and replaces those matches with the second parameter of the function. I should note here that the matches for my regex, while they do look for the y followed by the end of the word, don’t include those as part of the match. In other words, they do have to be there, but they aren’t replaced. The 3 characters before that, though (the vowel followed by a double consonant), are replaced by “$2$1$1”. “$n” basically means “the content of this match’s nth group”. So, the “vowel consonant consonant” part ends up being replaced by “consonant vowel vowel”.
Uh, hopefully this helps. Regexes are… certainly very interesting. Not everybody likes them, but I think they’re fun.