Javascript class object type

How to get the object type

But all I get told is that it is an Object. This error only occurs when the cache is empty and the data is loaded from a spreadsheet. E.g. User hits the page, the get the error, a refresh now loads the page as the cache was populated on the first hit. Now users can continue using the page until the cache is invalidated, then the next hit will cause this error again. This error started happening today after I read and followed this document. Previously my script was loading data in the template, I have now refactored to load asynchronously using:

I took a look at what was happening in my page as to why it worked when read from cache and the only thing I could see different was that data in the cache had been parsed from a JSON string. When the cache is empty I have to stringify the object in order to save into the cache, so rather than returning my original object, I then parse the string I just created and return that and now there is no error. I’m not sure where the error is coming from either, is it Apps Script or is it Caja? Parsing the JSON string back in order to return is not the ideal solution either, what is this stringifying / parsing doing to my original object that removes the error? When I use the built in debugger to inspect the objects (before and after the stringifying / parsing process) the values and types all seem to be identical to the best of my ability to check. Is this a bug in Apps Script? Am I doing something wrong? What is the best solution to remove this error?

Источник

Типы данных: [[Class]], instanceof и утки

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/instanceof.

Время от времени бывает удобно создавать так называемые «полиморфные» функции, то есть такие, которые по-разному обрабатывают аргументы, в зависимости от их типа. Например, функция вывода может по-разному форматировать числа и даты.

Для реализации такой возможности нужен способ определить тип переменной.

Оператор typeof

Мы уже знакомы с простейшим способом – оператором typeof.

Оператор typeof надёжно работает с примитивными типами, кроме null , а также с функциями. Он возвращает для них тип в виде строки:

alert( typeof 1 ); // 'number' alert( typeof true ); // 'boolean' alert( typeof "Текст" ); // 'string' alert( typeof undefined ); // 'undefined' alert( typeof null ); // 'object' (ошибка в языке) alert( typeof alert ); // 'function'

…Но все объекты, включая массивы и даты для typeof – на одно лицо, они имеют один тип ‘object’ :

alert( typeof <> ); // 'object' alert( typeof [] ); // 'object' alert( typeof new Date ); // 'object'

Поэтому различить их при помощи typeof нельзя, и в этом его основной недостаток.

Читайте также:  Ошибка 500 при обновлении php

Секретное свойство [[Class]]

Для встроенных объектов есть одна «секретная» возможность узнать их тип, которая связана с методом toString .

Во всех встроенных объектах есть специальное свойство [[Class]] , в котором хранится информация о его типе или конструкторе.

Оно взято в квадратные скобки, так как это свойство – внутреннее. Явно получить его нельзя, но можно прочитать его «в обход», воспользовавшись методом toString стандартного объекта Object .

Его внутренняя реализация выводит [[Class]] в небольшом обрамлении, как «[object значение]» .

var toString = <>.toString; var arr = [1, 2]; alert( toString.call(arr) ); // [object Array] var date = new Date; alert( toString.call(date) ); // [object Date] var user = < name: "Вася" >; alert( toString.call(user) ); // [object Object]

В первой строке мы взяли метод toString , принадлежащий именно стандартному объекту <> . Нам пришлось это сделать, так как у Date и Array – свои собственные методы toString , которые работают иначе.

Затем мы вызываем этот toString в контексте нужного объекта obj , и он возвращает его внутреннее, невидимое другими способами, свойство [[Class]] .

Для получения [[Class]] нужна именно внутренняя реализация toString стандартного объекта Object , другая не подойдёт.

К счастью, методы в JavaScript – это всего лишь функции-свойства объекта, которые можно скопировать в переменную и применить на другом объекте через call/apply . Что мы и делаем для <>.toString .

Метод также можно использовать с примитивами:

alert( <>.toString.call(123) ); // [object Number] alert( <>.toString.call("строка") ); // [object String]

При тестировании кода в консоли вы можете обнаружить, что если ввести в командную строку <>.toString.call(. ) – будет ошибка. С другой стороны, вызов alert( <>.toString. ) – работает.

Эта ошибка возникает потому, что фигурные скобки < >в основном потоке кода интерпретируются как блок. Интерпретатор читает <>.toString.call(. ) так:

 < >// пустой блок кода .toString.call(. ) // а что это за точка в начале? не понимаю, ошибка!

Фигурные скобки считаются объектом, только если они находятся в контексте выражения. В частности, оборачивание в скобки ( <>.toString. ) тоже сработает нормально.

Для большего удобства можно сделать функцию getClass , которая будет возвращать только сам [[Class]] :

function getClass(obj) < return <>.toString.call(obj).slice(8, -1); > alert( getClass(new Date) ); // Date alert( getClass([1, 2, 3]) ); // Array

Заметим, что свойство [[Class]] есть и доступно для чтения указанным способом – у всех встроенных объектов. Но его нет у объектов, которые создают наши функции. Точнее, оно есть, но равно всегда «Object» .

function User() <> var user = new User(); alert( <>.toString.call(user) ); // [object Object], не [object User]

Поэтому узнать тип таким образом можно только для встроенных объектов.

Читайте также:  Request python 3 документация

Метод Array.isArray()

Для проверки типа на массив есть специальный метод: Array.isArray(arr) . Он возвращает true только если arr – массив:

alert( Array.isArray([1,2,3]) ); // true alert( Array.isArray("not array")); // false

Но этот метод – единственный в своём роде.

Других аналогичных, типа Object.isObject , Date.isDate – нет.

Оператор instanceof

Оператор instanceof позволяет проверить, создан ли объект данной функцией, причём работает для любых функций – как встроенных, так и наших.

function User() <> var user = new User(); alert( user instanceof User ); // true

Таким образом, instanceof , в отличие от [[Class]] и typeof может помочь выяснить тип для новых объектов, созданных нашими конструкторами.

Заметим, что оператор instanceof – сложнее, чем кажется. Он учитывает наследование, которое мы пока не проходили, но скоро изучим и затем вернёмся к instanceof в главе Проверка класса: «instanceof».

Утиная типизация

Альтернативный подход к типу – «утиная типизация», которая основана на одной известной пословице: «If it looks like a duck, swims like a duck and quacks like a duck, then it probably is a duck (who cares what it really is)».

В переводе: «Если это выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это утка (какая разница, что это на самом деле)».

Смысл утиной типизации – в проверке необходимых методов и свойств.

Например, мы можем проверить, что объект – массив, не вызывая Array.isArray , а просто уточнив наличие важного для нас метода, например splice :

var something = [1, 2, 3]; if (something.splice)

Обратите внимание – в if мы не вызываем метод something.splice() , а пробуем получить само свойство something.splice . Для массивов оно всегда есть и является функцией, т.е. даст в логическом контексте true .

Проверить на дату можно, определив наличие метода getTime :

var x = new Date(); if (x.getTime) < alert( 'Дата!' ); alert( x.getTime() ); // работаем с датой >

С виду такая проверка хрупка, её можно «сломать», передав похожий объект с тем же методом.

Но как раз в этом и есть смысл утиной типизации: если объект похож на дату, у него есть методы даты, то будем работать с ним как с датой (какая разница, что это на самом деле).

То есть мы намеренно позволяем передать в код нечто менее конкретное, чем определённый тип, чтобы сделать его более универсальным.

Если говорить словами «классического программирования», то «duck typing» – это проверка реализации объектом требуемого интерфейса. Если реализует – ок, используем его. Если нет – значит это что-то другое.

Пример полиморфной функции

Пример полиморфной функции – sayHi(who) , которая будет говорить «Привет» своему аргументу, причём если передан массив – то «Привет» каждому:

function sayHi(who) < if (Array.isArray(who)) < who.forEach(sayHi); >else < alert( 'Привет, ' + who ); >> // Вызов с примитивным аргументом sayHi("Вася"); // Привет, Вася // Вызов с массивом sayHi(["Саша", "Петя"]); // Привет, Саша. Петя // Вызов с вложенными массивами - тоже работает! sayHi(["Саша", "Петя", ["Маша", "Юля"]]); // Привет Саша..Петя..Маша..Юля

Проверку на массив в этом примере можно заменить на «утиную» – нам ведь нужен только метод forEach :

Читайте также:  Показать скрытую кнопку html

Итого

Для написания полиморфных (это удобно!) функций нам нужна проверка типов.

  • Для примитивов с ней отлично справляется оператор typeof . У него две особенности:
    • Он считает null объектом, это внутренняя ошибка в языке.
    • Для функций он возвращает function , по стандарту функция не считается базовым типом, но на практике это удобно и полезно.

    Задачи

    Полиморфная функция formatDate

    Напишите функцию formatDate(date) , которая возвращает дату в формате dd.mm.yy .

    Её первый аргумент должен содержать дату в одном из видов:

    1. Как объект Date .
    2. Как строку, например yyyy-mm-dd или другую в стандартном формате даты.
    3. Как число секунд с 01.01.1970 .
    4. Как массив [гггг, мм, дд] , месяц начинается с нуля

    Для этого вам понадобится определить тип данных аргумента и, при необходимости, преобразовать входные данные в нужный формат.

    function formatDate(date) < /* ваш код */ >alert( formatDate('2011-10-02') ); // 02.10.11 alert( formatDate(1234567890) ); // 14.02.09 alert( formatDate([2014, 0, 1]) ); // 01.01.14 alert( formatDate(new Date(2014, 0, 1)) ); // 01.01.14

    Для определения примитивного типа строка/число подойдёт оператор typeof.

    alert( typeof 123 ); // "number" alert( typeof "строка" ); // "string" alert( typeof new Date() ); // "object" alert( typeof [] ); // "object"

    Оператор typeof не умеет различать разные типы объектов, они для него все на одно лицо: «object» . Поэтому он не сможет отличить Date от Array .

    Для отличия Array используем вызов Array.isArray . Если он неверен, значит у нас дата.

    function formatDate(date) < if (typeof date == 'number') < // перевести секунды в миллисекунды и преобразовать к Date date = new Date(date * 1000); >else if (typeof date == 'string') < // строка в стандартном формате автоматически будет разобрана в дату date = new Date(date); >else if (Array.isArray(date)) < date = new Date(date[0], date[1], date[2]); >// преобразования для поддержки полиморфизма завершены, // теперь мы работаем с датой (форматируем её) return date.toLocaleString("ru", ); /* // можно и вручную, если лень добавлять в старый IE поддержку локализации var day = date.getDate(); if (day < 10) day = '0' + day; var month = date.getMonth() + 1; if (month < 10) month = '0' + month; // взять 2 последние цифры года var year = date.getFullYear() % 100; if (year < 10) year = '0' + year; var formattedDate = day + '.' + month + '.' + year; return formattedDate; */ >

    Источник

Оцените статью