renovations
This commit is contained in:
parent
c7d4c7e3ff
commit
e1948130f6
170 changed files with 1496 additions and 1161 deletions
103
1-js/7-js-misc/1-class-property/article.md
Normal file
103
1-js/7-js-misc/1-class-property/article.md
Normal file
|
@ -0,0 +1,103 @@
|
|||
# Секретное свойство [[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
|
||||
```
|
||||
|
||||
Разберем происходящее более подробно.
|
||||
|
||||
<ol>
|
||||
<li>Можно переписать эту строку в две:
|
||||
|
||||
```js
|
||||
var obj = {};
|
||||
var toClass = obj.toString;
|
||||
```
|
||||
|
||||
Иначе говоря, мы создаём пустой объект `{}` и копируем ссылку на его метод `toString` в переменную `toClass`.
|
||||
|
||||
**Для получения `[[Class]]` нужна именно внутренняя реализация `toString` стандартного объекта `Object`, другая не подойдёт.**</li>
|
||||
<li>Вызываем скопированный метод в контексте нужного объекта `obj`.
|
||||
|
||||
Мы могли бы поступить проще -- одолжить метод под другим названием:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = [1,2];
|
||||
arr.toClass = {}.toString;
|
||||
|
||||
alert( arr.toClass() ); // [object Array]
|
||||
```
|
||||
|
||||
...Но зачем копировать лишнее свойство в объект? Синтаксис `toClass.call(arr)` делает то же самое, поэтому используем его.
|
||||
</li>
|
||||
<li>Всё, класс получен. При желании можно убрать обёртку `[object ...]`, взяв подстроку вызовом `slice(8,-1)`.</li>
|
||||
</ol>
|
||||
|
||||
Метод также можно использовать с примитивами:
|
||||
|
||||
```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]
|
||||
|
||||
## Итого
|
||||
|
||||
<ul>
|
||||
<li>Свойство `[[Class]]` позволяет получить тип для встроенных объектов. Далее мы будем рассматривать создание своих объектов через функцию-конструктор, с ними `[[Class]]` не работает.</li>
|
||||
<li>Для доступа к `[[Class]]` используется `{}.toString.call(obj).slice(8, -1)`.</li>
|
||||
</ul>
|
||||
|
||||
Обычно в JavaScript используется "утиная" типизация. Свойство `[[Class]]` -- самое надёжное средство проверки типа встроенных объектов, но обычно утиной типизации вполне хватает.
|
Loading…
Add table
Add a link
Reference in a new issue