Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

254
Views
Hacer una copia verdadera de una función en Javascript

Me gustaría definir dos funciones (o clases) en Javascript con exactamente el mismo cuerpo de función, pero que sean objetos completamente diferentes. El caso de uso para esto es que tengo una lógica común en el cuerpo que es polimórfica (la función puede aceptar múltiples tipos), pero al llamar a la función con un solo tipo, la función termina más rápido, supongo que ya que el JIT puede tomar un camino rápido más feliz en cada caso.

Una forma de hacerlo es simplemente repetir el cuerpo de la función por completo:

 function func1(x) { /* some body */ } function func2(x) { /* some body */ }

Otra forma de lograr lo mismo con menos repetición es eval() :

 function func(x) { /* some body */ } function factory() { return eval("(" + func.toString() + ")") } let func1 = factory(), func2 = factory()

La desventaja de eval() , por supuesto, es que cualquier otra herramienta (minificadores, optimizadores, etc.) se toman completamente por sorpresa y tienen el potencial de alterar mi código para que esto no funcione.

¿Hay alguna forma sensata de hacer esto dentro de los límites de una cadena de herramientas estándar (yo uso Typescript, esbuild y Vite), sin usar trucos de eval() o simplemente copiar y pegar el código? También tengo la pregunta análoga sobre las definiciones de clase.


Editar: para resumir lo que ha estado sucediendo en los comentarios:

  1. Sí, la diferencia de rendimiento es real y medible (especialmente en Chrome, menos pronunciada en Firefox y Safari), como lo demuestra este microbenchmark . El programa real que motiva esta pregunta es mucho más grande y las diferencias de rendimiento son mucho más pronunciadas, sospecho que porque el JIT puede hacer más en línea para funciones monomórficas, lo que tiene muchos efectos colaterales.
  2. La solución obvia de devolver un cierre no funciona, es decir
     function factory() { function func() { /* some body */ } return func } let func1 = factory(), func2 = factory()
    como lo demuestra este segundo microbenchmark . Esto se debe a que un JIT solo compilará el cuerpo de una función una vez, incluso si es un cierre.
  3. Puede darse el caso de que esta ya sea la mejor solución, al menos cuando se trabaja dentro de una cadena de herramientas JS/Typescript estándar (que no incluye funciones de generación de código o macro).
over 4 years ago · Santiago Trujillo
4 answers
Answer question

0

puedes probar de esta manera:

 function func1(x) { /* some body */ } var func2 = new Function("x", func1.toString().match(/{.+/g)[0].slice(1,-1));

Estoy definiendo la nueva función func2(x) usando el constructor de funciones donde los primeros n-1 argumentos son parámetros y el último parámetro es el cuerpo de la función

para el cuerpo de la función, utilicé expresiones regulares para extraer todas las líneas en el alcance de func1 es decir, entre las llaves de función { y }

puede leer más sobre el constructor de funciones aquí

over 4 years ago · Santiago Trujillo Report

0

Jugando con la Function constructora de funciones, supongo que esto haría el trabajo

 function func(x) { /* some body */ } function factory() { return ( new Function('return ' + func.toString()) )(); } let func1 = factory(), func2 = factory()
over 4 years ago · Santiago Trujillo Report

0

  1. Utilice el sistema de archivos para hacer que un solo archivo de módulo ESM aparezca como varios archivos diferentes.
  2. Luego importe su función varias veces.

El único requisito de la cadena de herramientas es esbuild, pero también funcionarán otros paquetes como rollup:

Producción:

 // From command: esbuild main.js --bundle (() => { // .func1.js function func(x2) { return x2 + 1; } // .func2.js function func2(x2) { return x2 + 1; } // main.js func(x) + func2(x); })(); // From command: rollup main.js function func$1(x) { return x+1 } function func(x) { return x+1 } func$1(x) + func(x);

Con estos archivos como entrada:

 // func.js export function func(x) { return x+1 }
 // main.js import {func as func1} from './.func1'; import {func as func2} from './.func2'; func1(x) + func2(x)

Los archivos importados son en realidad enlaces duros al mismo archivo generado por este script:

 #!/bin/sh # generate-func.sh ln func.js .func1.js ln func.js .func2.js

Para evitar que los enlaces duros arruinen tu repositorio, dile a git que ignore los enlaces duros generados. De lo contrario, los enlaces duros pueden divergir como archivos separados si se registran y desprotegen nuevamente:

# .gitignore
.func*

notas

  • Puse todo en la misma carpeta por simplicidad, pero puede generar los enlaces duros en su propia carpeta para la organización.
  • Rollup "verá a través" de este truco si usa enlaces simbólicos al mismo archivo JS. Sin embargo, los enlaces simbólicos a los directorios funcionan bien.
  • Probado en git-bash para Windows; YMMV en otras plataformas.
over 4 years ago · Santiago Trujillo Report

0

Su idea de tener una "fábrica" o una función maestra que produciría funciones independientes, físicamente separadas, en lugar de hacer referencia a la misma es un muy buen comienzo...

Antes de las animaciones CSS, teníamos que usar JavaScript para crear efectos cronometrados, etc. La idea de pasar el mouse sobre elementos que los iluminarían, pero a medida que el mouse deja ese elemento sobre el otro, querrás que se desvanezcan lentamente (dejando un rastro suave de luz a la moda), no abruptamente sobre cientos de elementos, sería imposible hacerlo con una sola función, mientras que reescribir el mismo cuerpo de función con nombres ligeramente diferentes cientos de veces no tendría sentido, y mucho menos asignar cada función al elemento de destino individualmente.

Nos enfrentamos al mismo problema...

Para acortar la historia, teníamos que ir con una 'solución sensata' como dices, o abandonar la idea por completo... ¡Yo no lo hice!

Aquí hay una lógica detrás de la solución (de fábrica) y un contenido de registro de la consola para demostrar que estas funciones gemelas idénticas están separadas físicamente (según sea necesario) y no hacen referencia a las mismas.

 function Factory( x ){ return function( ){ console.log( x ) } }; func1 = new Factory("I'm the first born!"); func2 = new Factory("I'm the second born!"); func1(); func2();

Espero que encuentre esta solución lo suficientemente sensata.

pd: puede agregar tantos argumentos como necesite a Factory y proporcionar sus valores específicos durante la creación de las funciones que estarán disponibles durante la sesión en todo momento, tal como lo está la cadena console.log que vemos en la demostración.

Saludos.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!