Em javascript, quero fazer uma cópia (superficial) de um Function
, para que as propriedades do novo objeto não sejam afetadas pelo objeto original:
function func(...) { ... } // to say, function func(x, y) { return [x,y] }
func.a = 1
let func1 = func // without copy, func1 and func IS the same object
let func2 = copy(func) // need to be implemented
func.a = 2
func1.a // becomes 2
func2.a // shall still be 1
func2("abc") // shall return the same result as func("abc")
É possível?
A melhor maneira que encontrei no momento é definir uma função wrapper:
function f0(x, y) { return [x,y] }
f0.a = 1
function copy(fn){
function wrapper(){
return fn.apply(wrapper, arguments)
}
Object.assign(wrapper,fn)
return wrapper
}
let f2 = copy(f0)
f0.a = 2
f2.a // is still 1
f0.length // gives 2
f2.length // gives 0
Entretanto, há alguns problemas com esta solução:
- A aplicação em cadeia de
copy
levará a vários níveis de wrapper. por exemplo,copy(copy(copy(fn)))
retornará uma função com três wrappers. - a
length
função de origem é perdida,wrapper.length
é sempre0
.
Os principais problemas que vejo são
fn
aowrapper
, não aothis
Object.assign
copia apenas as propriedades enumeráveis (próprias) e apenas seus valores. (Isso inclui seu problema com.length
, mas também com.name
, e, claro, outras propriedades personalizadas)Function.prototype
, ela não necessariamente tem o mesmo protótipo quefn
.Isso não é necessariamente inesperado. Mas se você quisesse resolver isso, precisaria de uma maneira de extrair o original
fn
de qualquer função wrapper; isso pode ser feito usando umWeakMap
.Para fazer uma cópia superficial de uma função (ou seja, copiar seu comportamento invocável e suas próprias propriedades), você precisará fazer algumas coisas:
Crie uma nova função que se comporte da mesma maneira.
Copie as propriedades enumeráveis próprias da função original.
EDITADO:
conforme sugerido acima, a solução tem problemas de múltiplos wrappers e o comprimento é perdido, pois a nova função é variável
((...args))
então agora o que podemos fazer é reconstruir a função usando sua representação de string, isso evitará cadeias de wrapper profundas.
NOTA: esta solução tem a limitação de que não funcionará para funções nativas que não podem ser transformadas em strings, por exemplo, funções vinculadas, fechamentos com dependências externas, mas funcionará para funções simples