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

  • there are some problems with this solution

    The major problems I see are

    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;
    }