Я знаю, що запізнився на вечірку, але ось коротший метод, який більше відповідає вашим початковим спробам.
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. Саме комбінація 3-х рішень, наведених вище, та цих заходів щодо економії байтів, є тим, як ми отримуємо код у верхній частині цього повідомлення.