Я знаю, что опаздываю на вечеринку, но вот более короткий метод, который больше соответствует вашим первоначальным попыткам.
a.replace('f', String.call.bind(a.toUpperCase));
Так в чем же вы ошиблись и что это за новое вуду?
Проблема 1
Как указывалось ранее, вы пытались передать результаты вызываемого метода в качестве второго параметра String.prototype.replace () , тогда как вместо этого вы должны передать ссылку на функцию
Решение 1
Это достаточно легко решить. Простое удаление параметров и скобок даст нам ссылку, а не выполнение функции.
a.replace('f', String.prototype.toUpperCase.apply)
Проблема 2
Если вы попытаетесь запустить код сейчас, вы получите сообщение об ошибке, в котором говорится, что undefined не является функцией и поэтому не может быть вызван. Это связано с тем, что String.prototype.toUpperCase.apply на самом деле является ссылкой на Function.prototype.apply () через прототипное наследование JavaScript. То, что мы делаем на самом деле, выглядит примерно так
a.replace('f', Function.prototype.apply)
Это явно не то, что мы планировали. Как он узнает, что нужно запустить Function.prototype.apply () в String.prototype.toUpperCase () ?
Решение 2
Используя Function.prototype.bind (), мы можем создать копию Function.prototype.call со специально установленным контекстом String.prototype.toUpperCase. Теперь у нас есть следующие
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Проблема 3
Последняя проблема заключается в том, что String.prototype.replace () передаст несколько аргументов своей функции замены. Однако Function.prototype.apply () ожидает, что второй параметр будет массивом, но вместо этого получает либо строку, либо число (в зависимости от того, используете ли вы группы захвата или нет). Это вызовет ошибку списка недопустимых аргументов.
Решение 3
К счастью, мы можем просто заменить в Function.prototype.call () (которая принимает любое количество аргументов, ни один из которых не имеет ограничений типа) на Function.prototype.apply () . Мы подошли к рабочему коду!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Сбрасывание байтов!
Никто не хочет набирать прототип много раз. Вместо этого мы воспользуемся тем фактом, что у нас есть объекты, которые ссылаются на одни и те же методы через наследование. Конструктор String, будучи функцией, наследуется от прототипа функции. Это означает, что мы можем заменить в String.call Function.prototype.call (на самом деле мы можем использовать Date.call, чтобы сохранить еще больше байтов, но это менее семантично).
Мы также можем использовать нашу переменную 'a', поскольку ее прототип включает ссылку на String.prototype.toUpperCase, мы можем заменить ее на a.toUpperCase. Это комбинация трех вышеперечисленных решений и этих мер по экономии байтов - вот как мы получаем код в верхней части этого поста.