Как в 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>
вспомнилось
if (Boolean.valueOf(stringValue).length() == 4) {
// stringValue is «true» :)
}
Комментарий для bealex.moikrug.ru:
Хехе :)
Только «Boolean.valueOf.call(stringValue).length», наверное :) И на «null» оно тоже «4» вернёт. И на «1234» — тоже.
Знатная подлянка. Между контекстами JS можно безопасно передавать только во что-нибудь сериализованные объекты, и пересоздавать их на принимающей стороне заново.
Я на ней однажды, давным-давно, ещё во времена IE 5.5, потерял кучу времени. Приложение у меня было многофреймовое, JSON’а тогда ещё не было, и пришлось здорово поизвращаться.
Комментарий для Евгения Степанищева:
А я не говорил, что это корректный код. Это кусок какого-то индусского программирования. Напомнило не в смысле также круто, просто ассоциация :)
Array.isArray, не везде, правда.
Комментарий для Imfo.ru:
Ну это что-то совсем не везде.
Всегда недолюбливал этот метод. Насколько помню, то, что отдает Array при приведении к строке — vendor-specific и никто не гарантирует, что в какой-нибудь среде эта строка не будет другой. Хотя, isArray в jQuery использует именно этот метод, как достаточно надежный.
Куда более изящно выглядит такой способ: [].constructor.name, но в средах, где он поддерживается, скорее всего есть и isArray.
Комментарий для ixth:
Насколько я знаю, напротив, в стандарте закреплено, что строка будет именно такой.
Комментарий для Евгения Степанищева:
Проверил по спеке — действительно, часть стандарта. Почему-то всегда думал наоборот.
Интересно, а почему тогда конструкция «[1,2,3].toString()» возвращает строку «1,2,3»? Судя по описанной логике, при приведении массива к строке тоже должно было получиться «[object Array]».
Комментарий для morozov.livejournal.com:
Она возвращает сроку, потому что метод toString у массива возвращает строку элементов через запятую. Где вы увидели, что должно быть иначе?
Ну да, не заметил. Используется Object.prototype.toString, а не Array.prototype.toString
Комментарий для Евгения Степанищева:
я полагал, что Кантор должен к тебе ходить на семинары ;-)
Комментарий для alshur:
Я же не всё на свете знаю :) Но кое-что новое я ему рассказал, полагаю :)