Did I use recursion correctly? - javascript

I'm working through some practice JavaScript problems, and solved a problem involving recursion. Although I got it right, my implementation is different from the "official" solution, so I was wondering if anyone had any insight on whether the official answer is better and if so, why.
Question
Implement a function that takes a function as its first argument, a number num as its second argument, then executes the passed in function num times.
It's ok to use a loop in your implementation, bonus points if you use recursion instead.
My Solution
function repeat(operation, num) {
if (num > 0) {
operation();
repeat(operation, num - 1);
};
};
Given Solution
function repeat(operation, num) {
if (num <= 0)
return;
operation();
return repeat(operation, --num);
};
Is there anything about the given solution that makes it better than mine?

There is a specific reason to directly return the result of a recursive call. This is called "tail recursion", and a clever run-time environment can optimise for that case and execute without using any additional stack space for the recursive calls (it simply reuses the stack space of the current function). In the latest ECMAScipt 6 specification (Javascript to you and me) it specifically calls out that the runtime environment should optimise tail-recursive calls.
In practice, your code does in fact not do anything after the recursive call, so it is properly tail-recursive. Putting the recursive call with a return statement makes it clear that it should be a tail-recursive call, and a bit more likely that the run-time environment will correctly optimise it.

Just bear in the mind. There is something that every JavaScript developer MUST know. If recursion continues very long time the browser can kill your script or alert error to user. Often JavaScript developers uses approaches like this:
var inputArray = [1,2,3,4,5,6];
(function handleArray() {
var currentElement = inputArray.shift();
// do something with currentElement
if (inputArray.length > 0 ) {
setTimeout(handleArray, 0);
}
}());
In this way you will break long time operation on small parts.

The solutions are identical, but in practice the given solution is easier to understand. There is a clear "base case," and the recursion is done in the return statement. Both of these properties lead to better code quality and readability when dealing with recursive functions.

Related

Double Function Call or storing the Result as a variable?

Assume I have some function f(-) defined elsewhere. I use it twice in the following type of code:
if (f(-) satisfies some condition) {
do some stuff
if (f(-) satisfies some other condition) {
do some other stuff
}
}
When the code is run, is f(-) calculated twice (or is the interpreter "intelligent" enough to see that it is enough to calculate it once)? If so, is it recommended to define a constant x = f(-) before that code and use that instead of f(-)? Usually I do this, but I am not fully sure if it is necessary, in particular, when f(-) can be computed really fast.
In case it matters, the language is JavaScript.
if (f(-) satisfies some other condition) will call the same function and it may never enter the block followed by this if, since the function satisfies the outer if that is why it entered into that block.
Create a const and depending on that value execute next step
const isFunResult = f(-);
// expecting this function gives a boolean
if(isFunResult){
// code goes here
}
else{
// code goes here
}
You can also use switch statement if function return multiple result .
In short words, the interpreter is not "intelligent" enough to see that it is enough to calculate it once. So it will call the function twice.
What you are looking for is something called memoization which is used to optimize performance for computational heavy functions to be remembered when the same parameters are passed.
If you need memoization, you could either implement that yourself in your own functions or you could use a javascript framework that supports that. Like React has the useMemo hook.
See https://reactjs.org/docs/hooks-reference.html#usememo
Usually you wont need that and just storing the result of the function in a variable will be enough for most use cases.
Run this to see the examples. Even if the conditions are the same.
function test_me() {
console.log("I got called");
return 99;
}
if (test_me() == 99) console.log("n=99"); // 1st function call
if (test_me() == 99) console.log("n=99"); // 2nd function call
// is different from the following
var n = test_me(); // function called once
if (n == 99) console.log("n=99"); // 1st test
if (n == 99) console.log("n=99"); // 1st test
To answer your question: Yes, it calculates function f(-) TWICE.
More than it is the intelligence of the interpreter, it is the intent of the programmer. The same function can be called twice if the programmer thinks that the function might return a changed value the second time. i.e: if the function uses a new Date() inside the function...
But, if the programmer knows that it is the same output both times (as in your case), it is better to define a constant x = f(-) and reuse it. This will improve performance (if the function is heavy), and improves code maintainability.
Even if it is a compiler, the compiler might not be intelligent enough to detect this, unless the function is a very simple code. But as #perellorodrigo mentioned, you can use memoization, but it is beyond the scope of this answer.
To wrap up, if you call the same function twice, it will be evaluated twice.

Why can't the Iterator.next() method in ES6 just return the value?

To implement an iterator in ES6, one has to implement a method next that returns a structure like this: {value: Any, done: Boolean}.
I understand that the done field is necessary to signal that there are no more values, but I don't understand why the iterator itself couldn't simply have a field/method to do the same job.
As it stands, a new object needs to be created on every iteration step as a defensive measure against potential bugs (e.g. if someone decides to keep a reference to the result) and it seems like a waste of resources, but surely they had a reason to choose this interface.
What am I missing?
[EDIT]
The most obvious possible alternative implementation example I could think of:
function iter(arr) {
var idx = 0, done = false;
return {
isDone: function() {
return done;
},
next: function() {
if(idx >= arr.length - 1) {
done = true;
}
return arr[idx++];
}
};
}
var i = iter([1, 2, 3, 4]);
while(!i.isDone()) {
console.log(i.next());
}
it seems like a waste of resources
It's not really. Engines are quite good at optimising short-lived object allocation. On the other hand, your approach requires two method calls, which aren't free either.
Object creation is unlikely to be cheaper than a method call
That might be where you're mistaken.
Why had they to return two values in the first place when there's a pretty obvious alternative that seems cleaner and more efficient?
Well, it's clear why the two values are needed (an alternative would have been throwing an IterationEnd exception, but that was deemed really ugly). You always need both of them when iterating. So why would they choose two separate methods that always had to be called both (cumbersome and possibly error-prone), when there's a pretty obvious alternative that seems cleaner and more efficient?
For some discussion, see https://esdiscuss.org/topic/performance-of-iterator-next-as-specified.

Javascript recursive function inside a for loop

var f_drum_min = function myself(a){
alert(a);
$f_min_node.push(a);
for (i=0;i<=$m;i++){
if ($f_leg[i][1]==a){
myself($f_leg[i][0]);
}
}
};
myself($f_leg[i][0]); breaks the for loop , how can I make it run multiple times in loop?
Your function is riddled with bad habits
There's no way for me to improve this function because I have no idea what all of those external states do. Nor is it immediately apparent what their data types are.
These are bad habits because there's no possible way to know the effect of your function. Its only input is a, yet the function depends on $f_min_node, $f_leg, and $m.
What is the value of those variables at the time you call your function?
What other functions change those values?
I assigned $f_min_node to some value and then called f_drum_min. How was I supposed to know that $f_min_node was going to get changed?
Every time you call your function, it's a big surprise what happens as a result. These are the woes of writing non-deterministic ("impure") functions.
Until you can fix these problems, recursion in a for-loop the least of your concerns
I have annotated your code with comments here
// bad function naming. what??
var f_drum_min = function myself(a){
// side effect
alert(a);
// external state: $f_min_node
// mutation: $f_min_node
$f_min_node.push(a);
// leaked global: i
// external state: $m
for (i=0;i<=$m;i++){
// external state: $f_leg
// loose equality operator: ==
if ($f_leg[i][1]==a){
myself($f_leg[i][0]);
}
}
};
I can help you write a deterministic recursive function that uses a linear iterative process though. Most importantly, it doesn't depend on any external state and it never mutates an input.
// Number -> Number
var fibonacci = function(n) {
function iter(i, a, b) {
if (i === 0)
return a;
else
return iter(i-1, b, a+b);
}
return iter(n, 0, 1);
}
fibonacci(6); // 8
for loops are pretty primitive; Imperative programmers will reach for it almost immediately thinking it's the only way to solve an iteration problem.
I could've used a for loop in this function, but thinking about the problem in a different way allows me to express it differently and avoid the for loop altogether.
One basic problem with the code, which would cause it to break under almost any circumstances, is that the loop variable i is a global, and is thus shared by all recursive invocations of the function.
For example, let's say the function is invoked for the first time. i is 0. Now it recurses, and let's say that the condition in the if is never true. At the end of the 2nd call, i = $m + 1. When you return to the first call, because i is global, the loop in the first call ends. I assume this is not what you want.
The fix for this is to declare i as local:
for (var i=0;i<=$m;i++){
This may or may not fix all of your problems (as pointed out in comments, we'd have to see more of your code to identify all possible issues), but it is a critical first step.

Don't make functions within loops Javascript

I get that there are possibly three hundred of these questions, and I understand why not to. If we were looping saying a regular for loop, each iteration we are creating an anonymous function expression which is using more memory. Instead we take the function outside of the loop thus giving it a name
Anonymous Function Iteration Example
var elements = document.getElementsByClassName('elementName');
for(var i=0; i < elements.length; i++ )
{
elements[i].addEventListener('click',function(e){
console.log(e);
});
}
Named Function Iteration Example
function handleClickEvents(e) {
console.log(e);
}
var elements = document.getElementsByClassName('elementName');
for(var i=0; i < elements.length; i++ )
{
elements[i].addEventListener('click',handleClickEvents);
}
Problem here is trying to prove someone the logic of this, and to be honest my jsperfs are disproving me completely. Please see the test results for yourself here
So is jsPerf just wrong in the calculations or is this just a myth busted completely? I see that by running the anonymous function as my eventListener function I gain speed compared to the ladder.
Can anyone enlighten me to what the deal is here and why if we gain more speed with the first example should I even bother with two more lines from the second version?
You should not worry about performance-- I hardly imagine you are adding millions of event listeners.
The second alternative (specifying a function reference) is superior in that the function, once defined, could potentially be used in other places. It requires fewer });, and so is less prone to typos. Perhaps more importantly, it is potentially more readable. Let's take the example of passing a function to Array#filter, to check that a filename is a jpg:
names.filter(function(name) {
return /\.jpg$/i.test(name);
});
vs.
function isJpeg(name) { return /\.jpg$/i.test(name); }
names.filter(isJpeg);
If you're chaining methods together, the benefits become more obvious:
names . filter(isJpeg) . map(makeThumbnail) . forEach(uploadJpg);
At the end of the day it doesn't really matter and boils down to personal preference, but the one thing that is clear is that performance concerns should not be what drives your decision, except in very specialized situations. A good general rule is to write very short, one-off functions in-line. With ES6 and arrow functions, more functions can be "very short" and be candidates for inlining.
By the way, even when writing the function in-line, it's often a good idea to give it a name:
names.filter(function isJpeg(name) {
That has a couple of benefits. First, it's a form of documentation/comment and helps people read your code. Second, most debuggers and stack traces will do a better job of reporting about the function. Most minifiers will remove the name so there's no production impact.
I believe there is flaw in your comparison. If you were to reverse the code. Putting the anonymous function later of the comparison. It will be slower. (http://jsperf.com/best-event-listener-practice/5). Later code will always be slower because there has been so many binding has done before.

Which of these cross-browser Javascript functions performs better?

As a rule of thumb, which of these methods of writing cross-browser Javascript functions will perform better?
Method 1
function MyFunction()
{
if (document.browserSpecificProperty)
doSomethingWith(document.browserSpecificProperty);
else
doSomethingWith(document.someOtherProperty);
}
Method 2
var MyFunction;
if(document.browserSpecificProperty) {
MyFunction = function() {
doSomethingWith(document.browserSpecificProperty);
};
} else {
MyFunction = function() {
doSomethingWith(document.someOtherProperty);
};
}
Edit: Upvote for all the fine answers so far. I've fixed the function to a more correct syntax.
Couple of points about the answers so far - whilst in the majority of cases it is a fairly pointless performance enhancement, there are a few reasons one might want to still spend some time analyzing the code:
Has to run on
slow computers, mobile devices, old
browsers etc.
Curiosity
Use the same
general principal to performance
enhance other scenarios where the
evaluation of the IF statement does
take some time.
Unless you're doing this a trillion times, it doesn't matter. Go with the one that is more readable and maintainable to you and/or your organization. The productivity gains you will get from writing clean, simple code matters way more than shaving a tenth of a microsecond off your JS execution time.
You should only even start thinking about what performs better when and only when you've written code and it is unacceptably slow. Then you should start tracking down the bottleneck, which will never be something like this. You will never get a measurable performance gain out of switching from one to the other here.
Unfortunately the code above is not actually cross-browser friendly as it relies on a mozilla quirk not present in other browsers -- namely that function statements are treated as function expressions inside branches. On browsers other that aren't built on mozilla the above code will always use the second function definition. I made a simple testcase to demonstrate this here.
Basically the ECMAScript spec says that function statements are treated similarly to var declarations, eg. they all get hoisted to the top of the current execution scope (eg. the start of a <script> tag, the start of a function, or the start of an eval block).
To clarify olliej's answer, your second method is technically a syntax error. You could rewrite it this way:
var MyFunction;
if(document.browserSpecificProperty) {
MyFunction = function() {
doSomethingWith(document.browserSpecificProperty);
};
} else {
MyFunction = function() {
doSomethingWith(document.someOtherProperty);
};
}
Which is at least correct syntax, but note that MyFunction would only be available in the scope in which that occurs. (Omit var MyFunction;, and preferably use window.MyFunction = function() ... for global.)
Technically, I would say that the second one would perform better, because the if statement is only executed once, rather than every time the function is run.
The difference, however, would be negligible to the point of being meaningless. The performance penalty of a single if statement such as this would be insignificant even compared to the performance penalty of simply calling a function. It would make a smallish difference even if if is called a million times.
The first one is easier to understand, because it doesn't have the awkwardness of defining the same function twice based on a condition, with both versions behaving differently. That seems to be a recipe for confusion later on.
I wouldn't be the first person to say that unless you are really insane about this optimization thing, you'll get more of a win out of code readability.
I generally prefer the second version, as the condition only has to be evaluated once and not on every call, but there are times when it's not really feasible because it will hamper readability.
Btw, this is a case where you might want to use the ?: operator, e.g (taken from production code):
var addEvent =
document.addEventListener ? function(type, listener) {
document.addEventListener(type, listener, false);
} :
document.attachEvent ? function(type, listener) {
document.attachEvent('on' + type, listener);
} :
throwError;
For your simplified example I would do what's below assuming that your browser property check only needs to be done once:
var MyFunction = (function() {
var rightProperty = document.browserSpecificProperty || document.someOtherProperty;
return function doSomethingWith() {
// use the rightProperty variable in your function
}
})();
The performance should be nearly equal!
Thing about using Frameworks like JQuery to get rid of the Browser compability problems!
If performance is your main goal, have a look at SlickSpeed! It is a page which benchmarks different JavaScript frameworks!

Categories

Resources