понедельник, 22 сентября 2014 г.

БАЗОВЫЕ ТИПЫ ДАННЫХ JavaScript

Неформальное определение: тип - внутренняя встроенная характеристика, которая позволяет определить некоторое значение и однозначно отличать его от прочих значений как движку, так и разработчику. Например, если и разработчик и движок трактуют значение 42 иначе, чем "42", эти значения относятся к разным типам.

Важно! Переменные не имеют типа. Его имеют только значения, которые содержат эти переменные.

typeof - встроенный оператор языка, возвращающий строку, содержащую название типа. Определяется тип значения (value) той конструкции, которую передали оператору (это может быть переменная, выражение или примитив).

Встроенные примитивы языка:

1. Объекты (typeof {}; // > object)

Важно! Массивы и функции являются разновидностями объектов ( typeof [] === "object" ) с особыми свойствами. Функции могут исполняться (благодаря внутреннему свойств [[Call]], содержащему код функции), массивы имеют целочисленные свойства и автоматически изменяемое свойство length.

2. Строковые литералы (typeof "abc"; // > string)
3. Числа (все - с плавающей точкой двойной точности, typeof 123; // > number)
4. Булевские значения - true, false (typeof true; // > boolean)

Специальные значения:
5. undefined - значение по умолчанию, предопределенная переменная, назначается автоматически, неожиданно отсутствующие данные, в том месте, где они предполагаются (type of undefined; // undefined).

Получается следующим образом:
- Значение переменной по умолчанию (объявление без присвоения).
- Обращение к несуществующему свойству объекта или отсутствующему элементу массива.
- Обращение к отсутствующему аргументу функции.
- Результат выполнения функции без оператора return или с оператором return без параметра.
- Результат использования оператора void expr;

Важно! Фактические могут находиться в двух состояниях - undefined (переменная объявлена, но не имеет значения) и uneclared (переменная не объявлена). Обращение к переменной в состоянии undefined не вызывает ошибки (вернётся undefined), а в состоянии undeclared вызывает ReferenceError. Проблема заключается в том, что typeof для обоих состояний возвращает undefined (причём без ошибки для необъявленных переменных).

6. null - намеренно отсутствующие данные в том месте, в котором они предполагаются, фактически - оператор, однако typeof null === "object". Это известная ошибка языка (фактически должна возвращаться строка "null"), однако она вряд ли будет исправлена.
Объекту, который перестали использовать, лучше сразу присваивать значение null, чтобы освобождать память и не вызывать дополнительно GC и чтобы вылавливать ошибки с повторным обращением к объекту, которых не должно быть.

7. Стандарт ES6 вводит также тип Symbol. ( typeof Symbol() === "symbol" )

Встроенные объекты языка:

String - обёртка для string
typeof "abc"; //"string"
typeof String("abc"); //"string"
typeof new String("abc"); //"object"
typeof (new String("abc")).valueOf(); //"string"

Number - обёртка для number
typeof 123; //"number"
typeof Number(123); //"number"
typeof new Number(123); //"object"
typeof (new Number(123)).valueOf(); //"number"

Boolean - обёртка для boolean
typeof true; //"boolean"
typeof Boolean(true); //"boolean"
typeof new Boolean(true); //"object"
typeof (new Boolean(true)).valueOf(); //"boolean"

Прочие встроенные объекты:

Array        // var a = new Array или var a = [];
Date 
Function   // var f = new Function() или var f = function() {};
RegExp    // var s = new Regexp(/\s*/) или var r = /\s*/;
Math
JSON

Object       // var o = new Object или var o = {}; 
Error

Важно! Объект является базовым типом языка, использование оператора new всегда возвращает объект. Примитивы были введены с целью повышения скорости работы движка. Только объекты имеют свойства и методы. При обращении к методам примитивов (причем только числовых, строковых и логических) они временно приводятся к объектам и методы корректно исполняются. Однако попытки присвоить значения свойствам примитивов ничего не дают - в дальнейшем эти свойства возвращают undefined.

Обращение к свойствам и методам значений unedifned и null (или переменных, содержащих эти значения) вызовет ошибку TypeError.

Каждый объект имеет два внутренних свойства-метода valueOf() и toString(), которые могут быть переопределены. Они неявно вызываются при использовании объекта (или ссылки на него), valueOf() при использовании в числовом контексте (арифметические операции с объектами), toString() - в строковом.

Примитивы можно сравнивать напрямую, в отличие от объектов они не имеют внутреннего идентификатора и представляются только своим значением. Объекты сравниваются по ссылке, поэтому два объекта с одинаковыми полями не равны друг другу:

var a = { x: 10 }
var b = { x: 10 }
var c = a;
console.log(a == b);  // false
console.log(a === b); // false
console.log(a == c);  // true
console.log(a === c); // true

typeof возвращает "object" для всех типов кроме Function, Object и Error, для которых возвращается "function".
Единственный способ избежать ReferenceError для необъявленной переменной - предварительно использовать typeof переменная (вернет "undefined"). При этом реально переменная является undeclared.

value instanceof Constructor

эквивалентно

Constructor.protoptype.isPrototypeOf(value

Следующая функция возвращает более конкретный тип для каждого объекта, включая встроенные:


var toType = function(obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}


toType({a: 4}); //"object"
toType([1, 2, 3]); //"array"
toType(null); //"null"
toType(undefined); //"undefined"
(function() {console.log(toType(arguments))})(); //arguments
toType(new ReferenceError); //"error"
toType(new Date); //"date"
toType(/a-z/); //"regexp"
toType(Math); //"math"
toType(JSON); //"json"
toType(new Number(4)); //"number"
toType(new String("abc")); //"string"
toType(new Boolean(true)); //"boolean"

Однако возможны нюансы при работе с хост-объектами, которые создаются браузерами и не подчиняются стандарту:


toType(window);
//"global" (Chrome) "domwindow" (Safari) "window" (FF/IE9) "object" (IE7/IE8)
toType(document);
//"htmldocument" (Chrome/FF/Safari) "document" (IE9) "object" (IE7/IE8)
toType(document.createElement('a'));
//"htmlanchorelement" (Chrome/FF/Safari/IE) "object" (IE7/IE8)
toType(alert);
//"function" (Chrome/FF/Safari/IE9) "object" (IE7/IE8)

Модифицированный вариант функции:

function getTypeName(value) {
  if (value === null) {
    return "null";
  }
  var t = typeof value;
  switch(t) {
    case "function":
    case "object":
      if (value.constructor) {
        if (value.constructor.name) {
          return value.constructor.name;
        } else {
          // Internet Explorer
          // Anonymous functions are stringified 
          // as follows: 'function () {}'
          // => the regex below does not match
          var match = value.constructor.toString().match(/^function (.+)\(.*$/);
          if (match) {
            return match[1];
          }
        }
      }
      // fallback, for nameless constructors etc.
      return Object.prototype.toString.call(value).match(/^\[object (.+)\]$/)[1];
    default:
      return t;
  }
}


Комментариев нет :

Отправить комментарий