f.apply(x, y) is x.f(the contents of y).
Where f is arr1.push, x is arr1, and y is arr2,
that's arr1.push.apply(arr1, arr2) is arr1.push(the contents of arr2).
Note, arr1.push adds all its arguments to arr1, so arr1.push(arr2) adds arr2 to arr1, making it ['a', 'b', ['c', 'd']].
Where f is Math.max, and y is [-1, 5, 11, 3],
that's Math.max.apply(x, [-1, 5, 11, 3]).
But what do you put in x?
Math.max is made to work as function called on its own, not as a method of an object.
If you leave out x and do Math.max.apply([-1, 5, 11, 3]), Math.max will think it's being called as a method of the array and without any arguments.
So it will give the result of Math.max().
So then you have to put something in the x, and it doesn't matter what, because Math.max is not made to use it, so it will ignore it.
The best value you can give x is the simplest, which is null.
If you're wondering what a line of Javascript code will do, it's a good idea to test it.
Firefox and Chrome both have a built-in Javascript command-line you can use, and there are websites that do Javascript command-lines too.
I used Firefox > Tools > Web Developer > Web Console to check my answer.