Подтвердить что ты не робот

Функция.прототип - это функция

Я копаю в цепочку прототипов Javascript.
Чтобы документировать мои выводы, я составил следующую схему:

введите описание изображения здесь

Хотя большинство понятий ясны, у меня осталось только два связанных вопроса. Вместо того, чтобы разделить их, я догадался, что централизация их в этом вопросе может быть лучше:

  • Есть ли причина, по которой Function.prototype имеет функцию типа, вместо объекта?
    typeof Function.prototype; //"function"
  • Является ли Function.prototype "уникальной функцией" в JS, поскольку у него нет собственного свойства прототипа, как это делают другие функции? (есть ли общепринятое "имя", чтобы ссылаться на него?)
4b9b3361

Ответ 1

Причина в том, что спецификация ES5 говорит так:

Объект-прототип функции сам является объектом Function (его [[Класс]] - это "Функция" ), который при вызове принимает любые аргументы и возвращает undefined.

Обратите внимание, что в ES5 обычно используется, чтобы прототип некоторого класса был членом этого класса:

  • Object.prototype - объект Object.
  • Function.prototype - это объект Function, который возвращает undefined при вызове.
  • Array.prototype - пустой объект Array.
  • String.prototype - объект String, значение которого является пустой строкой.
  • Boolean.prototype - это булев объект, значение которого false.
  • Number.prototype - это объект Number, значение которого +0.
  • Date.prototype - объект Date, чей [[PrimitiveValue]] - NaN.
  • RegExp.prototype - это объект RegExp, свойства которого похожи на new RegExp().
  • Error.prototype является объектом Error.

Я думаю, что он был стандартизирован как таковой, потому что прототип класса обладает внутренними свойствами этого класса, как экземпляры этого класса. И если он выглядит как утка, он должен вести себя как утка. Поэтому нужно также использовать методы прототипа самого прототипа, а не экземпляра.

Однако ES6 это не понравилось. Поэтому он изменил поведение для тех:

  • Boolean.prototype - обычный объект без внутреннего слота [[BooleanData]].
  • Error.prototype - обычный объект без внутреннего слота [[ErrorData]].
  • Number.prototype - обычный объект без внутреннего слота [[NumberData]].
  • Date.prototype - обычный объект без внутреннего слота [[DateValue]].
  • String.prototype - обычный объект без внутреннего внутреннего слота [[StringData]].
  • RegExp.prototype - обычный объект без [[RegExpMatcher]] или любой другой внутренний слот объектов экземпляра RegExp.

А также для новых "классов" (объекты ES6 больше не имеют [[Class]]):

  • Symbol.prototype - обычный объект без внутреннего слота [[SymbolData]].
  • TypedArray.prototype - это обычный объект без [[ViewedArrayBuffer]] или любой другой из внутренних слотов, специфичных для объектов экземпляра TypedArray.
  • Map.prototype - обычный объект без внутреннего внутреннего слота [[MapData]].
  • Set.prototype - обычный объект без внутреннего интервала [[SetData]].
  • WeakMap.prototype - обычный объект без внутреннего слота [[WeakMapData]].
  • WeakSet.prototype - обычный объект без внутреннего слота [[WeakSetData]].
  • ArrayBuffer.prototype - обычный объект без внутренних слотов [[ArrayBufferData]] и [[ArrayBufferByteLength]].
  • DataView.prototype - обычный объект без [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], ни [[ByteOffset]] внутренние слоты.
  • GeneratorFunction.prototype - это обычный объект без [[ECMAScriptCode]] или любой другой из внутренних слотов, перечисленных в Таблица 27 или Таблица 56.
  • Promise.prototype является обычным объектом без [[PromiseState]] или любого другого внутреннего слота экземпляров Promise.

Однако для них остается прежнее поведение:

  • Function.prototype сам является встроенным функциональным объектом.
  • Array.prototype является экзотическим объектом Array и имеет внутренние методы, указанные для таких объектов.

Итак, теперь причина обратной совместимости:

Объект прототипа функции задан как объект функции для обеспечить совместимость с кодом ECMAScript, который был создан до спецификация ECMAScript 2015.

Обратите внимание, что это не делает специальную функцию Function.prototype. Только конструкторы имеют свойство prototype:

Экземпляры функций, которые могут использоваться как конструктор, имеют prototypeсвойство.

Существует несколько примеров неконструкторских функций, кроме Function.prototype, таких как

  • Методы в объекте Math:

    typeof Math.pow; // "function
    'prototype' in Math.pow; // false
    
  • Некоторые объекты хоста:

    typeof document.createElement('object'); // "function
    'prototype' in document.createElement('object'); // false
    
  • В ES6 функции стрелок:

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

Ответ 2

Отвечая на ваши вопросы:

1) Function.prototype - это тип функции, поскольку, согласно ECMAScript 2015:

Объект-прототип функции является внутренним объектом% FunctionPrototype%. Объект-прототип функции сам по себе является встроенным функциональным объектом.

Объект-прототип функции задан как объект функции для обеспечения совместимости с кодом ECMAScript, который был создан до спецификации ECMAScript 2015.

Таким образом, объект-прототип функции определяется только как объект Function, чтобы обеспечить совместимость со старыми стандартами ECMAScript. Функция фактически ничего не делает:

При вызове он принимает любые аргументы и возвращает undefined.

http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-prototype-object

2) Что касается свойства прототипа:

Объект прототипа функции не имеет свойства прототипа.

Тот же источник

Это уникально, поскольку все функции обычно имеют свойство prototype, однако, поскольку объект-прототип функции задан только как объект Function для обеспечения совместимости, это поведение отличается от поведения обычных функций.

Я создал JSFiddle с различными тестами, если он кому-то помог:

http://jsfiddle.net/Ld0b39xz/

// We'll use 'Object.getPrototypeOf' to access [[prototype]]

// As you know, [[prototype]] of Object.prototype returns 'null'. 
console.log(Object.getPrototypeOf(Object.prototype));
// null

////////////////////////////////////////////////////////

// Let take a closer look at Function.prototype
console.log(Function.prototype);
// Output:
// function(){}

// This is what the specs say should happen:
// "The Function prototype object is itself a built-in function object."

/////////////////////////////////////////////////////

// Let see if this function has a 'prototype' property.
// All functions normally have a prototype property that initially
// references an empty object...except this one.
var fn = Function.prototype;
console.log(fn.prototype);
// Output:
// undefined

// This is expected, according to the specs:
// "The Function prototype object does not have a prototype property."

// It does have some properties such as 'name' and 'length',
// but not 'prototype'.

////////////////////////////////////////////////////////

// Let see what [[prototype]] of Function.prototype returns.
console.log(Object.getPrototypeOf(Function.prototype));
// Output:
// Object{}

// Again this is expected:
// "The value of the [[Prototype]] internal slot of the
// Function prototype object is the intrinsic object %ObjectPrototype%"

/////////////////////////////////////////////////////////

// Now lets see what the [[Prototype]] of this object is:
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function.prototype)));
// Output:
// null

// We've come full circle since all the statement above is
// doing is looking for the prototoype of the native Object,
// which we already know is 'null' from our first test.

Ответ 3

Взамен предыдущего ответа, которого я не мог выдержать. Благодаря Ориолу. Головка царапает меня.

В отношении первого вопроса объект Function он не особенно отличается просто потому, что Function.prototype является функцией. Другие встроенные конструкторы используют прототипы объектов своего типа. Что привлекает внимание к случаю функции, так это то, что оператор typeof относится к объектам функции к другим объектам, возвращая "функцию" вместо "объекта".

Глобальные конструкторы перечисляют себя как конструкторы своих объектов-прототипов:

var BuiltIn = Function; // for example
BuiltIn.prototype.constructor == BuiltIn // true

более или менее документально. Объекты-прототипы встроенных конструкторов обычно имеют методы, которые взаимодействуют с движком javascript и не создаются с использованием вызова javascript к их указанному конструктору, как он отображается во время выполнения: Function.prototype instanceof Function является ложным с аналогичными результатами для других встроенных конструкторов, таких как Array, RegExp и т.д.

Глобальный объект Function уникален, тем не менее, тем, что он перечисляет сам себя, поскольку его собственный конструктор (Function.constructor == Function is true), и что он является экземпляром самого себя (Function instanceof Function также является истинным). Последний результат показывает, что Function.prototype находится в цепочке прототипов Function. Function.prototype сам прототипирован на Object.prototype.

Еще одна причина думать, что Function.prototype не является объектом Function в обычном смысле (помимо того, что это сказано в документации) заключается в том, что он не может быть вызван как конструктор и выдает ошибку, если делается попытка сделать это. Поскольку свойство прототипа функции используется, когда функция вызывается как конструктор, для Function.prototype имеет смысл не иметь этого свойства.