Функция.прототип - это функция
Я копаю в цепочку прототипов Javascript.
Чтобы документировать мои выводы, я составил следующую схему:
![введите описание изображения здесь]()
Хотя большинство понятий ясны, у меня осталось только два связанных вопроса. Вместо того, чтобы разделить их, я догадался, что централизация их в этом вопросе может быть лучше:
- Есть ли причина, по которой
Function.prototype
имеет функцию типа, вместо объекта?
typeof Function.prototype; //"function"
- Является ли
Function.prototype
"уникальной функцией" в JS, поскольку у него нет собственного свойства прототипа, как это делают другие функции? (есть ли общепринятое "имя", чтобы ссылаться на него?)
Ответы
Ответ 1
Причина в том, что спецификация ES5 говорит так:
Объект-прототип функции сам является объектом Function (его [[Класс]] - это "Функция" ), который при вызове принимает любые аргументы и возвращает undefined.
Обратите внимание, что в ES5 обычно используется, чтобы прототип некоторого класса был членом этого класса:
Я думаю, что он был стандартизирован как таковой, потому что прототип класса обладает внутренними свойствами этого класса, как экземпляры этого класса. И если он выглядит как утка, он должен вести себя как утка. Поэтому нужно также использовать методы прототипа самого прототипа, а не экземпляра.
Однако 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
имеет смысл не иметь этого свойства.