Skip to content

Latest commit

 

History

History
1083 lines (764 loc) · 62.3 KB

6-objects.md

File metadata and controls

1083 lines (764 loc) · 62.3 KB

Объекты


Введение

В JavaScript почти всё является объектом.

Давайте расмотрим список нативных типов:

  • String()
  • Number()
  • Boolean()
  • Array()
  • Object()
  • Function()
  • RegExp()
  • Date()
  • Error()
  • Symbol()

Т.е. вы можете использовать их как конструктор при помощи оператора new

var s = new String("Hello World!");  // Что получим?

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

typeof s; // "object" ... not "String"
s instanceof String; // true
Object.prototype.toString.call(s); // "[object String]"

Т.е. мы получили не строку, как могли ожидать, а некоторую объектную обертку над строкой.

Это объектные обертки играют очень важную роль. Дело в том, что примитивы не имеют свойств и методов, а обертка позволяет нам обратиться к методам .length или .toString(). К счастью, в JS эта обёртка создается автоматически, что позволяет нам делать так:

var a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"

Еще несколько примеров, говорящих, что в JS почти всё - объекты:

var a = new Boolean(false);

if (!a) {
    console.log( "Oops" ); // never runs
}

Дело в том, что вы создали объект обертку вокруг примитива false, а объект, как известно, всегда является истиной. В результате вы можете получить не то, что ожидали.

Если вы желаете получить сам примитив из обертки, то можете использовать метод valueOf()

var a = new String("abc");
var b = new Number( 42 );
var c = new Boolean( true );

a.valueOf(); // "abc"
b.valueOf(); // 42
c.valueOf(); // true

Получение примитива также может происходить неявно, в случае если это необходимо, например

var a = new String("abc");
var b = a + ""; // "abc"

typeof a; // "object"
typeof b; // "string"

Так что же такое объект? Давайте разберемся.

Object

Понятие object

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

Помимо собственных свойств, объекты в языке JavaScript могут также наследовать свойства от других объектов, известных под названием «прототипы» (об этом позже).

Объекты в языке JavaScript являются динамическими - обычно они позволяют добавлять и удалять свойства.

Свойства-функции называют «методами» объектов.

var people = {
	// свойство
	name: 'Mad Max',
	// метод
	printName: function () {
		console.log(this.name);
	}
};

people.printName() // 'Mad Max'

Операции с объектами выполняются по ссылке, а не по значению.

var x = {name: 'Mad Max'};
var y = x;

Если переменная x ссылается на объект, и выполняется инструкция var y = x;, в переменную y будет записана ссылка на тот же самый объект, а не его копия.

console.log(y.name); // 'Mad Max'
x.name = 'Jenna Jameson';

console.log(y.name); // 'Jenna Jameson'

Любые изменения, выполняемые в объекте с помощью переменной y, будут также отражаться на переменной x.

Создание объекта

Объекты можно создавать с помощью литералов объектов, ключевого слова new и (в ECMAScript 5) функции Object.create().

Создание объектов с помощью литерала объектов

Самый простой способ создать объект заключается во включении в программу литерала объекта. Литерал объекта - это заключенный в фигурные скобки список свойств (пар имя/значение), разделенных запятыми.

Пример

// Объект без свойств
var empty = {};

var driver = {
	'first name': 'Max', // Имя свойства с пробелом
	skills: {
		mad: 1000
	}
};

Литерал объекта - это выражение, которое создает и инициализирует новый объект всякий раз, когда производится вычисление этого выражения. Значение каждого свойства вычисляется заново, когда вычисляется значение литерала. Это означает, что с помощью единственного литерала объекта можно создать множество новых объектов, если этот литерал поместить в тело цикла или функции, которая будет вызываться многократно, и что значения свойств этих объектов могут отличаться друг от друга.

Создание объектов с помощью оператора new

Оператор new создает и инициализирует новый объект. За этим оператором должно следовать имя функции. Функция, используемая таким способом, называется конструктором и служит для инициализации вновь созданного объекта.

// Создает пустой объект
var obj = new Object();

Создание объектов с помощью Object.create()

Стандарт ECMAScript 5 определяет метод Object.create(), который создает новый объект и использует свой первый аргумент в качестве прототипа этого объекта. Дополнительно Object.create() может принимать второй необязательный аргумент, описывающий свойства нового объекта.

// obj наследует свойства x и y
var obj = Object.create({x:1, y:2});

console.log(obj); // {__proto__: {x:1, y2}};

Чтобы создать объект, не имеющий прототипа, можно передать значение null

// obj2 не наследует ни свойств, ни методов
var obj2 = Object.create(null);

но в этом случае вновь созданный объект не унаследует ни каких-либо свойств, ни базовых методов, таких как toString().

Собственные свойста и методы объекта

Все объекты в JavaScript являются потомками Object; все объекты наследуют методы и свойства из прототипа объекта Object.prototype, хотя они и могут быть переопределены.

  • Object.toString()
  • Object.assign() - Создаёт новый объект путём копирования значений всех собственных перечислимых свойств из одного или более исходных объектов в целевой объект.
  • Object.create() - Создаёт новый объект с указанными объектом прототипа и свойствами.
  • Object.defineProperty() - Добавляет к объекту именованное свойство, описываемое переданным дескриптором.
  • Object.defineProperties() - Добавляет к объекту именованные свойства, описываемые переданными дескрипторами.
  • Object.keys() - Возвращает массив, содержащий имена всех собственных перечислимых свойств переданного объекта.

Получение и изменение свойств

Получить значение свойства можно с помощью операторов точки . и квадратных скобок []. Слева от оператора должно находиться выражение, возвращающее объект. При использовании оператора точки справа должен находиться простой идентификатор, соответствующий имени свойства.

// Простой объект
var user = { login:'twin', 'first-name':'Pavel' };

var login = user.login;		 			// twin
var firstName = user['first-name'];		// Pavel

Как говорилось выше, объекты являются динамическими, т.е. мы можем добавлять/удалять свойста после создания объекта.

Чтобы создать новое свойство или изменить значение существующего свойства, также используются операторы точки и квадратные скобки, как в операциях чтения значений свойств, но само выражение помещается уже слева от оператора присваивания:

user.age = 28;					// Изменить значение свойства 'age'
user['last-name'] = 'Alexov';	// Изменить значение свойства 'last-name'

Ошибки доступа к свойствам

Выражения обращения к свойствам не всегда возвращают или изменяют значение свойства. В этом разделе описываются ситуации, когда операции чтения или записи свойства терпят неудачу.

Попытка обращения к несуществующему свойству не считается ошибкой. Если свойство x не будет найдено среди собственных или унаследованных свойств объекта obj, выражение обращения к свойству obj.x вернет значение undefined.

Однако попытка обратиться к свойству несуществующего объекта считается ошибкой. Значения null и undefined не имеют свойств, и попытки обратиться к свойствам этих значений считаются ошибкой:

// Простой объект
var coord = { x:1, y:2 };

var z = coord.z;			// undefined: свойство отсутствует

// Возбудит исключение TypeError.
// Значение undefined не имеет свойства length
var len = coord.z.length;

Удаление свойств

Оператор delete удаляет свойство из объекта. Его единственный операнд должен быть выражением обращения к свойству. Может показаться удивительным, но оператор delete не оказывает влияния на значение свойства, он оперирует самим свойством:

// Простой объект
var coord = { x:9, y:10 };

delete coord.x;
delete coord['y'];

console.log(coord); // {}

Оператор delete удаляет только собственные свойства и не удаляет унаследованные.

Проверка существования свойств

Объекты в языке JavaScript можно рассматривать как множества свойств, и нередко бывает полезно иметь возможность проверить принадлежность к множеству: проверить наличие в объекте свойства с данным именем. Выполнить такую проверку можно с помощью оператора in, с помощью методов hasOwnProperty() и propertyIsEnumerable() или просто обратившись к свойству.

Оператор in требует, чтобы в левом операнде ему было передано имя свойства (в виде строки) и объект в правом операнде. Он возвращает true, если объект имеет собственное или унаследованное свойство с этим именем:

var obj = { x:1 }
"x" in obj;			// true
"y" in obj;			// false
"toString" in obj;	// true: obj наследует свойство toString

obj.hasOwnProperty('x');		// true: obj имеет собственное свойство "x"
obj.hasOwnProperty('y');		// false
obj.hasOwnProperty('toString');	// false: toString - наследуемое свойство

obj.x !== undefined;			// true
obj.y !== undefined;			// false
obj.toString !== undefined;		// true

Методы чтения и записи свойств (getter/setter)

Выше уже говорилось, что свойство объекта имеет имя, значение и набор атрибутов. В ECMAScript 5 значение может замещаться одним или двумя методами, известными как методы чтения (getter) и записи (setter). Свойства, для которых определяются методы чтения и записи, иногда называют свойствами с методами доступа, чтобы отличать их от свойств с данными, представляющих простое значение.

Когда программа пытается получить значение свойства с методами доступа, интерпретатор вызывает метод чтения (без аргументов). Возвращаемое этим методом значение становится значением выражения обращения к свойству. Когда программа пытается записать значение в свойство, интерпретатор вызывает метод записи, передавая ему значение, находящее справа от оператора присваивания. Этот метод отвечает за «установку» значения свойства. Значение, возвращаемое методом записи, игнорируется.

Если свойство имеет только метод чтения, оно доступно только для чтения. А если свойство имеет только метод записи, оно доступно только для записи (такое невозможно для свойств с данными) и попытки прочитать значение такого свойства всегда будут возвращать undefined.

Самый простой способ определить свойство с методами доступа заключается в использовании расширенного синтаксиса определения литералов объектов:

var point = {
	x: 1.0,
	y: 1.0,

	// r - доступное для чтения/записи свойство с двумя методами доступа.
	get r() {
		return Math.sqrt(this.x * this.x + this.y * this.y);
	},

	set r(newvalue) {
		var oldvalue = Math.sqrt(this.x*this.x + this.y*this.y);
		var ratio = newvalue/oldvalue;

		this.x *= ratio;
		this.y *= ratio;
	},

	// theta - доступное только для чтения свойство с единственным методом чтения
	get theta() { return Math.atan2(this.y, this.x); }
};

point.r = 16;
console.log(point.x, point.y); // 11.313, 11.313
console.log(point.theta); // 0.785

Object.defineProperty

Метод Object.defineProperty() определяет новое или изменяет существующее свойство непосредственно на объекте, возвращая этот объект.

Object.defineProperty(obj, prop, descriptor);
  • obj Объект, на котором определяется свойство.
  • prop Имя определяемого или изменяемого свойства.
  • descriptor Дескриптор определяемого или изменяемого свойства.

Дескрипторы свойств, присутствующие в объектах, бывают двух основных типов:

  • Дескриптор данных — это свойство, имеющее значение, которое может быть (а может и не быть) записываемым.
  • Дескриптор доступа — это свойство, описываемое парой функций — геттером и сеттером.

Дескриптор может быть только чем-то одним из этих двух типов; он не может быть одновременно обоими.

И дескриптор данных, и дескриптор доступа являются объектами. Они обладают следующими обязательными ключами:

  • configurable Равен true только в том случае, если тип этого дескриптора свойства может быть изменён и если свойство может быть удалено из содержащего его объекта. Значение по умолчанию установлено в false.
  • enumerable Равен true только в том случае, если это свойство можно увидеть через перечисление свойств содержащего его объекта. Значение по умолчанию установлено в false.

Дескриптор данных также может содержать следующие дополнительные ключи:

  • value Значение, ассоциированное со свойством. Может быть любым допустимым значением JavaScript (числом, объектом, функцией и т.д.). Значение по умолчанию установлено в undefined.
  • writable Равен true только в том случае, если значение, ассоциированное со свойством, может быть изменено с помощью оператора присваивания. Значение по умолчанию установлено в false.

Дескриптор доступа также может содержать следующие дополнительные ключи:

  • get Функция, используемая как геттер свойства, либо undefined, если свойство не имеет геттера. Возвращаемое значение функции будет использоваться как значение свойства. Значение по умолчанию установлено в undefined.
  • set Функция, используемая как сеттер свойства, либо undefined, если свойство не имеет сеттера. Функция принимает единственным аргументом новое значение, присваиваемое свойству. Значение по умолчанию установлено в undefined.

Примеры

var o = {};

// Пример добавления свойства к объекту через defineProperty() с дескриптором данных
Object.defineProperty(o, 'a', {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true
});
console.log(o.a); // 37
// Пример добавления свойства к объекту через defineProperty() с дескриптором доступа
var bValue = 38;
Object.defineProperty(o, 'b', {
  get: function() { return bValue; },
  set: function(newValue) { bValue = newValue * 10; },
  enumerable: true,
  configurable: true
});
console.log(o.b = 10); // 100
Object.defineProperty(o, 'conflict', {
  value: 0x9f91102,
  get: function() { return 0xdeadbeef; }
});
// Выкинет исключение TypeError: свойство value применимо только в дескрипторах данных, свойство get применимо только в дескрипторах доступа

Сериализация объектов

Сериализация объектов - это процесс преобразования объектов в строковую форму представления, которая позднее может использоваться для их восстановления. Для сериализации и восстановления объектов JavaScript стандартом ECMAScript 5 предоставляются встроенные функции JSON.stringify() и JSON.parse(). Эти функции используют формат обмена данными JSON. Название JSON происходит от «JavaScript Object Notation» (форма записи объектов JavaScript), а синтаксис этой формы записи напоминает синтаксис литералов объектов и массивов в языке JavaScript:

var obj = {x:1, y:{z:[false,null,""]}};
var s = JSON.stringify(obj);			// '{"x":1,"y":{"z":[false,null,""]}}'
var p = JSON.parse(s);					// копия объекта obj

Объекты Function, RegExp и Error и значение undefined не могут быть сериализованы или восстановлены. Функция JSON.stringify() сериализует только перечислимые собственные свойства объекта. Если значение свойства не может быть сериализовано, это свойство просто исключается из строкового представления. Обе функции, JSON.stringify() и JSON.parse(), принимают необязательный второй аргумент, который можно использовать для настройки процесса сериализации и/или восстановления, например, посредством определения списка свойств, подлежащих сериализации, или функции преобразования значений во время сериализации.

Источники и литература


Array

Понятие array

Массив - это упорядоченная коллекция значений. Значения в массиве называются элементами, и каждый элемент характеризуется числовой позицией в массиве, которая называется индексом.

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

Отсчет индексов массивов в языке JavaScript начинается с нуля и для них используются 32-битные целые числа, первый элемент массива имеет индекс 0.

Массивы в JavaScript являются динамическими: они могут увеличиваться и уменьшаться в размерах по мере необходимости; нет необходимости объявлять фиксированные размеры массивов при их создании или повторно распределять память при изменении их размеров.

Массивы в языке JavaScript - это специализированная форма объектов, а индексы массивов означают чуть больше, чем просто имена свойств, которые по совпадению являются целыми числами.

Создание массивов

при помощи литерала []

Легче всего создать массив с помощью литерала, который представляет собой простой список разделенных запятыми элементов массива в квадратных скобках.

var empty = [];						// Пустой массив
var misc = [ 1.1, true, "a"];		// 3 элемента разных типов

var base = 1024;
var table = [base, base+1, base+2, base+3];		// Массив с переменными

при помощи конструктора

  • Вызвать конструктор без аргументов:
var arr = new Array();

В этом случае будет создан пустой массив, эквивалентный литералу [].

  • Вызвать конструктор с единственным числовым аргументом, определяющим длину массива:
var arr = new Array(10);

В этом случае будет создан пустой массив указанной длины. Такая форма вызова конструктора Array() может использоваться для предварительного распределения памяти под массив, если заранее известно количество его элементов. Обратите внимание, что при этом в массиве не сохраняется никаких значений.

  • Явно указать в вызове конструктора значения первых двух или более элементов массива или один нечисловой элемент:
var arr = new Array(5, 4, 3, 2, 1, "тест");

Длина массива (length)

Свойство length представляется беззнаковым 32-х битным целым числом, указывающим количество элементов в массиве.

В любой момент вы можете установить свойство length для обрезки массива. Когда вы расширяете массив, изменяя его свойство length, реальное количество элементов в массиве не увеличивается; например, если вы установите свойство length в 3, когда оно равно 2, массив по-прежнему будет содержить только два элемента. Таким образом, свойство length ничего не говорит о количестве определённых значений в массиве. Также смотрите раздел Взаимосвязь свойства length с числовыми свойствами.

var numbers = [1, 2, 3, 4, 5];
console.log(numbers.length); // 5

var arr = new Array(10);
console.log(arr); // 10

var arr2 = [];
arr2[100] = 1;
console.log(arr2.length); // 101

Т.е. length — не количество элементов массива, а последний индекс + 1.

Дырки в массиве

var a = [1, 2, 3, 4, 5];
delete a[2]; // Получаем дырку - разреженный массив

console.log(a); // [1, 2, undefined, 4, 5]

Чтение и запись элементов массива

Доступ к элементам массива осуществляется с помощью оператора []. Слева от скобок должна присутствовать ссылка на массив. Внутри скобок должно находиться произвольное выражение, возвращающее неотрицательное целое значение. Этот синтаксис пригоден как для чтения, так и для записи значения элемента массива. Следовательно, допустимы все приведенные далее JavaScript-инструкции:

// Создать массив с одним элементом
var arr = ["world"];

// Прочитать элемент 0
var value = arr[0]; // world

// Записать значение в элемент 1
arr[1] = 3.14;

// Записать значение в элемент 2
i = 2; arr[i] = 3; // [3.14, 3]

// Записать значение в элемент 3
arr[i + 1] = 'привет'; // [3.14, 3, 'привет']

Интерпретатор JavaScript преобразует указанные в скобках числовые индексы в строки - индекс 1 превращается в строку "1" - а затем использует строки как имена свойств.

Обратите внимание, что в качестве индексов массивов допускается использовать отрицательные и не целые числа. В этом случае числа преобразуются в строки, которые используются как имена свойств.

var arr = [];
arr[-1] = 10;
console.log(arr[-1]); // 10;

Добавление и удаление элементов массива

var arr = [];		// Создать пустой массив
arr.push('zero');	// Добавить значение в конец
arr.push('one',2);	// Добавить еще два значения
console.log(arr);   // ['zero', 'one', 2];
  • pop() Удаляет последний элемент из массива и возвращает его.
  • push() Добавляет один или более элементов в конец массива и возвращает новую длину массива.
  • shift() Удаляет первый элемент из массива и возвращает его.
  • unshift() Добавляет один или более элементов в начало массива и возвращает новую длину массива.
  • splice() Добавляет и/или удаляет элементы из массива.

Перечисление элементов массива

forEach

arr.forEach(callback[, thisArg])

Метод forEach() выполняет функцию callback один раз для каждого элемента, находящегося в массиве в порядке возрастания. Она не будет вызвана для удалённых или пропущенных элементов массива. Однако она будет вызвана для элементов, которые присутствуют в массиве и имеют значение undefined.

Функция callback будет вызвана с тремя аргументами:

  • значение элемента (value)
  • индекс элемента (index)
  • массив, по которому осуществляется проход (array)
[2, 5, , 9].forEach(function (value, index, array) {
	console.log(value, index);
});

// 2 0
// 5 1
// 9 3

map

arr.map(callback[, thisArg])

Метод map вызывает переданную функцию callback один раз для каждого элемента в порядке их появления и конструирует новый массив из результатов её вызова.

var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
  return num * 2;
});
// теперь doubles равен [2, 8, 18], а numbers всё ещё равен [1, 4, 9]

reduce

arr.reduce(callback[, thisArg])

Функция callback принимает четыре аргумента:

  • previousValue Значение, возвращённое предыдущим выполнением функции callback, либо значение initialValue, если оно предоставлено (смотрите пояснения ниже).
  • currentValue Текущий обрабатываемый элемент массива.
  • index Индекс текущего обрабатываемого элемента массива.
  • array Массив, для которого была вызвана функция reduce.

Метод reduce() выполняет функцию callback один раз для каждого элемента, присутствующего в массиве, за исключением пустот, принимая четыре аргумента: начальное значение (или значение от предыдущего вызова callback), значение текущего элемента, текущий индекс и массив, по которому происходит итерация.

При первом вызове функции, параметры previousValue и currentValue могут принимать одно из двух значений. Если при вызове reduce() передан аргумент initialValue, то значение previousValue будет равным значению initialValue, а значение currentValue будет равным первому значению в массиве. Если аргумент initialValue не задан, то значение previousValue будет равным первому значению в массиве, а значение currentValue будет равным второму значению в массиве.

Если массив пустой и аргумент initialValue не указан, будет брошено исключение TypeError. Если массив состоит только из одного элемента (независимо от его положения в массиве) и аргумент initialValue не указан, или если аргумент initialValue указан, но массив пустой, то будет возвращено одно это значение, без вызова функции callback.

var result = [0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) {
  return previousValue + currentValue;
});
console.log(result); // 10

filter

arr.filter(callback[, thisArg])

Метод filter() вызывает переданную функцию callback один раз для каждого элемента, присутствующего в массиве, и конструирует новый массив со всеми значениями, для которых функция callback вернула true или значение, становящееся true при приведении в boolean.

var filtered = [12, 5, 8, 130, 44].filter(function (value) {
  return value >= 10;
}); // [12, 130, 44]

Другие методы массива

join

var arr = [1, 2, 3];

arr.join();			// '1,2,3'
arr.join("-");		// '1-2-3'

reverse()

var arr = [1, 2, 3];
arr.reverse().join();		// "3,2,1"

sort()

var arr = [33, 4, 1111, 222];
arr.sort();						// Алфавитный порядок: 1111, 222, 33, 4

arr.sort(function(a, b) {
	// Числовой порядок: 4, 33, 222, 1111
	return a-b;		// Возвращает значение < 0, 0 или > 0
					// в зависимости от порядка сортировки a и b
});

// Сортируем в обратном направлении, от большего к меньшему
arr.sort(function(a, b) { return b-a; });

concat()

var arr = [1, 2, 3];
arr.concat(4, 5);		// Вернет	[1, 2, 3, 4, 5]
arr.concat([4, 5]);		// Вернет	[1, 2, 3, 4, 5]

slice()

var arr = [1, 2, 3, 4, 5];
arr.slice(0, 3);		// Вернет [1, 2, 3]
arr.slice(3);		// Вернет [4, 5]
arr.slice(1, -1);	// Вернет [2, 3, 4]
arr.slice(-3, -2);	// Вернет [3]

splice()

Метод splice() изменяет исходный массив, относительно которого он был вызван. Обратите внимание, что методы splice() и slice() имеют очень похожие имена, но выполняют совершенно разные операции.

var arr = [1, 2, 3, 4, 5, 6, 7, 8];

arr.splice(4);					// Вернет [5, 6, 7, 8], arr = [1, 2, 3, 4]
arr.splice(1, 2);				// Вернет [2, 3], arr = [1, 4]
arr.splice(1, 1);				// Вернет [4]; arr = [1]

arr = [1, 2, 3, 4, 5];
arr.splice(2, 0, 'a', 'b');		// Вернет []; arr = [1, 2, 'a', 'b', 3, 4, 5]

Источники и литература


Date

Для работы с датой и временем в JavaScript используются объекты Date.

Создание

Для создания нового объекта типа Date используется один из синтаксисов:

new Date()

Создает объект Date с текущей датой и временем:

var now = new Date();
console.log(now);

new Date(milliseconds)

Создает объект Date, значение которого равно количеству миллисекунд (1/1000 секунды), прошедших с 1 января 1970 года GMT+0.

// 24 часа после 01.01.1970 GMT+0
var Jan02_1970 = new Date(3600 * 24 * 1000);
console.log(Jan02_1970);

new Date(datestring)

Если единственный аргумент – строка, используется вызов Date.parse (см. далее) для чтения даты из неё.

new Date(year, month, date, hours, minutes, seconds, ms)

Дату можно создать, используя компоненты в местной временной зоне. Для этого формата обязательны только первые два аргумента. Отсутствующие параметры, начиная с hours считаются равными нулю, а date — единице.

Заметим:

  • Год year должен быть из 4 цифр.
  • Отсчет месяцев month начинается с нуля 0.

Например:

new Date(2011, 0, 1, 0, 0, 0, 0); // // 1 января 2011, 00:00:00
new Date(2011, 0, 1); // то же самое, часы/секунды по умолчанию равны 0

Дата задана с точностью до миллисекунд:

var date = new Date(2011, 0, 1, 2, 3, 4, 567);
console.log(date); // 1.01.2011, 02:03:04.567

Получение компонентов даты

Для доступа к компонентам даты-времени объекта Date используются следующие методы:

  • getFullYear()

Получить год (из 4 цифр)

  • getMonth()

Получить месяц, от 0 до 11.

  • getDate()

Получить число месяца, от 1 до 31.

  • getHours(), getMinutes(), getSeconds(), getMilliseconds()

Получить соответствующие компоненты.

Некоторые браузеры реализуют нестандартный метод getYear(). Где-то он возвращает только две цифры из года, где-то четыре. Так или иначе, этот метод отсутствует в стандарте JavaScript. Не используйте его. Для получения года есть getFullYear().

Дополнительно можно получить день недели:

  • getDay()

Получить номер дня в неделе. Неделя в JavaScript начинается с воскресенья, так что результат будет числом от 0 (воскресенье) до 6 (суббота).

Все методы, указанные выше, возвращают результат для местной временной зоны.

Существуют также UTC-варианты этих методов, возвращающие день, месяц, год и т.п. для зоны GMT+0 (UTC): getUTCFullYear(), getUTCMonth(), getUTCDay(). То есть, сразу после "get" вставляется "UTC".

Если ваше локальное время сдвинуто относительно UTC, то следующий код покажет разные часы:

// текущая дата
var date = new Date();

// час в текущей временной зоне
console.log(date.getHours());

// сколько сейчас времени в Лондоне?
// час в зоне GMT+0
console.log(date.getUTCHours());

Кроме описанных выше, существуют два специальных метода без UTC-варианта:

  • getTime()

Возвращает число миллисекунд, прошедших с 1 января 1970 года GMT+0, то есть того же вида, который используется в конструкторе new Date(milliseconds).

  • getTimezoneOffset()

Возвращает разницу между местным и UTC-временем, в минутах.

console.log(new Date().getTimezoneOffset()); // Для GMT-1 выведет 60
  • now()

возвращает дату сразу в виде миллисекунд.

Технически, он аналогичен вызову +new Date(), но в отличие от него не создаёт промежуточный объект даты, а поэтому — во много раз быстрее.

Установка компонентов даты

Следующие методы позволяют устанавливать компоненты даты и времени:

  • setFullYear(year [, month, date])
  • setMonth(month [, date])
  • setDate(date)
  • setHours(hour [, min, sec, ms])
  • setMinutes(min [, sec, ms])
  • setSeconds(sec [, ms])
  • setMilliseconds(ms)
  • setTime(milliseconds) (устанавливает всю дату по миллисекундам с 01.01.1970 UTC)

Все они, кроме setTime(), обладают также UTC-вариантом, например: setUTCHours().

Как видно, некоторые методы могут устанавливать несколько компонентов даты одновременно, в частности, setHours. При этом если какая-то компонента не указана, она не меняется. Например:

var today = new Date;

today.setHours(0);
console.log(today); // сегодня, но час изменён на 0

today.setHours(0, 0, 0, 0);
console.log(today); // сегодня, ровно 00:00:00.

Автоисправление даты

Автоисправление — очень удобное свойство объектов Date. Оно заключается в том, что можно устанавливать заведомо некорректные компоненты (например 32 января), а объект сам себя поправит.

var d = new Date(2013, 0, 32); // 32 января 2013 ?!?
console.log(d); // ... это 1 февраля 2013!

Неправильные компоненты даты автоматически распределяются по остальным.

Например,

нужно увеличить на 2 дня дату «28 февраля 2011». Может быть так, что это будет 2 марта, а может быть и 1 марта, если год високосный. Но нам обо всем этом думать не нужно. Просто прибавляем два дня. Остальное сделает Date:

var d = new Date(2011, 1, 28);
d.setDate(d.getDate() + 2);

console.log(d); // 2 марта, 2011

Также это используют для получения даты, отдаленной от имеющейся на нужный промежуток времени. Например, получим дату на 70 секунд большую текущей:

var d = new Date();
d.setSeconds(d.getSeconds() + 70);

console.log(d); // выведет корректную дату

Можно установить и нулевые, и даже отрицательные компоненты. Например:

var d = new Date;

d.setDate(1); // поставить первое число месяца
console.log(d);

d.setDate(0); // нулевого числа нет, будет последнее число предыдущего месяца
console.log(d);

var d = new Date;
d.setDate(-1); // предпоследнее число предыдущего месяца
console.log(d);

Преобразование к числу

Когда объект Date используется в числовом контексте, он преобразуется в количество миллисекунд:

alert(Number(new Date)) // то же самое, что: +data.valueOf()

Важно: даты можно вычитать, результат вычитания объектов Date — их временная разница, в миллисекундах.

Это используют для измерения времени:

var start = new Date; // засекли время

// что-то сделать
for (var i = 0; i < 100000; i++) {
  var doSomething = i * i * i;
}

var end = new Date; // конец измерения

console.log("Цикл занял " + (end - start) + " ms");

console.time

Для измерения с одновременным выводом результатов в консоли есть методы: console.time(метка) — включить внутренний хронометр браузера с меткой. console.timeEnd(метка) — выключить внутренний хронометр браузера с меткой и вывести результат.

Параметр "метка" используется для идентификации таймера, чтобы можно было делать много замеров одновременно и даже вкладывать измерения друг в друга.

console.time('test1')
for (var i = 0; i < 100000; i++) {
  var doSomething = i * i * i;
}
console.timeEnd('test1'); // 'test1: 122.04 ms'

Форматирование и вывод дат

  • toString(),
  • toDateString(),
  • toTimeString()

Возвращают стандартное строчное представление, не заданное жёстко в стандарте, а зависящее от браузера. Единственное требование к нему — читаемость человеком. Метод toString возвращает дату целиком, toDateString() и toTimeString() — только дату и время соответственно.

var d = new Date();
console.log(d.toString()); // вывод, похожий на 'Wed Jan 26 2011 16:40:50 GMT+0300'

Разбор строки, Date.parse

  • YYYY-MM-DD — дата в формате год-месяц-день.
  • Обычный символ T используется как разделитель.
  • HH:mm:ss.sss — время: часы-минуты-секунды-миллисекунды.
  • Часть 'Z' обозначает временную зону — в формате +-hh:mm, либо символ Z, обозначающий UTC. По стандарту её можно не указывать, тогда UTC, но в Safari с этим ошибка, так что лучше указывать всегда.

Также возможны укороченные варианты, например YYYY-MM-DD или YYYY-MM или даже только YYYY.

Метод Date.parse(str) разбирает строку str в таком формате и возвращает соответствующее ей количество миллисекунд. Если это невозможно, Date.parse возвращает NaN.

Например:

var msUTC = Date.parse('2012-01-26T13:51:50.417Z'); // зона UTC

console.log(msUTC); // 1327571510417 (число миллисекунд)

С таймзоной -07:00 GMT:

var ms = Date.parse('2012-01-26T13:51:50.417-07:00');
console.log(ms); // 1327611110417 (число миллисекунд)

Вывод

  • Дата и время представлены в JavaScript одним объектом: Date. Создать «только время» при этом нельзя, оно должно быть с датой.
  • Отсчёт месяцев начинается с нуля.
  • Отсчёт дней недели (для getDay()) тоже начинается с нуля (и это воскресенье).
  • Объект Date удобен тем, что автокорректируется. Благодаря этому легко сдвигать даты.
  • При преобразовании к числу объект Date даёт количество миллисекунд, прошедших с 1 января 1970 UTC. Побочное следствие — даты можно вычитать, результатом будет разница в миллисекундах.
  • Для получения текущей даты в миллисекундах лучше использовать Date.now(), чтобы не создавать лишний объект Date

Math

В отличие от других глобальных объектов, Math не является конструктором. Все свойства и методы Math статичны.

Свойства

  • Math.E

Число Эйлера или Непера, основание натуральных логарифмов, приблизительно равное 2,718.

  • Math.LN2

Натуральный логарифм из 2, приблизительно равен 0,693.

  • Math.LN10

Натуральный логарифм из 10, приблизительно равен 2,303.

  • Math.LOG2E

Двоичный логарифм из E, приблизительно равен 1,443.

  • Math.LOG10E

Десятичный логарифм из E, приблизительно равен 0,434.

  • Math.PI

Отношение длины окружности круга к его диаметру, приблизительно равно 3,14159.

  • Math.SQRT1_2

Квадратный корень из 1/2; или, что тоже самое, 1, делённая на квадратный корень из 2, приблизительно равен 0,707.

  • Math.SQRT2

Квадратный корень из 2, приблизительно равен 1,414.

Методы

Обратите внимание, что тригонометрические функции (sin(), cos(), tan(), asin(), acos(), atan() и atan2()) принимают в параметрах или возвращают углы в радианах. Для преобразования радианов в градусы, поделите их на величину (Math.PI / 180); для преобразования в обратном направлении, умножьте градусы на эту же величину.

  • Math.abs(x)

Возвращает абсолютное значение числа.

  • Math.cos(x)

Возвращает косинус числа.

  • Math.floor(x)

Возвращает наибольшее целое число, меньшее, либо равное указанному числу.

  • Math.log(x)

Возвращает натуральный логарифм числа (loge, также известен как ln).

  • Math.max([x[, y[, …]]])

Возвращает наибольшее число из своих аргументов.

  • Math.min([x[, y[, …]]])

Возвращает наименьшее число из своих аргументов.

  • Math.random()

Возвращает псевдослучайное число в диапазоне от 0 до 1.

  • Math.round(x)

Возвращает значение числа, округлённое до ближайшего целого.

  • Math.sign(x)

Возвращает знак числа, указывающий, является ли число положительным, отрицательным или нулём.

  • Math.sin(x)

Возвращает синус числа.

  • Math.sqrt(x)

Возвращает положительный квадратный корень числа.

  • Math.tan(x)

Возвращает тангенс числа.

  • ... И много других