Yes, your example is recursive.
Any function that contains a reachable invocation of itself is recursive.
Recursion like this is leveraging the recursive function invocation feature of JavaScript.
Before ALGOL-60 in 1960 (although Lisp was defined around that time, its compiler came later), languages did not support convenient user-land recursion for two reasons:
First, early languages were register-based. Subroutine instructions would save the current memory location in the jump address, and then set the program counter to the next address. This was simpler than maintaining a stack, but it meant the programmer had to effectively implement their own recursion inside the language. When stack-based languages were introduced, recursion became easier.
Second, it was seen as being computationally expensive to achieve (and CPUs were pretty weedy back then).
JavaScript is an example of a stack-based language (as most (all?) modern languages are).
This means that the location in the execution of your program is defined by a stack data structure. The stack was chosen for this task because it offers the required last-in first-out (LIFO) behavior needed for nested subroutine calls.
The items on the stack are called stack frames or simply frames (sometimes they are called activation records) and they correspond to invoked subroutines in your program (the top frame being current). Each frame contains metadata associated with the subroutine call, and this varies with each language.
In JavaScript stack frames are called Execution Contexts, and the EcmaScript specification defines the metadata they contain.
In your example:
01 function isEven(number) {
02 if (number == 0)
03 return true;
04 else if (number == 1)
05 return false;
06 else if (number<0) {
07 number*=-1
08 return isEven(number)
09 }
10 else
11 return isEven(number-2)
12 };
13
14 console.log(isEven(2)); // 2 chosen for simplicity.
// >> << indicates the currently executing expression.
Expression | Current stack
--------------------------------------------------------
14 console.log(>>isEven(2)<<); | [
| { fn: global, arguments: [], ... }
| ]
11 return >>isEven(0)<<; | [
| { fn: isEven, arguments: [2], ... },
| { fn: global, arguments: [], ... }
| ]
03 >>return true<<; | [
| { fn: isEven, arguments: [0], ... },
| { fn: isEven, arguments: [2], ... },
| { fn: global, arguments: [], ... }
| ]
11 >>return isEven(0)<<; | [
| { fn: isEven, arguments: [2], ... },
| { fn: global, arguments: [], ... }
| ]
14 >>console.log(isEven(2));<< | [
| { fn: global, arguments: [], ... }
| ]
>>end of program<< | [
| ]