Sé que llego tarde a la fiesta, pero aquí hay un método más corto que está más en la línea de sus intentos iniciales.
a.replace('f', String.call.bind(a.toUpperCase));
Entonces, ¿en qué te equivocaste y qué es este nuevo vudú?
Problema 1
Como se indicó anteriormente, estaba intentando pasar los resultados de un método llamado como el segundo parámetro de String.prototype.replace () , cuando en su lugar debería pasar una referencia a una función
Solución 1
Eso es bastante fácil de resolver. Simplemente eliminar los parámetros y los paréntesis nos dará una referencia en lugar de ejecutar la función.
a.replace('f', String.prototype.toUpperCase.apply)
Problema 2
Si intenta ejecutar el código ahora, obtendrá un error que indica que undefined no es una función y, por lo tanto, no se puede llamar. Esto se debe a que String.prototype.toUpperCase.apply es en realidad una referencia a Function.prototype.apply () a través de la herencia prototípica de JavaScript. Entonces, lo que estamos haciendo se parece más a esto
a.replace('f', Function.prototype.apply)
Que obviamente no es lo que pretendíamos. ¿Cómo sabe ejecutar Function.prototype.apply () en String.prototype.toUpperCase () ?
Solucion 2
Usando Function.prototype.bind () podemos crear una copia de Function.prototype.call con su contexto específicamente establecido en String.prototype.toUpperCase. Ahora tenemos lo siguiente
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Problema 3
El último problema es que String.prototype.replace () pasará varios argumentos a su función de reemplazo. Sin embargo, Function.prototype.apply () espera que el segundo parámetro sea una matriz, pero en cambio obtiene una cadena o un número (dependiendo de si usa grupos de captura o no). Esto provocaría un error de lista de argumentos no válidos.
Solución 3
Afortunadamente, podemos simplemente sustituir Function.prototype.call () (que acepta cualquier número de argumentos, ninguno de los cuales tiene restricciones de tipo) por Function.prototype.apply () . ¡Hemos llegado al código de trabajo!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
¡Eliminando bytes!
Nadie quiere escribir un prototipo muchas veces. En su lugar, aprovecharemos el hecho de que tenemos objetos que hacen referencia a los mismos métodos a través de la herencia. El constructor String, al ser una función, hereda del prototipo de Function. Esto significa que podemos sustituir String.call por Function.prototype.call (en realidad, podemos usar Date.call para guardar aún más bytes, pero eso es menos semántico).
También podemos aprovechar nuestra variable 'a' ya que su prototipo incluye una referencia a String.prototype.toUpperCase , podemos intercambiar eso con a.toUpperCase. Es la combinación de las 3 soluciones anteriores y estas medidas de ahorro de bytes que es como obtenemos el código en la parte superior de esta publicación.