Q:

Chaining .apply() and .bind() surprising behaviour

I need your help to better understand the following behavior.
In the snippet below, we can see that fooBar outputs foo as this and then returns bar 1, 2, 3 as expected - means bar is called with foo as context.

const arguments = [1,2,3];

function bar(...args) {
  console.log('bar this ->', this);
  return 'bar ' + args;
}

function foo(...args) {
  console.log('foo this ->', this);
  return 'foo ' + args;
}

const fooBar = bar.bind(foo, null)(arguments);

console.log(fooBar); // <--- no surprises!

Let's now have const bar = Math.max.apply; instead.

const arguments = [1,2,3];

const bar = Math.max.apply;

function foo(...args) {
  console.log('foo this ->', this);
  return 'foo ' + args;
}

const fooBar = bar.bind(foo, null)(arguments);

console.log(fooBar); // <--- surprise!

In this case, foo is being called as opposed to bar. Why? What is bind() exactly doing under the hood in this case? I'd have assumed that again bar should be called with foo as a context. The context, in this case, is window. 
I always thought someFunction.apply(someContext, args) behaves as someFunction.bind(someContext, null)(args), but in the second example someFunction.bind(someContext, null)(args) behaves as someContext(args).

A:

This is because of the specific purpose of apply: to call a given function. Remember that bar is the generic Function.prototype.apply function.
bind essentially creates a copy of the original function, with the context (this value) and (optionally) arguments preset. A polyfill for bind would use apply internally.
So fooBar = bar.bind(foo, null) is the same as
function fooBar(...args) {
    return Function.prototype.apply.apply(foo, [null, args]);
}

The double use of apply is obviously confusing!
Let's step through what bar.bind(foo, null)(arguments) would do:
Function.prototype.apply.bind(foo, null)(arguments)

which can be reduced to
Function.prototype.apply.apply(foo, [null, arguments])

which in this specific instance is the same as
foo(null, ...arguments);

The reason this is so confusing is that you are doing a complex invocation of the apply function, which is designed for complex invocations of functions!

