Ich weiß, dass ich zu spät zur Party komme, aber hier ist eine kürzere Methode, die eher Ihren ersten Versuchen entspricht.
a.replace('f', String.call.bind(a.toUpperCase));
Wo hast du etwas falsch gemacht und was ist das für ein neues Voodoo?
Problem 1
Wie bereits erwähnt, haben Sie versucht, die Ergebnisse einer aufgerufenen Methode als zweiten Parameter von String.prototype.replace () zu übergeben , wenn Sie stattdessen einen Verweis auf eine Funktion übergeben sollten
Lösung 1
Das ist leicht zu lösen. Durch einfaches Entfernen der Parameter und Klammern erhalten wir eine Referenz, anstatt die Funktion auszuführen.
a.replace('f', String.prototype.toUpperCase.apply)
Problem 2
Wenn Sie versuchen, den Code jetzt auszuführen, wird eine Fehlermeldung angezeigt, dass undefined keine Funktion ist und daher nicht aufgerufen werden kann. Dies liegt daran, dass String.prototype.toUpperCase.apply tatsächlich ein Verweis auf Function.prototype.apply () über die prototypische Vererbung von JavaScript ist. Was wir also tatsächlich tun, sieht eher so aus
a.replace('f', Function.prototype.apply)
Welches ist offensichtlich nicht das, was wir beabsichtigt haben. Woher weiß es, Function.prototype.apply () auf String.prototype.toUpperCase () auszuführen ?
Lösung 2
Mit Function.prototype.bind () können wir eine Kopie von Function.prototype.call erstellen, deren Kontext speziell auf String.prototype.toUpperCase festgelegt ist. Wir haben jetzt folgendes
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Problem 3
Das letzte Problem ist, dass String.prototype.replace () mehrere Argumente an seine Ersetzungsfunktion übergibt . Function.prototype.apply () erwartet jedoch, dass der zweite Parameter ein Array ist, erhält jedoch entweder eine Zeichenfolge oder eine Zahl (je nachdem, ob Sie Erfassungsgruppen verwenden oder nicht). Dies würde einen ungültigen Argumentlistenfehler verursachen.
Lösung 3
Glücklicherweise können wir Function.prototype.apply () einfach in Function.prototype.call () ersetzen (das eine beliebige Anzahl von Argumenten akzeptiert, von denen keines Typeinschränkungen aufweist) . Wir sind jetzt beim Arbeitscode angekommen!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Bytes verlieren!
Niemand möchte ein paar Mal einen Prototyp schreiben. Stattdessen nutzen wir die Tatsache, dass wir Objekte haben, die über die Vererbung auf dieselben Methoden verweisen. Der String-Konstruktor ist eine Funktion und erbt vom Prototyp der Funktion. Dies bedeutet, dass wir Function.prototype.call in String.call ersetzen können (tatsächlich können wir Date.call verwenden, um noch mehr Bytes zu speichern, aber das ist weniger semantisch).
Wir können auch unsere Variable 'a' nutzen, da ihr Prototyp einen Verweis auf String.prototype.toUpperCase enthält. Wir können diesen mit a.toUpperCase austauschen. Durch die Kombination der drei oben genannten Lösungen und dieser Maßnahmen zum Speichern von Bytes erhalten wir den Code oben in diesem Beitrag.