Как функции декораторы работают изнутри?
Что делает декоратор — получает одну и создаёт новую функцию.

Пример из жизни. Декоратор == мастерская жуликов. Был обычный банкомат (функция). Засунули его в мастерскую злодеев и получили новый банкомат. Новый банкомат выглядит как прежний, но внутри теперь ещё и отправляет данные карты и введённые пин-коды злодеям. При этом свои внешние обычные действия он продолжает выполнять: принимает карту, показывает баланс.

 1. Каким образом аргумент функции double() передаётся в аргумент функции, которую возвращает декоратор? 
Наоборот: теперь работают с новой функцией, которую вернул декоратор. А уже она, внутри, вызывает double() в которую и передаёт аргумент, с которым её вызвали.

 2. Почему не работает прямой вызов функции-декоратора?  decorator(double(5)) в таком варианте аргументом в decorator() попадает что? — не сама функция double, а результат её выполнения с аргументом 5.

Наверное, вам пока непривычно, что аргументом функций может быть не только, скажем, число,
а и целая функция. Почувствуйте разницу:(fn2( fn1 ))(arg)
// fn2 получает аргументом функцию fn1
// возвращает новую функцию, и уже та выполняется
// с аргументом arg

fn2( fn1( arg ))
// fn1 выполняется с аргументом arg
// результат попадает аргументом в fn2
// возвращается результат вызова fn2
function double(num) {
    return num * 2;
}
function decorator(innerFn) {
    return function (num) {
        if(isNaN(num)) {
            throw new TypeError('Ошибка! Не число.');
        }
        return innerFn(num);
    };
}

const decoratedDouble = decorator(double);
alert(decoratedDouble(5));

decorator просто оборачивает переданную функцию в другую(`function (x)`) и возвращает её.
decorator(double(5))
не работает потому что ты напрямую вызываешь double, в результате в decorator передается 10(5*2), а не double.

В js есть класс Proxy позволяющий упростить подобные действия.