Jump to content

[Javascript] Can a function call itself?

G1K777

Hi,

can a function call itself?

 

function create(element) {
    let prefix = element[0],
        suffix = element[1],
        node = document.createElement(prefix);

    // Check if suffix is a string.
    if( typeof suffix === "string" ) node.appendChild(document.createTextNode(suffix));
	
    // Is the suffix is a array, call itself to create a function.
    if( element[1] instanceof Array ) {
      return create(this); // <-- ?????
    }

    return node;

  }

  var element1 = create(["div","hi"]); // Output: <div>hi</div>
  document.body.appendChild(element1);
  var element2 = create(["div",["p","My paragraph."]]); // Expected: <div><p>My paragraph.</p></div>
  document.body.appendChild(element2);

 

AMD FX8320 | GTX660 | 4x4GB DDR3 | LG ZR2740W

Logitech Wireless Pro  | Logitech G413 | Nuforce uDAC5  | AKG K612

Link to comment
Share on other sites

Link to post
Share on other sites

Is there any difference between:
 

Array.prototype.slice.call(myArr);
// vs
myArr.slice();
// ?

The prototype is way longer, does it affect the performance or something?

AMD FX8320 | GTX660 | 4x4GB DDR3 | LG ZR2740W

Logitech Wireless Pro  | Logitech G413 | Nuforce uDAC5  | AKG K612

Link to comment
Share on other sites

Link to post
Share on other sites

13 hours ago, G1K777 said:

Is there any difference between:
 


Array.prototype.slice.call(myArr);
// vs
myArr.slice();
// ?

The prototype is way longer, does it affect the performance or something?

In the first you are directly accessing the method. In the second you are accessing the same method that is inherited from your declared type. There will be performance differences, but they will be so small that its irrelevant in any application. (the performance difference is less than you'd see by overclocking your PC by 1mhz).

Link to comment
Share on other sites

Link to post
Share on other sites

2 hours ago, Erik Sieghart said:

Rewrite your algorithm to not be recursive. It's harder to read and less performant.

^^^this^^^. Recursion is a great tool. For thinking and proving that things are correct. For real world implementations, you need to reformat the recursive function as an iterative function. One of the side effects of the Church-Turing Thesis is that every recursion function can be turned into an iterative function.

In addition to the stack space problem, recursion also results in a series of function calls, while iteration results in a series of branches. As a metaphor, function calls move just about as fast as rocks compared to branches.

The way that function/subroutine calls work differs from machine to machine and implementation to implementation, but it goes something like:

  1. Push all arguments onto the stack.
  2. Save all the registers.
  3. Jump to the subroutine.
    1. Get all arguments off the stack
    2. Do my work.
    3. Jump to the caller.
  4. Get all returns off the stack.
  5. Restore all the registers.

Be aware that Javascript is a JIT language, so there can be some optimization on function calls, but they are still extremely slow compared to loops.

 

Whereas a loop looks something like:

  1. Create a variable N + 1
  2. Decrement N.
  3. Check if N is greater than 0.
    1. If so, do calculations.
    2. Goto step 2.
  4. You're done. No clean-up required.

 

 

ENCRYPTION IS NOT A CRIME

Link to comment
Share on other sites

Link to post
Share on other sites

As everyone said before, using recursive function mostly is a no-no.
It potentially can use a lot more memory and a lot more RAM and CPU. Someone browsing website with low-end phone/PC/toaster would probably will have terrible experience.
Also potentially it can run to infinity and beyond (bad code, bad data) eating all resources on client and/or server (imagine your recursive function calls API, oh boy).

 

At start of my software developer carrier i've had couple of upsyies with recursive function bringing down servers. I was writing application to load ancestry tree and in some cases data was corrupted (great grandpa was a child to his great grandson). Lot's of fun.

Link to comment
Share on other sites

Link to post
Share on other sites

@Erik Sieghart

I get the speed thing....

https://jsperf.com/array-prototype-slice-call-vs-slice-call/12

But I dont understand why it would affect stack space and cant find anything on it.  Would you have any links I could read?  I have a little understanding of stack stuff but not this.

Unless you meant the recursion thing, which makes sense.

Link to comment
Share on other sites

Link to post
Share on other sites

Is this a recursive function? I have no idea what you mean by recusive function.

 

function create(x){
  let element = x[0],
      child = x[1],
      node = document.createElement(element),
      i = 1;

  if (typeof child === "object" && child !== null && !isArray(child))
    for (var attr in child) node[attr] = child[attr];
    i = 2;

  let l = x.length;
  for (; i < l; i++)
    if( isArray(x[i]) ) node.appendChild( create(x[i]) );
    else node.appendChild( document.createTextNode(x[i]) );

  return node;
}

 

AMD FX8320 | GTX660 | 4x4GB DDR3 | LG ZR2740W

Logitech Wireless Pro  | Logitech G413 | Nuforce uDAC5  | AKG K612

Link to comment
Share on other sites

Link to post
Share on other sites

5 hours ago, G1K777 said:

Is this a recursive function? I have no idea what you mean by recusive function. 

That is not a recursive function.

Recursion can be a somewhat hard concept to grasp, but it is actually quite simple.

Let's think about the following, non javascript, program:

// This is a non recursive, non iterative function 
// that adds two numbers
int Add(int a, int b)
{
  return a + b;
}

Let's rewrite that a slightly different way:

// This is an iterative function
// that adds two numbers.
int Add(int a, int b)
{
  for (; b > 0; b--)
    a += 1;
  
  return a;
}

 

We can make the above function recursive if we define a few things: A recursive condition and an exit condition.

In this case, our exit condition is relatively simple: if b is equal to zero, we want to return a.

Our recursive condition would then be: If b is not equal to zero, we want to return Add(a + 1, b - 1)

 

That looks like this:

// A recursive function to
// add two numbers.
int Add(int a, int b)
{
  if (b == 0)
    return a;
  
  else
    return Add(a + 1, b - 1);
}


But there is a big problem with both of our modified Add() functions. Neither of them return the correct result if b is negative. But it gets worse than that.

In the iterative function, if B is negative, we simply don't pass the loop condition and we return a. This is an incorrect result, but the system doesn't come crashing down.
 

However, in the recursive function, if B is negative, then subtracting positive 1 from b will never cause it to become 0, and we get a stack overflow error, causing program execution to stop. Unless, of course, you are lucky enough to have a stack that can handle a recursion depth large enough to accommodate b wrapping around and becoming positive, and then becoming zero. If you're interested, that will take 4,294,967,296 - abs(b) recursive calls (atleast on systems with a 32 bit integer type)

Now, reread the last sentence of the previous paragraph. I told you that to tell you arguably the biggest or second biggest reason why you don't ever want to use recursion in a real implementation: Imagine if there is some function which does not reach a stack overflow error for all invalid inputs, but sometimes does, and sometimes just gives an incorrect result. Now, imagine trying to debug that. How will you know why it sometimes returns a correct result, sometimes returns an incorrect result, and sometimes throws a stack overflow error? What's worse, the conditions that cause a stack overflow error may differ from system to system, meaning that bug reports from users contain misaligned and sporadic information about what inputs are causing the stack overflow errors, making it even harder to find the problem.

 

Simply put, a recursive function is any function which might return a function call to itself.

ENCRYPTION IS NOT A CRIME

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×