Function.prototype is a function

后端 未结 3 1376
粉色の甜心
粉色の甜心 2020-12-01 04:08

I\'m digging into the Javascript prototype chain.
In order to document my findings, I\'ve drawn the following scheme:

Although most of the concepts are

3条回答
  •  无人及你
    2020-12-01 04:30

    The reason is that the ES5 spec says so:

    The Function prototype object is itself a Function object (its [[Class]] is "Function") that, when invoked, accepts any arguments and returns undefined.

    Note it's common in ES5 to make the prototype of some class a member of that class:

    • Object.prototype is an Object object.
    • Function.prototype is a Function object which returns undefined when invoked.
    • Array.prototype is an empty Array object.
    • String.prototype is a String object whose value is an empty String.
    • Boolean.prototype is a Boolean object whose value is false.
    • Number.prototype is a Number object whose value is +0.
    • Date.prototype is a Date object whose [[PrimitiveValue]] is NaN.
    • RegExp.prototype is a RegExp object whose data properties are like new RegExp()'s ones.
    • Error.prototype is an Error object.

    I think it was standardized as such because the prototype of a class has the intrinsic properties of that class, as the instances of that class. And if it looks like a duck it should behave as a duck. So calling the methods of the prototype on the prototype itself instead of on an instance should work too.

    However, ES6 didn't like this. So it changed the behavior for those:

    • Boolean.prototype is an ordinary object with no [[BooleanData]] internal slot.
    • Error.prototype is an ordinary object with no [[ErrorData]] internal slot.
    • Number.prototype is an ordinary object with no [[NumberData]] internal slot.
    • Date.prototype is an ordinary object with no [[DateValue]] internal slot.
    • String.prototype is an ordinary object with no [[StringData]] internal slot.
    • RegExp.prototype is an ordinary object with no [[RegExpMatcher]] nor any of the other internal slots of RegExp instance objects.

    And also for new "classes" (ES6 objects no longer have a [[Class]]):

    • Symbol.prototype is an ordinary object with no [[SymbolData]] internal slot.
    • TypedArray.prototype is an ordinary object with no [[ViewedArrayBuffer]] nor any other of the internal slots that are specific to TypedArray instance objects.
    • Map.prototype is an ordinary object with no [[MapData]] internal slot.
    • Set.prototype is an ordinary object with no [[SetData]] internal slot.
    • WeakMap.prototype is an ordinary object with no [[WeakMapData]] internal slot.
    • WeakSet.prototype is an ordinary object with no [[WeakSetData]] internal slot.
    • ArrayBuffer.prototype is an ordinary object with no [[ArrayBufferData]] nor [[ArrayBufferByteLength]] internal slots.
    • DataView.prototype is an ordinary object with no [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], nor [[ByteOffset]] internal slots.
    • GeneratorFunction.prototype is an ordinary object with no [[ECMAScriptCode]] nor any other of the internal slots listed in Table 27 or Table 56.
    • Promise.prototype is an ordinary object with no [[PromiseState]] nor any of the other internal slots of Promise instances.

    However, the old behavior remains for those:

    • Function.prototype is itself a built-in function object.
    • Array.prototype is an Array exotic object and has the internal methods specified for such objects.

    So now the reason is backwards compatibility:

    The Function prototype object is specified to be a function object to ensure compatibility with ECMAScript code that was created prior to the ECMAScript 2015 specification.

    Note this doesn't make Function.prototype a special function. Only constructors have the prototype property:

    Function instances that can be used as a constructor have a prototype property.

    There are multiple examples of non-constructor functions apart from Function.prototype, such as

    • Methods in Math object:

      typeof Math.pow; // "function
      'prototype' in Math.pow; // false
      
    • Some host objects:

      typeof document.createElement('object'); // "function
      'prototype' in document.createElement('object'); // false
      
    • In ES6, arrow functions:

      typeof (x => x * x); // "function
      'prototype' in (x => x * x); // false
      

提交回复
热议问题