javascriptfunction

How to make a copy of a function?


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:

  1. Chain appling of copy will lead to multiple levels of wrapper. for example, copy(copy(copy(fn))) will return a function with three wrappers.
  2. the length of the origin function is lost, wrapper.length is alaways 0.

Solution

  • According to the OP's asking I'm providing my above comment as an answer ...

    As for the OP's use case, the simplest, most straight forward way is as follows. Create another function via bind. And since all of func's properties are assigned directly, the best way of assigning an entirely decoupled set of func specific own properties to f2 is by utilizing both Object.assign and structuredClone ... all-in-one solution ... const f2 = Object.assign(func.bind(), structuredClone(Object.assign({}, func)));

    function blueprint(a, b) {
      return [a, b].join(' ');
    }
    blueprint.foo = 'foo';
    
    const bpReference = blueprint;
    const boundBpCopy = Object
      .assign(
        blueprint.bind(),
        structuredClone(
          Object.assign({}, blueprint)
        )
      );
    
    console.log({ 'bpReference.foo': bpReference.foo });
    console.log({ 'boundBpCopy.foo': boundBpCopy.foo });
    
    blueprint.foo = 'BAR';
    
    console.log({ 'bpReference.foo': bpReference.foo });
    console.log({ 'boundBpCopy.foo': boundBpCopy.foo });
    
    console.log(boundBpCopy('hello', 'world'));
    .as-console-wrapper { bottom: auto; right: auto; top: 0; min-height: 100%; }

    The OP's simplified version of the above provided stack snippet ...

    const f2 = Object.assign(func.bind(),func);
    

    ... will create just a shallow copy for each of func's own properties where such a property is an object itself and not just a primitive value.