Im reading John Resigs "Learning Advanced JavaScript" http://ejohn.org/apps/learn/#10 and came across this function below that I don`t understand.
The function yell is called with an argument of 4. When this is done, the argument 4 is run through the terniary operator. If it is greater than zero, which it is, then we come to yell(n-1) + a
My questions relate to this.
a) does yell(n-1) + a call the function again (i.e. restart it) with an argument of 3.
b) If you do (n-1) + a, you get a result of 3a. Does JavaScript convert 3a to "aaa". I ask this because in the assert line it says yell(4) == "hiyaaaa"
c) after converting it, does it somehow add it to "hiy"? I don`t understand how.
d) if JavaScript does convert 3a to a string of "aaa"s, and somehow manages to add it to "hiy", I don`t understand why yell(4)=hiyaaaa. Yell(n-1) + a = hiyaaa (3as), not hiyaaaa(4"a"s).
As you can see I am totally confused.
function yell(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
}
assert( yell(4) == "hiyaaaa", "Calling the function by itself comes naturally." );
a) This function is taking advantage of recursion, so yes, the function called again and everything else is pushed on the stack waiting for that return value.
b) No, the function is called with a return value as mentioned above.
c) See Above.
d) It doesn't.
Think of it like this:
function a(val) {
return val + "a";
}
function b(val) {
return a(val) + "a";
}
If you call b("hiya") you'll get hiyaaa. Now instead of calling a different function, call the same one.
a) Yes it calls the function again, so the function is recursive.
b) If one of the operands is a string, + does string concatenation.
c) It returns it.
d) Write the recursion out on paper to better visualise it.
For a), it is known as a recursive function, and yes it is calling self with 3.
For b) you aren't just doing (n-1), you are doing yell(n-1) + "a", and once n =0, yell(0) returns 0.
For c), read the last part of b), i.e. because of the ternary statement, it will return "hiy" once n=0.
For d), see the rest of them.
Try replacing the "a" with the argument supplied to the yell function. Like this:
function yell(n){ return n > 0 ? yell(n-1) + n : "hiy"; }
var x = yell(4); log(x);
assert( yell(4) == "hiy1234", "Calling the function by itself comes naturally." );
So, each value of n is taken and put on a LIFO stack ie 4,3,2,1 and when n becomes 0 "hiy" is on top of the LIFO stack. Then the concatenation is done be popping each value off of the stack such that the string becomes "hiy1234".
Hope this helps.
Bumpfster
Related
This question already has answers here:
What's the meaning of "=>" (an arrow formed from equals & greater than) in JavaScript?
(14 answers)
Closed 3 years ago.
I have a function that takes an input (n) and puts it in the parameters of another function. (n) represents in the second equation the number to what (m) is being compared to (in this case 10). I understand how this function is structured, just don't understand what this means:
return m => m > n;
function greaterThan(n) {
return m => m > n;
}
let greaterThan10 = greaterThan(10);
console.log(greaterThan10(9)); //should output false
m => m > n is an arrow function in javascript. almost same as,
function(m){
return m>n
}
Read more here http://2ality.com/2012/04/arrow-functions.html
This is an example of currying. The function greaterThan is returning a new anonymous function. It's probably easier to understand written like this:
function greaterThan(n) {
return function (m) {
return m > n
}
}
Calling greaterThan(10) returns a new function that will compare its argument to 10. In your example you give it the name greaterThan10 so now you can call greaterThan10(9). This is all because the other function returns another function to use.
You can rewrite your example:
function greaterThan(n) {
return function(m) { return m > n }
}
which uses the same function syntax for both of them.
Otherwise I found your explanation to be let much what anyone would write to explain it. m is simply the parameter to the function returned.
I was in codewars this morning and there is this Kata asking for a function to reverse a string passed as parameter through recursion method.
The best solution listed for this problem was this.
function reverse(str) {
return str.length > 1 ? reverse(str.slice(1)) + str[0] : str;
}
I researched for this all this morning and I still don't know what is happening here:
+ str[0]
Can somebody please clarify this for me?
The essence of the function is the following:
Take the substring from the second character to the last
Apply the reverse function recursively
Take the first character and append it to the end of the result of the recursive call
Return the result
This results in the following logic, the (recursive) function calls indicated by brackets:
(A B C D E)
((B C D E) A)
(((C D E) B) A)
((((D E) C) B) A)
(((((E) D) C) B) A)
str.slice(1) "chops off" the first letter of the string and returns the rest of it. So 'abcd'.slice(1) gives you 'bcd'.
str[0] is the first letter of the string. 'abcd'[0] is 'a'.
So, str.slice(1) + str[0] is taking the first letter of the string and "moving" it to the end: 'abcd' becomes 'bcda'.
This does not address the recursive nature of the solution, but it answers your question about + str[0].
I'll try to rewrite the function in a more "human-readable" way
reverse = str => {
// If there is still string to reverse
if (str.length > 1) {
let firstChar = str[0]
let strWithoutFirstChar = str.slice(1)
// Notice only a part of the string 'comes back' here
// console.log(strWithoutFirstChar) // Might help
return reverse(strWithoutFirstChar) + firstChar
}
// Else return result as is
else {
return str
}
}
This is the same function, but without ternaries and declaring well named variables.
If you uncomment the console.log() line and call:
reverse('help');
The output should be:
elp
lp
p
'pleh'
Hope it helps!
The + operator is a concatenator for string.
You can instead use concat this :
var reverse = str => str.length > 1 ? reverse(str.slice(1)).concat(str[0]) : str;
console.log(reverse("123456789")); // 987654321
Much apologies for the vague title, but I need to elaborate. Here is the code in question, which I read on http://ariya.ofilabs.com/2013/07/prime-numbers-factorial-and-fibonacci-series-with-javascript-array.html:
function isPrime(i) {
return (i > 1) && Array.apply(0, Array(1 + ~~Math.sqrt(i))).
every(function (x, y) {
console.log(x + ' ' + i % y);
return (y < 2) || (i % y !== 0)
});
}
isPrime(23);
isPrime(19);
isPrime(188);
Just for fun, I added those logs so we can see some output:
undefined NaN
undefined 0
undefined 1
undefined 2
undefined 3
undefined NaN
undefined 0
undefined 1
undefined 1
undefined 3
undefined NaN
undefined 0
undefined 0
This is the first time I have every seen apply and every, so bear with me, but my understanding is that apply basically calls the Array function, where the first argument is the substitution for its this and the second is the output...Never would think that would be useful, but this function seems to work, so...
Here, they seem to be creating an array of length equal to the square root of the number in question. I suppose that makes sense because the square root would be the largest possible factor of the number in question.
OK, so from here, if we were to log that array for, say, the first number, it would look like this:
> var i = 23;
undefined
> Array.apply(0, Array(1 + ~~Math.sqrt(i)));
[ undefined, undefined, undefined, undefined, undefined ]
Great, so it is an array of five undefined. Ok, fine, so from here, the every method is supposed to check whether every element in that array passes the callback function test (or whatever).
The Microsoft documentation specifies three possible arguments for the every method:
value
index
array
Therefore, in this example x is the value, i.e. undefined, and y is the index.
Our output agrees with that conclusion. However, I'm still fuzzy about nested return statements (if the lowest one returns, does its parent also return?), the || operator here (if the first test passes, does the every loop stop?), and just generally how this works.
EDIT
the log should be with an x, not a y. my mistake:
console.log(y + ' ' + i % y); -> console.log(x + ' ' + i % y);
EXPLANATION
So, how did I come across this code, you ask? Well, of course, the simplest way to check for a prime in Java would be like this:
public static boolean isPrime(double num) {
for (double i = 2.0; i < sqrt(num); i++) {
if (num % i == 0.0) {
return true;
}
}
return false;
}
or Python
def isPrime(num):
x = 2
isPrime = True
while x < math.sqrt(num):
if num % x == 0:
isPrime = False
break
x = x + 1
return isPrime
or js
function isPrime(n) {
for (var i = 2.0; i < Math.sqrt(n); i++) {
if (n % i === 0.0) {
return false;
}
}
return true;
}
But say I wanted to check for the largest prime factor of a number like 600851475143 These looping methods would take too long, right? I think this "hack", as we are describing it, may be even less efficient, because it is using arrays instead of integers or floats, but even still, I was just looking for a more efficient way to solve that problem.
The code in that post is basically crap. Teaching people to write code while simultaneously using hacks is garbage. Yes, hacks have their place (optimization), but educators should demonstrate solutions that don't depend on them.
Hack 1
// the 0 isn't even relevant here. it should be null
Array.apply(0, Array(1 + ...))
Hack 2
// This is just Math.floor(x), but trying to be clever
~~x
Hack 3
// this is an outright sin; totally unreadable code
// I bet most people don't know the binding precedence of % over +
y + ' ' + i % y
// this is evaluated as
y + ' ' + (i % y)
// example
2 + ' ' + (5 % 2) //=> "2 1"
I'm still fuzzy about nested return statements (if the lowest one returns, does its parent also return?),
No. A return only return the function the statement exists in
the || operator here (if the first test passes, does the every loop stop?)
No. Array.prototype.every will return false as soon as the callback returns a false. If a false is never returned from the callback, .every will return `true.
function isEven(x) { return x % 2 === 0; }
[2,4,5,6].every(isEven); //=> false, stops at the 5
[2,4,6].every(isEven); //=> true
Here's an example of .every short circuiting
[1,2,3,4,5,6].every(x=> {console.log(x, x<4); return x<4;});
// 1 true
// 2 true
// 3 true
// 4 false
//=> false
See how it stops once the callback returns false? Elements 5 and 6 aren't even evaluated.
... and just generally how this works.
&& kind of works like Array.prototype.every and || kind of works like Array.prototype.some.
&& will return false as soon as the first false is encountered; in other words, it expects every arguments to be true.
|| will return true as soon as the first true is encountered; in other words, it expects only some argument to be true.
Relevant: short circuit evaluation
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am really new to this kind of programming and i have a block of code which i have some questions about.
Code:
function numFormat(n) {
return n.toFixed(0).replace(/./g, function(c, i, a) {
//console.log(a);
return i > 0 && c !== "." && (a.length - i) % 3 === 0 ? "," + c : c;
});
}
I actually do know what it does, it turns a number for example 1234 to 1,234 divides in groups of 3 with a "," for currency figures.
I really do not understand how it does it.
I dont know from where c i and a are being filled with what and from where!?
Can please somebody explain to me this function?
Thanks and Regards
Replace
The replace function accepts a regular expression, and replaces each match with a value. The replacement value is determined by the function you pass to replace as the second argument.
Anonymous functions as callbacks
The anonymous function is not (visibly) called from the JavaScript code, but is called internally by the replace function. You don't pass the function result but the function itself to replace, so replace can call your function to process the matches. This way you can 'inject' behaviour into JavaScript's built-in functions. This is a common concept in JavaScript, and you'll encounter this on many occasions.
The '.' wildcard in the pattern
So, the function is called for each match of the pattern. The core of this pattern is the dot . character. It is a wildcard meaning 'any character'. So any character in the given number is matched by the dot. The effect of this, is that the function is called for each separate character in the number.
Arguments and inner workings of the callback
Then the arguments a, c and i. The meaning of the arguments of the callback function are of course documented for the replace function, but it may become a bit clear at once if you output c, i and a to the console as I've done in the snippet below.
function numFormat(n) {
return n.toFixed(0).replace(/./g, function(c, i, a) {
console.log(a + ',' + i +',' + c);
return i > 0 && c !== "." && (a.length - i) % 3 === 0 ? "," + c : c;
});
}
alert(numFormat(107784));
The parameters of the function are the matched substring (c), which is one character each time (as matched by the pattern), the offset/string position (i) of the match, and the whole string (a).
Using the offset i, a calculation is made to see if it is the third character or not. If so, the character c is returned with a comma in front of it, otherwise, just the character is returned. i > 0 is added as an extra condition to prevent a comma at the start of the string. c !== "." seems to be obsolete and may be a leftover from an attempt to support floating point numbers as well.
All these returned strings are put back together (again, internally by replace) and will form the return value of the replace function.
Additional documentation
Documentation of the replace function, including the part about the function callback and its parameters can be found on developer.mozilla.org.
More information about callbacks can be found in Understanding callback functions in Javascript.
Quick overview:
For every character in the given input
return n.toFixed(0).replace(/./g, function(c, i, a) {
Execute the following ternary:
return i > 0 && c !== "." && (a.length - i) % 3 === 0 ? "," + c : c;
Which can simply be written as
if (i > 0 && c !== "." && (a.length - i) % 3 === 0) {
return "," + c;
} else {
return c;
};
The arguments c, i and a are as outlined in the spec, namely:
c is the matched substring, that is, a single character of the input
i is the offset of the matched substring, in this context meaning the index of the char we're currently working with
a is the total string being examined
Combining all this we can reword
if (i > 0 && c !== "." && (a.length - i) % 3 === 0) {
return "," + c;
} else {
return c;
};
as
If we're not looking at the first character of the input
and
if the character we're looking at is not a dot
and
if the current index of the examined char is divisible by three (since we want to separate every three chars)
then insert a comma followed by the current character,
otherwise replace that character with itself.
I'm looking through some of the JavaScript code of YouTube and I've come across something I've never seen before. Here's the relevant bit of code:
for (var e = window.ytbuffer.queue, a = 0; 5 > a && a < e.length; a++) {
var g = e[a],
h = g.target || g.srcElement;
(0, m.Hf)((0, m.Af)({
a: "buffer_events",
event_index: a,
clientX: g.clientX,
clientY: g.clientY,
localName: h.localName,
className: h.className,
id: h.id,
page_name: (0, m.v)("PAGE_NAME")
}))
}
window.document.removeEventListener ? window.document.removeEventListener("click",
window.ytbuffer.enqueueEvent, !1) : window.document.detachEvent("onclick", window.ytbuffer.enqueueEvent);
(0, m.Wc)("ytbuffer")
What I'm wondering is, what does (0, m.Hf) actually do? I know parenthesis can be used as grouping for mathematical operations, but then I wouldn't expect to see a comma there, and I know that parenthesis can be used to surround function arguments, but there's no function name.
Thanks,
YM
Edit: I used Chrome's inspector on the page and found that m is undefined. This has made me even more confused.
The parens with comma separated expressions inside will return the last expression. So:
(2, 3, 4) + 1 returns 5
So, instead of doing:
alert("Hello World!!")
You could do:
(prompt, alert)("Hello World!!")
Because (prompt, alert) returns alert, right?
That's exactly what's happening in that code
(0, m.Hf)(...) is just calling the m.Hf() method, just with some nesting.
Hope this helps. Cheers