Yes. It is guaranteed to be pure.
The reason is that it only depends on bound and immutable free variables.
However, this code breaks the rule of accessing external function's scope.
There is nothing in your quote that says you cannot access free variables. It says external input as reading from a file, network, etc not a free variable from a previous scope.
Even Haskell use global function names like foldr and it is a free variable in every function it is used and of course the result is pure.
Remember that functions by name is just variables. parseInt is a variable that points to a function so it would have been hard to make anything at all if every function you should use in another function be passed as parameter.
If you redefine parseInt to something that is not pure or during the duration of your program so that it works differently then no function calling it would be pure.
Function composition and partial evaluation work because they supply free variables. Its an essential method of abstraction in functional programming. eg.
function compose(f2, f1) { return (...args) => f2(f1(...args)); } function makeAdder(initialValue) { return v => v + initialValue; } const add11 = compose(makeAdder(10), makeAdder(1)); add11(5); // ==> 16
This is pure. The closure variable / free variable f1, f2, initialValue never changes for the created functions. add11 is a pure function.
Now look at compose again. It looks pure but it can be tainted. If not both functions passed to it were pure the result isn't either.
OO can be purely functional too!
They can easily be combined by not mutating the objects you create.
class FunctionalNumber { constructor(value) { this.value = value; } add(fn) { return new FunctionalNumber(this.value + fn.value); } sub(fn) { return new FunctionalNumber(this.value - fn.value); } }
This class is purely functional.
In fact you can think of a method call like obj.someMethod(arg1, arg2) as a function call with obj as first argument someFunction(obj, arg1, arg2). It's only syntactic differences and if someFunction mutated obj you would have said it was not pure. This is how it is with someMethod and obj too.
You can make classes that work on large data structures that are functional, which means you never have to copy it before changing when doing a backtracking puzzle solver. A simple example is the pair in Haskell and Lisp. Here is one way to make it in JavaScript:
class Cons { constructor(car, cdr) { this.car = car; this.cdr = cdr; } } const lst = new Cons(1, new Cons(2, new Cons(3, null))); const lst0 = new Cons(0, lst);
lst0 is lst but with a new element in front. lst0 reuses everything in lst. Everything from lists to binary trees can be made with this and you can make many sequential data structures with immutable binary trees. It's been around since the 50s.
timesTenis a pure function. You have no guarantee for referential transparency in Javascript though. Hence it would probably be more appropriate to say that you can be confident that your function is pure.