Hoy descubriremos lo siguiente: qué es el método Array.isArray (), cómo funciona bajo el capó, qué ha cambiado con él después del lanzamiento de ES6, por qué devuelve verdadero para Array.prototype y muchos más temas relacionados con este método.
El método isArray()
constructor se Array
ha agregado desde la versión 5 del estándar ECMAScript . En la página que describe este método en el sitio web de MDN , dice:
El método Array.isArray () devuelve verdadero si el objeto es una matriz y falso si no es una matriz.
De hecho, este método es muy adecuado para probar varios valores para ver si el valor es una matriz. Sin embargo, tiene una característica (a dónde podemos ir sin ellos). Si pasa este método Array.prototype
, que es un objeto, se devuelve true
. A pesar de que:
Array.prototype instanceof Array // false
Object.getPrototypeOf(Array.prototype) === Array.prototype // false
Array.prototype.isPrototypeOf(Array.prototype) // false
Array.prototype instanceof Object // true
Object.getPrototypeOf(Array.prototype) === Object.prototype // true
Object.prototype.isPrototypeOf(Array.prototype) // true
Este comportamiento inesperado puede confundir no solo a un programador de JavaScript ordinario, sino también a un luchador experimentado. En realidad, esto me impulsó a escribir este artículo. Alguien podría comparar este comportamiento con una característica famosa de JS:
typeof null === 'object' // true
Sin embargo, no hay necesidad de apresurarse a agregar este caso a la lista wtfjs , porque (de repente) hay una explicación lógica para esto. Pero primero, descubramos por qué se creó el método isArray()
y qué se esconde debajo del capó.
Antecedentes
ES5 , , instanceof
.
[] instanceof Array // true
( ) prototype
( ). :
Object.getPrototypeOf([]) === Array.prototype // true
, (realm), , iframe, iframe (window). instanseof Array
false, Array Array .
, , Array. , Object.prototype.toString()
[[Class]]
. :
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
, Array.
Array.isArray Array.prototype
ES6 . Arrray.prototype
Object.prototype.toString()
[object Array]
:
Object.prototype.toString.call(Date.prototype) // [object Object]
Object.prototype.toString.call(RegExp.prototype) // [object Object]
1. false.
2. [[Class]] «Array» true.
3. false.
Object.prototype.toString()
. , [[Class]]
Array.prototype
«Array»? ?
isArray()
ES6. , , . ES6 [[Class]]
Object.prototype.toString()
-. :
…
3. O ToObject(this value).
4. isArray isArray(O).
5. isArray true, builtinTag «Array».
...
isArray()
ES6 Array.isArray()
. isArray()
, , . true
[[DefineOwnProperty]]
, ( length
).
Array.prototype
, [[DefineOwnProperty]]
. . . .
console.log(Array.prototype);
// [constructor: f, concat: f, ..., length: 0, ..., __proto__: Object]
. length
, , (__proto__
) Object
. ! .
console.log(Object.getOwnPropertyDescriptor(Array.prototype, 'length'));
// {value: 0, writable: true, enumerable: false, configurable: false}
. length
. . Array exotic object
console.log(Array.prototype.length); // 0
Array.prototype[42] = 'I\'m array';
Array.prototype[18] = 'I\'m array exotic object';
console.log(Array.prototype.length); // 43
Array.prototype.length = 20;
console.log(Array.prototype[42]); // undefined
console.log(Array.prototype[18]); // 'I\'m array exotic object'
, Array.prototype
. ( ), prototype
Array
.
Array.prototype = new Array();
Object.assign(Array.prototype, {constructor() { ... }, concat() { ... }, ...});
Object.setPrototypeOf(Array.prototype, Object.prototype);
, , Array.prototype
. , [[Class]]
( ) 'Array'
.
Function, Date, RegExp
Date
RegExp
(Object
), .. , .
Object.prototype.toString.call(Date.prototype); // [object Object]
Object.prototype.toString.call(RegExp.prototype); // [object Object]
Function.prototype
. Object.prototype.toString()
Object.prototype.toString.call(Function.prototype); // [object Function]
, Function.prototype
.
Function.prototype() // undefined;
)))
(Boolean
, Number
, String
) Object.prototype.toString
Object.prototype.toString.call(Boolean.prototype); // [object Boolean]
Object.prototype.toString.call(Number.prototype); // [object Number]
Object.prototype.toString.call(String.prototype); // [object String]
. . [[Class]]
…
3. O ToObject(this value).
…
7. , O exotic String object builtinTag «String».
…
11. , O [[BooleanData]] builtinTag «Boolean».
12. , O [[NumberData]] builtinTag «Number».
)))
String.prototype + Number.prototype + Boolean.prototype // '0false'
(String.prototype + Boolean.prototype)[Number.prototype]; // 'f'
' ' + Number.prototype + Number.prototype + '7'; // ' 007'
Symbol.toStringTag
, Object.prototype.toString()
ES6, Set
, Symbol
, Promise
, :
Object.prototype.toString.call(Map.prototype); // [object Map]
Object.prototype.toString.call(Set.prototype); // [object Set]
Object.prototype.toString.call(Promise.prototype); // [object Promise]
Object.prototype.toString.call(Symbol.prototype); // [object Symbol]
, Object.prototype.toString
, . , @@toStringTag
. Object.prototype.toString()
. , ES5 , , Set.prototype
, Promise.prototype
Set
Promise
.
, Object.prototype.toString()
.
Array.prototype
ECMAScript . , , , Array.isArray()
. , . ? - ?
- ES5 — 5- ESMAScript.
- ES6 — 6- ESMAScript.
- ECMAScript 6 | — , .
- Determining with absolute accuracy whether or not a JavaScript object is an array — , , Array.isArray .