In javascript, I want to make a (shallow) copy of a Function
, so that the properties of the new object will not be affected by the original object:
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")
Is it possible?
The best way I've found at present is defining a wrapper function:
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
However, there are some problems with this solution:
copy
will lead to multiple levels of wrapper. for example, copy(copy(copy(fn)))
will return a function with three wrappers.length
of the origin function is lost, wrapper.length
is alaways 0
.there are some problems with this solution
The major problems I see are
fn
to the wrapper
, not to this
Object.assign
only copies (own) enumerable properties, and only their values. (This includes your problem with .length
, but also the .name
, and of course other custom properties)Function.prototype
, it does not necessarily have the same prototype as fn
.Chain appling of copy will lead to multiple levels of wrapper.
That isn't necessarily unexpected. But if you wanted to solve this, you'd need a way to extract the original fn
from any wrapper function; this can be achieved by using a WeakMap
.
const originals = new WeakMap();
function copy(source) {
const fn = originals.get(source) ?? source;
const target = function() {
return fn.apply(this, arguments);
};
originals.set(target, fn);
Object.setPrototypeOf(target, Object.getPrototypeOf(source));
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
return target;
}