Hoje vamos descobrir o seguinte: o que é o método Array.isArray (), como funciona nos bastidores, o que mudou com ele após o lançamento do ES6, por que ele retorna verdadeiro para Array.prototype e muitos outros tópicos relacionados a esse método.
O método isArray()
construtor Array
foi adicionado desde a versão 5 do padrão ECMAScript . Na página que descreve esse método no site do MDN , está escrito:
O método Array.isArray () retorna verdadeiro se o objeto for uma matriz e falso se não for uma matriz.
Na verdade, este método é adequado para testar diferentes valores para ver se o valor é uma matriz. No entanto, ele tem um recurso (onde podemos ir sem eles). Se você passar este método Array.prototype
, que é um objeto, ele retorna true
. Apesar do fato 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
Esse comportamento inesperado pode confundir não apenas um programador de JavaScript comum, mas também um lutador experiente. Na verdade, isso me levou a escrever este artigo. Alguém pode comparar esse comportamento a um famoso recurso JS:
typeof null === 'object' // true
No entanto, não se apresse em adicionar esse caso à lista wtfjs , porque há (de repente) uma explicação lógica para isso. Mas primeiro, vamos descobrir por que o método foi criado isArray()
e o que está escondido sob o capô.
fundo
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 .