It all has to do with what is in the accumulator (high). If you don't provide the second argument to reduce, the accumulator starts off as the first object, and the current element is the second element. In your first iteration, you treat the accumulator as the object, fetching the grade using high.grade; but then you return a number (94), and not an object, to be your next accumulator. In the next iteration of the loop, high is not an object any more but 94, and (94).grade makes no sense.
When you remove the third element, there is no second iteration, and there is no time for the bug to occur, and you get the value of the current accumulator (94). If there were only one element, you'd get the initial accumulator ({name: 'Leah', grade: 94}). This is, obviously, not ideal, as you can't reliably predict the shape of the result of your calculation (object, number or error).
You need to decide whether you want the number or the object, one or the other.
let highest = students.reduce(
(high, current) => Math.max(high, current.grade),
Number.NEGATIVE_INFINITY
)
This variant keeps the accumulator as a number, and will return 94. We can't rely on the default starting accumulator, as it needs to be a number, so we set it artificially at -INF.
let highest = students.reduce(
(high, current) => high.grade > current.grade ? high : current,
)
This is the object version, where highest ends up with {name: 'Leah', grade: 94}.
highandcurrent. You should be able to figure out the problem soon enough.