ordenar - sort json javascript
Function.prototype es una función (3)
Estoy cavando en la cadena de prototipos de Javascript.
Para documentar mis hallazgos, he dibujado el siguiente esquema:
Aunque la mayoría de los conceptos son claros, solo me quedan dos preguntas relacionadas. En lugar de dividirlos, supuse que centralizarlos en esta pregunta podría ser mejor:
- ¿Hay alguna razón para que
Function.prototype
sea de tipo function, en lugar de object?
typeof Function.prototype; //"function"
- ¿Es
Function.prototype
una ''función única'' en JS, ya que no tiene una propiedad de prototipo propia como otras funciones? (¿Hay un ''nombre'' generalmente aceptado para referirse a él?)
En respuesta a tus preguntas:
1) Function.prototype
es un tipo de función porque, según ECMAScript 2015:
El objeto prototipo de función es el objeto intrínseco% FunctionPrototype%. El objeto prototipo de función es en sí mismo un objeto de función incorporado.
El objeto prototipo de función se especifica como un objeto de función para garantizar la compatibilidad con el código ECMAScript que se creó antes de la especificación ECMAScript 2015.
Por lo tanto, el objeto prototipo de función solo se define como un objeto de función para garantizar la compatibilidad con los estándares ECMAScript más antiguos. La función en realidad no hace nada:
Cuando se invoca, acepta cualquier argumento y devuelve indefinido.
2) Respecto a la propiedad prototipo:
El objeto prototipo de función no tiene una propiedad de prototipo.
Esto es único ya que todas las funciones generalmente poseen una propiedad prototype
, sin embargo, dado que el objeto prototipo Función solo se especifica como un objeto Función para mantener la compatibilidad, su comportamiento es diferente al de las funciones normales.
He creado un JSFiddle con varias pruebas en caso de que ayude a alguien:
// 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''s 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''s 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''s 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.
La razón es que la especificación ES5 lo dice así:
El objeto prototipo de función es en sí mismo un objeto de función (su [[Clase]] es "función") que, cuando se invoca, acepta cualquier argumento y devuelve indefinido.
Tenga en cuenta que es común en ES5 hacer que el prototipo de alguna clase sea miembro de esa clase:
-
Object.prototype
es un objeto Object. -
Function.prototype
es un objeto Function que devuelveundefined
cuando se invoca. -
Array.prototype
es un objeto Array vacío. -
String.prototype
es un objeto String cuyo valor es un String vacío. -
Boolean.prototype
es un objeto booleano cuyo valor esfalse
. -
Number.prototype
es un objeto Number cuyo valor es+0
. -
Date.prototype
es un objeto Date cuyo [[PrimitiveValue]] esNaN
. -
RegExp.prototype
es un objeto RegExp cuyas propiedades de datos son como lasnew RegExp()
. -
Error.prototype
es un objeto Error.
Creo que se estandarizó como tal porque el prototipo de una clase tiene las propiedades intrínsecas de esa clase, como las instancias de esa clase. Y si parece un pato , debería comportarse como un pato. Así que llamar a los métodos del prototipo en el prototipo en lugar de hacerlo en una instancia también debería funcionar.
Sin embargo, a ES6 no le gustó esto. Así que cambió el comportamiento para aquellos:
-
Boolean.prototype
es un objeto común sin ranura interna [[BooleanData]]. -
Error.prototype
es un objeto ordinario sin ranura interna [[ErrorData]]. -
Number.prototype
es un objeto ordinario sin ranura interna [[NumberData]]. -
Date.prototype
es un objeto ordinario sin ranura interna [[DateValue]]. -
String.prototype
es un objeto ordinario sin ranura interna [[StringData]]. -
RegExp.prototype
es un objeto ordinario sin [[RegExpMatcher]] ni ninguna de las otras ranuras internas de objetos de instancia RegExp.
Y también para las nuevas "clases" (los objetos ES6 ya no tienen una [[Clase]]) :
-
Symbol.prototype
es un objeto ordinario sin ranura interna [[SymbolData]]. -
TypedArray.prototype
es un objeto ordinario sin [[VistoArrayBuffer]] ni ninguna otra de las ranuras internas que son específicas de los objetos de instancia de TypedArray . -
Map.prototype
es un objeto ordinario sin ranura interna [[MapData]]. -
Set.prototype
es un objeto ordinario sin ranura interna [[SetData]]. -
WeakMap.prototype
es un objeto ordinario sin ranura interna [[WeakMapData]]. -
WeakSet.prototype
es un objeto ordinario sin ranura interna [[WeakSetData]]. -
ArrayBuffer.prototype
es un objeto ordinario sin ranuras internas [[ArrayBufferData]] ni [[ArrayBufferByteLength]]. -
DataView.prototype
es un objeto ordinario sin [[DataView]], [[seenArrayBuffer]], [[ByteLength]], ni [[ByteOffset]] ranuras internas. -
GeneratorFunction.prototype
es un objeto ordinario sin [[ECMAScriptCode]] ni ninguna otra de las ranuras internas enumeradas en la Tabla 27 o la Tabla 56 . -
Promise.prototype
es un objeto ordinario sin [[PromiseState]] ni ninguna de las otras ranuras internas de las instancias de Promise.
Sin embargo, el comportamiento antiguo permanece para aquellos:
-
Function.prototype
es en sí mismo un objeto de función incorporado. -
Array.prototype
es un objeto exótico de Array y tiene los métodos internos especificados para dichos objetos.
Así que ahora la razón es la compatibilidad hacia atrás:
El objeto prototipo de función se especifica como un objeto de función para garantizar la compatibilidad con el código ECMAScript que se creó antes de la especificación ECMAScript 2015.
Tenga en cuenta que esto no hace que Function.prototype
una función especial. Sólo los constructores tienen la propiedad prototype
:
Las instancias de función que se pueden usar como constructor tienen una propiedad de
prototype
.
Hay varios ejemplos de funciones no-constructoras aparte de Function.prototype
, como
Métodos en objeto
Math
:typeof Math.pow; // "function ''prototype'' in Math.pow; // false
Algunos objetos host:
typeof document.createElement(''object''); // "function ''prototype'' in document.createElement(''object''); // false
En ES6, las funciones de flecha:
typeof (x => x * x); // "function ''prototype'' in (x => x * x); // false
En reemplazo de una respuesta anterior que no pude soportar. Con agradecimiento a Oriol. El rascarme la cabeza es mío.
En lo que respecta a la primera pregunta, el objeto Function no es particularmente diferente simplemente porque Function.prototype
es una función. Otros constructores construidos utilizan objetos prototipo de su propio tipo. Lo que llama la atención sobre el caso de la función es que el operador typeof
trata los objetos de la función de forma diferente a otros objetos devolviendo "función" en lugar de "objeto".
Los constructores globales se listan como constructores de sus objetos prototipo:
var BuiltIn = Function; // for example
BuiltIn.prototype.constructor == BuiltIn // true
Es más o menos documental. Los objetos prototipo de los constructores integrados generalmente tienen métodos que interactúan con el motor javascript y no se crean mediante una llamada javascript a su constructor listado como aparece en el tiempo de ejecución: Function.prototype instanceof Function
es falso con resultados similares para otros constructores integrados como como Array, RegExp, etc. probado.
Sin embargo, el objeto Function
global es único, ya que se enumera a sí mismo como lo es su propio constructor ( Function.constructor == Function
es verdadera), y es una instancia de sí mismo (la Function instanceof Function
es verdadera). El último resultado indica que Function.prototype
está en la cadena de prototipos de Function
. Function.prototype
sí está prototipado en Object.prototype
.
Otra razón para pensar que Function.prototype
no es un objeto Function en el sentido habitual (aparte de decirlo en la documentación) es que no se puede llamar como constructor y arroja un error si se intenta hacerlo. Dado que la propiedad prototipo de una función se usa cuando se llama a la función como un constructor, tiene sentido que Function.prototype
no tenga esta propiedad.