Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Как в JS узнать что объект — массив?

Узнал на семинаре Кантора такую штуку. Как узнать, что объект, который пришёл на вход — массив? Конечно, лучше использовать утиную типизацию, но если нам нужен именно массив, со всей полнотой методов, не проверять же каждый?

Кстати, если кто-то думает, что ответ «typeof», то он просто не знает JS. Эта конструкция вернёт «object».

Я до недавнего времени думал, что правильный способ такой:

console.log([] instanceof Array); // true

А редко его используют, потому что конструкция «instanceof» не везде реализована. Я заблуждался. Вот правильный способ:

console.log(Object.prototype.toString.call([]) == '[object Array]'); // true

И вот почему. Оказывается, у каждого фрейма своя иерархия типов, если один фрейм передаёт во второй какой-то объект, то «instanceof» даст «false», так как сравнивает c «Array», локальным для этого фрейма. Проблему иллюстрирует следующий пример:

<script>
function Up(arr, iframeWindow) {
    alert(arr instanceof Array); // false
    alert(arr instanceof iframeWindow.Array); // true

    alert(Object.prototype.toString.call([]) == '[object Array]'); // true
}
</script>
<iframe src="data:text/html, <script>parent.Up([], window)</script>"></iframe>
15 комментариев
Александр Бабаев (bealex.moikrug.ru) 2012

вспомнилось

if (Boolean.valueOf(stringValue).length() == 4) {
// stringValue is «true» :)
}

Евгений Степанищев (bolknote.ru) 2012

Комментарий для bealex.moikrug.ru:

Хехе :)

Только «Boolean.valueOf.call(stringValue).length», наверное :) И на «null» оно тоже «4» вернёт. И на «1234» — тоже.

PastorGL 2012

Оказывается, у каждого фрейма своя иерархия типов

Знатная подлянка. Между контекстами JS можно безопасно передавать только во что-нибудь сериализованные объекты, и пересоздавать их на принимающей стороне заново.
Я на ней однажды, давным-давно, ещё во времена IE 5.5, потерял кучу времени. Приложение у меня было многофреймовое, JSON’а тогда ещё не было, и пришлось здорово поизвращаться.

Александр Бабаев (bealex.moikrug.ru) 2012

Комментарий для Евгения Степанищева:

А я не говорил, что это корректный код. Это кусок какого-то индусского программирования. Напомнило не в смысле также круто, просто ассоциация :)

Imfo.ru 2012

Array.isArray, не везде, правда.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для Imfo.ru:

Ну это что-то совсем не везде.

ixth 2012

Всегда недолюбливал этот метод. Насколько помню, то, что отдает Array при приведении к строке — vendor-specific и никто не гарантирует, что в какой-нибудь среде эта строка не будет другой. Хотя, isArray в jQuery использует именно этот метод, как достаточно надежный.

ixth 2012

Куда более изящно выглядит такой способ: [].constructor.name, но в средах, где он поддерживается, скорее всего есть и isArray.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для ixth:

Всегда недолюбливал этот метод. Насколько помню, то, что отдает Array при приведении к строке — vendor-specific и никто не гарантирует, что в какой-нибудь среде эта строка не будет другой.

Насколько я знаю, напротив, в стандарте закреплено, что строка будет именно такой.

ixth 2012

Комментарий для Евгения Степанищева:

Проверил по спеке — действительно, часть стандарта. Почему-то всегда думал наоборот.

Морозов (morozov.livejournal.com) 2012

Интересно, а почему тогда конструкция «[1,2,3].toString()» возвращает строку «1,2,3»? Судя по описанной логике, при приведении массива к строке тоже должно было получиться «[object Array]».

Евгений Степанищев (bolknote.ru) 2012

Комментарий для morozov.livejournal.com:

Она возвращает сроку, потому что метод toString у массива возвращает строку элементов через запятую. Где вы увидели, что должно быть иначе?

Морозов (morozov.livejournal.com) 2012

Ну да, не заметил. Используется Object.prototype.toString, а не Array.prototype.toString

alshur 2012

Комментарий для Евгения Степанищева:

Узнал на семинаре Кантора такую штуку

я полагал, что Кантор должен к тебе ходить на семинары ;-)

Евгений Степанищев (bolknote.ru) 2012

Комментарий для alshur:

Я же не всё на свете знаю :) Но кое-что новое я ему рассказал, полагаю :)