Wiem, że spóźniłem się na imprezę, ale tutaj jest krótsza metoda, która jest bardziej podobna do twoich początkowych prób.
a.replace('f', String.call.bind(a.toUpperCase));
Więc gdzie popełniłeś błąd i co to za nowe voodoo?
Zadanie 1
Jak wspomniano wcześniej, próbujesz przekazać wyniki wywoływanej metody jako drugi parametr metody String.prototype.replace () , podczas gdy zamiast tego powinieneś przekazać referencję do funkcji
Rozwiązanie 1
To dość łatwe do rozwiązania. Po prostu usunięcie parametrów i nawiasów da nam odniesienie zamiast wykonywania funkcji.
a.replace('f', String.prototype.toUpperCase.apply)
Problem 2
Jeśli spróbujesz teraz uruchomić kod, pojawi się błąd informujący, że undefined nie jest funkcją i dlatego nie można go wywołać. Dzieje się tak, ponieważ String.prototype.toUpperCase.apply jest w rzeczywistości odwołaniem do funkcji Function.prototype.apply () poprzez prototypowe dziedziczenie JavaScript. Więc to, co faktycznie robimy, wygląda bardziej tak
a.replace('f', Function.prototype.apply)
Co oczywiście nie jest tym, czego chcieliśmy. Skąd wie, że należy uruchomić Function.prototype.apply () na String.prototype.toUpperCase () ?
Rozwiązanie 2
Używając funkcji Function.prototype.bind () możemy utworzyć kopię Function.prototype.call z jej kontekstem ustawionym specjalnie na String.prototype.toUpperCase. Mamy teraz następujące
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Problem 3
Ostatnią kwestią jest to, że String.prototype.replace () przekaże kilka argumentów do swojej funkcji zastępującej. Jednak funkcja Function.prototype.apply () oczekuje, że drugi parametr będzie tablicą, ale zamiast tego pobiera ciąg lub liczbę (w zależności od tego, czy używasz grup przechwytywania, czy nie). Spowodowałoby to nieprawidłowy błąd listy argumentów.
Rozwiązanie 3
Na szczęście możemy po prostu podstawić w Function.prototype.call () (który akceptuje dowolną liczbę argumentów, z których żaden nie ma ograniczeń typu) dla Function.prototype.apply () . Doszliśmy do działającego kodu!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Utrata bajtów!
Nikt nie chce pisać prototypu kilka razy. Zamiast tego wykorzystamy fakt, że mamy obiekty, które odwołują się do tych samych metod poprzez dziedziczenie. Konstruktor String, będący funkcją, dziedziczy po prototypie Function. Oznacza to, że w String.call możemy zastąpić Function.prototype.call (w rzeczywistości możemy użyć Date.call, aby zapisać jeszcze więcej bajtów, ale to mniej semantyczne).
Możemy również wykorzystać naszą zmienną „a”, ponieważ jej prototyp zawiera odniesienie do String.prototype.toUpperCase, które możemy zamienić na a.toUpperCase. Jest to połączenie powyższych 3 rozwiązań i tych środków oszczędzania bajtów, dzięki czemu otrzymujemy kod na początku tego postu.