Las clases integradas como Array, Map y otras también se pueden ampliar.
Por ejemplo, aquí PowerArray
hereda del Array
nativo:
// agregarle un método más (puede hacer más) clase PowerArray extiende Array { está vacío() { devolver this.length === 0; } } let arr = nuevo PowerArray(1, 2, 5, 10, 50); alerta(arr.isEmpty()); // FALSO let filteredArr = arr.filter(item => item >= 10); alerta (arr filtrado); // 10, 50 alerta(filteredArr.isEmpty()); // FALSO
Tenga en cuenta una cosa muy interesante. Los métodos integrados como filter
, map
y otros devuelven nuevos objetos exactamente del tipo heredado PowerArray
. Su implementación interna utiliza la propiedad constructor
del objeto para eso.
En el ejemplo anterior,
arr.constructor === PowerArray
Cuando se llama arr.filter()
, crea internamente la nueva matriz de resultados usando exactamente arr.constructor
, no Array
básico. En realidad, eso es genial, porque podemos seguir usando métodos PowerArray
más adelante en el resultado.
Aún más, podemos personalizar ese comportamiento.
Podemos agregar un captador estático especial Symbol.species
a la clase. Si existe, debería devolver el constructor que JavaScript utilizará internamente para crear nuevas entidades en map
, filter
, etc.
Si queremos que métodos integrados como map
o filter
devuelvan matrices regulares, podemos devolver Array
en Symbol.species
, como aquí:
clase PowerArray extiende Array { está vacío() { devolver this.length === 0; } // los métodos integrados usarán esto como constructor obtención estática [Símbolo.especie]() { devolver matriz; } } let arr = nuevo PowerArray(1, 2, 5, 10, 50); alerta(arr.isEmpty()); // FALSO // el filtro crea una nueva matriz usando arr.constructor[Symbol.species] como constructor let filteredArr = arr.filter(item => item >= 10); // filteredArr no es PowerArray, sino Array alerta(filteredArr.isEmpty()); // Error: filteredArr.isEmpty no es una función
Como puede ver, ahora .filter
devuelve Array
. Por lo tanto, la funcionalidad ampliada no se transmite más.
Otras colecciones funcionan de manera similar
Otras colecciones, como Map
y Set
, funcionan de manera similar. También usan Symbol.species
.
Los objetos integrados tienen sus propios métodos estáticos, por ejemplo Object.keys
, Array.isArray
, etc.
Como ya sabemos, las clases nativas se extienden unas a otras. Por ejemplo, Array
extiende Object
.
Normalmente, cuando una clase extiende a otra, se heredan tanto los métodos estáticos como los no estáticos. Esto se explicó detalladamente en el artículo Propiedades y métodos estáticos.
Pero las clases integradas son una excepción. No heredan estática entre sí.
Por ejemplo, tanto Array
como Date
heredan de Object
, por lo que sus instancias tienen métodos de Object.prototype
. Pero Array.[[Prototype]]
no hace referencia Object
, por lo que no existe, por ejemplo, un método estático Array.keys()
(o Date.keys()
).
Aquí está la estructura de la imagen para Date
y Object
:
Como puede ver, no existe ningún vínculo entre Date
y Object
. Son independientes, solo Date.prototype
hereda de Object.prototype
.
Esa es una diferencia importante de herencia entre objetos integrados en comparación con lo que obtenemos con extends
.