# Секретное свойство [[Class]] Для встроенных объектов есть одна "секретная" возможность узнать их тип, которая связана с методом `toString`. Во всех встроенных объектах есть специальное свойство `[[Class]]`, в котором хранится информация о его типе или конструкторе. Оно взято в квадратные скобки, так как это свойство -- внутреннее. Явно получить его нельзя, но можно прочитать его "в обход", воспользовавшись методом `toString` из `Object`. [cut] ## Получение [[Class]] Вернёмся к примеру, который видели раньше: ```js //+ run var obj = {}; alert( obj ); // [object Object] ``` **В выводе стандартного `toString` для объектов внутри `[object ...]` указано как раз значение `[[Class]]`.** Для обычного объекта это как раз и есть `"Object"`, но если бы такой `toString` запустить для даты, то будет `[object Date]`, для массивов -- `[object Array]` и т.п. К сожалению или к счастью, но большинство встроенных объектов в JavaScript имеют свой собственный метод `toString`: для массивов он выводит элементы через запятую, для дат -- строчное представление и так далее. То есть, просто вызов `[1,2,3].toString()` вернёт нам `1,2,3` и никакой информации про `[[Class]]`. Поэтому для получения `[[Class]]` мы одолжим функцию `toString` у стандартного объекта и запустим её в контексте тех значений, для которых нужно получить тип. В этом нам поможет метод `call`: ```js //+ run var toClass = {}.toString; // (1) var arr = [1,2]; alert( toClass.call(arr) ); // (2) [object Array] var date = new Date; alert( toClass.call(date) ); // [object Date] var type = toClass.call(date).slice(8, -1); // (3) alert(type); // Date ``` Разберем происходящее более подробно.
  1. Можно переписать эту строку в две: ```js var obj = {}; var toClass = obj.toString; ``` Иначе говоря, мы создаём пустой объект `{}` и копируем ссылку на его метод `toString` в переменную `toClass`. **Для получения `[[Class]]` нужна именно внутренняя реализация `toString` стандартного объекта `Object`, другая не подойдёт.**
  2. Вызываем скопированный метод в контексте нужного объекта `obj`. Мы могли бы поступить проще -- одолжить метод под другим названием: ```js //+ run var arr = [1,2]; arr.toClass = {}.toString; alert( arr.toClass() ); // [object Array] ``` ...Но зачем копировать лишнее свойство в объект? Синтаксис `toClass.call(arr)` делает то же самое, поэтому используем его.
  3. Всё, класс получен. При желании можно убрать обёртку `[object ...]`, взяв подстроку вызовом `slice(8,-1)`.
Метод также можно использовать с примитивами: ```js //+ run alert( {}.toString.call(123) ); // [object Number] alert( {}.toString.call("строка") ); // [object String] ``` [warn header="Вызов `{}.toString` в консоли может выдать ошибку"] При тестировании кода в консоли вы можете обнаружить, что если ввести в командную строку `{}.toString.call(...)` -- будет ошибка. С другой стороны, вызов `alert( {}.toString... )` -- работает. Эта ошибка возникает потому, что фигурные скобки `{ }` в основном потоке кода интерпретируются как блок. Интерпретатор читает `{}.toString.call(...)` так: ```js { } // пустой блок кода .toString.call(...) // а что это за точка в начале? не понимаю, ошибка! ``` Фигурные скобки считаются объектом, только если они находятся в контексте выражения. В частности, оборачивание в скобки `( {}.toString... )` тоже сработает нормально. [/warn] ## Итого Обычно в JavaScript используется "утиная" типизация. Свойство `[[Class]]` -- самое надёжное средство проверки типа встроенных объектов, но обычно утиной типизации вполне хватает.