title: What's the best way to create JS functions with custom prototype?
body: <p>My goal is to create callable JavaScript objects (functions), that have a custom <code>[[Prototype]]</code>, and <em>may</em> (or may not) inherit from <code>Function.prototype</code>.</p>
  
  <p>This question has been asked many times (even on Stack Overflow, like <a href="https://stackoverflow.com/questions/46858944/create-function-with-specific-prototype">this</a>, <a href="https://stackoverflow.com/questions/12443769/create-function-in-javascript-with-custom-prototype">this</a> or <a href="https://stackoverflow.com/questions/16596117/can-you-create-functions-with-custom-prototypes-in-javascript">this</a>), but none of these has good solutions (some has no answers, while others have the solutions listed below).</p>
  
  <p>Some ways came to my mind. Here they are:</p>
  
  <ol>
  <li><p>Using <code>Object.create</code>:</p>
  
  <p>That's the standard way to create custom-prototyped objects. However, it isn't capable of creating callable objects (functions).</p></li>
  <li><p>Subclassing <code>Function</code>:</p>
  
  <p>That's probably the most straightforward way, that most people think of. Something like:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="true" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>class MyFunction extends Function{
    constructor(id){
      super(
        '...args',
        'return args.length'
      )
      this.id=id
    }
    logCall(...args){
      console.log('Calling MyFunction #%i with arguments: %o', this.id, args)
      return Reflect.apply(this, this, args)
    }
  }
  
  const fn = new MyFunction(1)
  console.log(fn('foo', 'bar'))   //2
  fn.logCall('foo', 'bar', 'baz') //Calling MyFunction #1 with arguments: ['foo', 'bar', 'baz']
  //Works, so far so good!</code></pre>
  </div>
  </div>
  </p>
  
  <p>
  However, that has several downsides:</p>
  
  <ul>
  <li>Uses the <code>eval</code>-like <code>Function</code> constructor</li>
  <li>Runtime compilation of the function's body, every time a new instance constructed</li>
  <li>Lack of access to lexical/closure scope inside the function body</li>
  <li>Lack of compile-time errors and syntax highlighting in the function body: harder to maintain</li>
  <li>Impossible to create functions that don't have <code>Function.prototype</code> (and therefore <code>Object.prototype</code>) in their prototype chain</li>
  </ul></li>
  <li><p><code>Object.setPrototypeOf()</code>:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="true" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>class MyFunction{
    constructor(id){
      const _this = function (...args){
        return args.length
      }
      Object.setPrototypeOf(_this, Object.getPrototypeOf(this))
      _this.id=id
      return _this
    }
    logCall(...args){
      console.log('Calling MyFunction #%i with arguments: %o', this.id, args)
      return Reflect.apply(this, this, args)
    }
  }
  
  const fn = new MyFunction(1)
  console.log(fn('foo', 'bar'))   //2
  fn.logCall('foo', 'bar', 'baz') //Calling MyFunction #1 with arguments: ['foo', 'bar', 'baz']
  //Works as well, so far so good!</code></pre>
  </div>
  </div>
  </p>
  
  <p>
  Downsides:</p>
  
  <ul>
  <li><p>Scary red warning on <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf" rel="nofollow noreferrer">MDN</a> about performance:</p>
  
  <blockquote>
    <p><strong>Warning:</strong> Changing the <code>[[Prototype]]</code> of an object is, by the nature of <a href="https://mathiasbynens.be/notes/prototypes" rel="nofollow noreferrer">how modern JavaScript engines optimize property accesses</a>, currently a very slow operation in every browser and JavaScript engine. In addition, the effects of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in the <code>Object.setPrototypeOf(...)</code> statement, but may extend to <strong><em>any</em></strong> code that has access to any object whose <code>[[Prototype]]</code> has been altered.</p>
    
    <p>Because this feature is a part of the language, it is still the burden on engine developers to implement that feature performantly (ideally). Until engine developers address this issue, if you are concerned about performance, you should avoid setting the <code>[[Prototype]]</code> of an object. Instead, create a new object with the desired <code>[[Prototype]]</code> using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create" rel="nofollow noreferrer"><code>Object.create()</code></a>.</p>
  </blockquote></li>
  <li><p>Harder-to-understand, unsemantic, hacky-looking code</p></li>
  </ul></li>
  <li><p><code>Proxy</code> with faked traps:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="true" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>class MyFunction{
    constructor(id){
      const _this = new Proxy(
        function (...args){
          return args.length
        }, 
        Object.assign(
          Reflect
            .ownKeys(Reflect)
            .reduce((handler, trap) =&gt; ( //Forward operations to real `this`
              handler[trap] = (...args) =&gt; Reflect[trap](this, ...args.slice(1)),
              handler
            ), {}),
          {
            apply(...args){
              return Reflect.apply(...args)
            }
          }
        )
      )
      _this.id=id
      return _this
    }
    logCall(...args){
      console.log('Calling MyFunction #%i with arguments: %o', this.id, args)
      return Reflect.apply(this, this, args)
    }
  }
  
  const fn = new MyFunction(1)
  console.log(fn('foo', 'bar'))   //2
  fn.logCall('foo', 'bar', 'baz') //Calling MyFunction #1 with arguments: ['foo', 'bar', 'baz']
  //Works as well, so far so good!</code></pre>
  </div>
  </div>
  </p>
  
  <p>
  Downsides:</p>
  
  <ul>
  <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#Browser_compatibility" rel="nofollow noreferrer">Unsupported <code>getPrototypeOf</code> trap in Safari</a></li>
  <li>Harder-to-understand, unsemantic, hacky-looking code</li>
  <li>Creation of multiple additional functions and objects (the handler and the traps)</li>
  </ul></li>
  </ol>
  
  <p>So, as far as I know, there's no <strong>good</strong> way to do that. </p>
  
  <p><strong>My question is:</strong></p>
  
  <p>Is there any <strong>alternative</strong>, that's better than these, or, if there isn't any, <strong>which of these has the most advantages</strong> in terms of <strong>performance</strong>, readability and support?</p>