0

I was going through the Typescript Ecmascript source code. I came across this:

interface FunctionConstructor {
    /**
     * Creates a new function.
     * @param args A list of arguments the function accepts.
     */
    new(...args: string[]): Function;
    (...args: string[]): Function;
    readonly prototype: Function;
}

declare var Function: FunctionConstructor;

I am assuming FunctionConstructor is the type of Function's constructor.

We declaring a Function variable which has FunctionConstructor interface. What are the first two parameters in the FunctionConstructor interface? And why would variable Function(a plain JavaScript object deriving from Object) have its type similar to its constructor?

Basically I am trying to understand what is happening behind the scenes. Any help is appreciated. Thanks!

VLAZ
  • 26,331
  • 9
  • 49
  • 67
ritwick_ _D
  • 117
  • 1
  • 11
  • 1
    "*the type of Function's constructor*", "*variable Function(a plain JavaScript object deriving from Object)*" - do you know what the [global `Function` variable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) actually is? – Bergi Mar 09 '23 at 13:50
  • My understanding: Its an object, has a prototype Object and is the prototype of all JS functions. Can you clarify if this is correct or not? – ritwick_ _D Mar 09 '23 at 14:11
  • 1
    No, that's `Function.prototype` (which has `Object.prototype` as its prototype and is the prototype of all functions). The `Function` object is `Function.prototype.constructor`, and it's a constructor function (that constructs functions). – Bergi Mar 09 '23 at 14:19
  • @Bergi Thank you for your explanation. So my understanding was wrong. Is it the same for Function, Object (anywhere we see syntax like: "declare var RegExp:RegExpConstructor")? If so, why do we need a named variable which is a constructor? A constructor should be a member of a class or object but can it be a separate variable by itself? Also, another question, which is the correct prototype chain: any function->Function->Object->Object.prototype OR any Function->Function.prototype->Object.prototype? I got confused seeing your last sentence. – ritwick_ _D Mar 09 '23 at 14:51
  • 1
    Yes, it's the same for all classes. "*why do we need a named variable which is a constructor?*" - that's just the way classes work in JS. The `.prototype` is a member of the constructor, the `.constructor` is a member of the prototype object, together they form the class - and we refer to the class through the named constructor function. The prototype chain of instances is "any function object -> `Function.prototype` -> `Object.prototype` -> null". – Bergi Mar 09 '23 at 14:55
  • @Bergi if .prototype is a member of the constructor, the .constructor is a member of the prototype object, isn't that a cyclic dependency? And here: "any function object -> Function.prototype -> Object.prototype -> null", is Function.prototype the readonly prototype member present in FunctionConstructor. And, if my understanding is correct, no function inherits from "Object", but they inherit from "Function.prototype", which depends on "Object.prototype"? And for a object: {} -> Object.prototype->null. Is this correct? – ritwick_ _D Mar 09 '23 at 15:16
  • Yes, it's a cyclic reference, and it's not a problem. As for your prototype chains, they're correct. – Bergi Mar 09 '23 at 15:18
  • Sorry for prolonging the discussion, but a final question, why is "Function === Function.prototype.constructor" and also "Function === (function(){}).constructor" And can you suggest some docs to clarify "The .prototype is a member of the constructor, the .constructor is a member of the prototype object, together they form the class - and we refer to the class through the named constructor function. "? It would be very helpful – ritwick_ _D Mar 09 '23 at 15:24
  • 1
    Because `(function(){})` inherits the `.constructor` property from `Function.prototype` – Bergi Mar 09 '23 at 15:26
  • 1
    As for classes, I'd recommend any general introduction to the language, e.g. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain, https://eloquentjavascript.net/06_object.html or https://exploringjs.com/es5/ch17.html#constructors and many others – Bergi Mar 09 '23 at 15:35

1 Answers1

1

Firstly see Function() constructor

The Function() constructor creates a new Function object. Calling the constructor directly can create functions dynamically, but suffers from security and similar (but far less significant) performance issues as eval(). However, unlike eval (which may have access to the local scope), the Function constructor creates functions which execute in the global scope only.

const sum = new Function('a', 'b', 'return a + b');

console.log(sum(2, 6));
// Expected output: 8

To rephrase: creating functions dynamically is an advanced feature. Use regular functions if possible.

Having said that:

remember that variables and types use different namespaces.

This code is legal

interface Foo {
  id: number
}

var Foo = 1;

Thus, var Function: FunctionConstructor is an object that can be used to produce Function objects.

Interface FunctionConstructor models how Function object can be used:

  • creating a function with new
// using new(...args: string[]): Function;
const sum = new Function('a', 'b', 'return a + b');
console.log(sum(2, 6));
  • creating a function without new
// using (...args: string[]): Function;
const sum = Function('a', 'b', 'return a + b');
console.log(sum(2, 6));

prototype: Function is a sign of prototypal inheritance in JS. Object created via Function object will have their __proto__ set to object of type Function, and thus can use methods from this type (can be called etc).

const sum = Function('a', 'b', 'return a + b');
console.log(sum(2, 6));

console.log(Function.prototype === sum.__proto__) // true
Lesiak
  • 22,088
  • 2
  • 41
  • 65
  • Thanks for the reply, it was well explained. But, I have a doubt, here: ``` new(...args: string[]): Function; ``` means the FunctionConstructor has a method new(), which should be callable by Function.new(<--function code-->). But in practice that method is called when we do new Function(<--function code-->). Why does this discrepancy exist? – ritwick_ _D Mar 09 '23 at 13:09
  • 1
    These are called construct signatures. See https://stackoverflow.com/questions/13407036/how-does-interfaces-with-construct-signatures-work – Lesiak Mar 09 '23 at 13:15