2

Annex E of the ES2015 spec contains the following:

19.2.3.2: In ECMAScript 2015, the [[Prototype]] internal slot of a bound function is set to the [[GetPrototypeOf]] value of its target function. In the previous edition, [[Prototype]] was always set to %FunctionPrototype%.

What is the significance of this?

Source: http://www.ecma-international.org/ecma-262/6.0/#sec-additions-and-changes-that-introduce-incompatibilities-with-prior-editions

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • Maybe it has something to do with native functions exposed by a particular runtime environment. By having the returned function from `.bind()` reflect the prototype-chain properties of the original bound function, it will behave more like the original function instead of a plain generic function. – Pointy Jun 07 '17 at 18:27
  • 1
    I can't think of a way that a normal function (like, a normal JavaScript function) object would have a prototype other than `Function.prototype`. – Pointy Jun 07 '17 at 18:27

2 Answers2

3

Before ES2015 there was only a single type of function. ES2015 introduced introduced arrow functions, generator functions and methods. Generator functions and class methods do not (necessarily) have Function.prototype as their prototype. For example:

9.2.6 GeneratorFunctionCreate (kind, ParameterList, Body, Scope, Strict)

  1. Let functionPrototype be the intrinsic object %Generator%.
  2. Let F be FunctionAllocate(functionPrototype, Strict, "generator").
  3. Return FunctionInitialize(F, kind, ParameterList, Body, Scope).

Bound versions of these functions should probably "preserve" the prototype of the original function.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    Hm, not sure what this is good for though. There isn't anything interesting on `GeneratorFunction.prototype`, is there? Even [@@toStringTag](https://ecma-international.org/ecma-262/6.0/#sec-generatorfunction.prototype-@@tostringtag) doesn't make sense given that bound functions implement [[Call]] and [always produce `"Function"`](https://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring). – Bergi Jun 07 '17 at 18:47
  • Might be used in other parts to check the type of the function? Haven't looked through it in detail. – Felix Kling Jun 07 '17 at 18:55
  • 1
    Yes, you're right, I found that `instanceof` or `.constructor` checks on functions would indeed be affected by this. Whether that's a good idea is a different question though… – Bergi Jun 07 '17 at 19:01
2

ES5 functions always had Function.prototype as their prototype, so it was only logical to have the same for bound functions.

ES6 introduced classes, where the constructors inherit from their superclass constructor, and generator functions, which have their own prototype. If you bind one of them, the bound function should reflect this:

class A {
    constructor(x) { this.x = x; }
    static example() { return "works" }
}
class B extends A {}

const a1 = new A(1) // {x: 1}
const b1 = new B(1) // {x: 1}
A.example() // "works"
B.example() // "works" - because of inheritance

const BoundA = A.bind(null, 2), BoundB = B.bind(null, 2);
const a2 = new BoundA() // {x: 2}
const b2 = new BoundB() // {x: 2}
BoundA.example() // uh, doesn't actually work
BoundB.example() // "works" - because of the change to bind

Maybe a better use case would be testing for the type of a function (which you shouldn't do though):

const GeneratorFunction = (function*(){}).constructor;

function* example() {
    …
}

test instanceof GeneratorFunction // true
test.bind() instanceof GeneratorFunction; // true as well!
Bergi
  • 630,263
  • 148
  • 957
  • 1,375