en.javascript.info/1-js/6-objects-more/3-constructor-new/article.md
2015-01-14 10:23:45 +03:00

191 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Создание объектов через "new"
Обычный синтаксис `{...}` позволяет создать один объект. Но зачастую нужно создать много однотипных объектов.
Для этого используют "функции-конструкторы", запуская их при помощи специального оператора `new`.
[cut]
## Конструктор
Конструктором становится любая функция, вызванная через `new`.
Например:
```js
function Animal(name) {
this.name = name;
this.canWalk = true;
}
*!*
var animal = new Animal("ёжик");
*/!*
```
Технически, любую функцию можно вызвать при помощи `new`. Но при этом она работает несколько иным образом, чем обычно, поэтому функции, предназначенные к вызову через `new`, называют с большой буквы.
**Алгоритм работы функции, запущенной через `new`:**
<ol>
<li>Автоматически создается новый пустой объект.</li>
<li>Ключевое слово `this` получает ссылку на этот объект.</li>
<li>Функция выполняется. Как правило, она модифицирует `this`, добавляет методы, свойства.</li>
<li>Возвращается `this`.</li>
</ol>
В результате вызова `new Animal("ёжик");` получаем такой объект:
```js
animal = {
name: "ёжик",
canWalk: true
}
```
Иными словами, при вызове `new Animal` происходит что-то в таком духе (первая и последняя строка -- это то, что делает интерпретатор):
```js
function Animal(name) {
*!*
// this = {}
*/!*
// в this пишем свойства, методы
this.name = name;
this.canWalk = true;
*!*
// return this
*/!*
}
```
## Правила обработки return
Как правило, конструкторы ничего не возвращают. Их задача -- записать всё, что нужно, в `this`, который автоматически станет результатом.
Но если явный вызов `return` всё же есть, то применяется простое правило:
<ul>
<li>При вызове `return` с объектом, будет возвращён он, а не `this`.</li>
<li>При вызове `return` с примитивным значением, оно будет отброшено.</li>
</ul>
Иными словами, вызов `return` с объектом вернёт объект, а с чем угодно, кроме объекта -- возвратит, как обычно, `this`.
Например, возврат объекта:
```js
//+ run
function BigAnimal() {
this.name = "Мышь";
return { name: "Годзилла" }; // <-- возвратим объект
}
alert( new BigAnimal().name ); // Годзилла, получили объект вместо this
```
А вот пример с возвратом строки:
```js
//+ run
function BigAnimal() {
this.name = "Мышь";
return "Годзилла"; // <-- возвратим примитив
}
alert( new BigAnimal().name ); // Мышь, получили this (а Годзилла пропал)
```
Эта особенность работы `new` прописана в стандарте, но используется она весьма редко.
[smart header="Можно без скобок"]
Кстати, при вызове `new` без аргументов скобки можно не ставить:
```js
var animal = new BigAnimal; // <-- без скобок
// то же самое что
var animal = new BigAnimal();
```
Не сказать, что выбрасывание скобок -- "хороший стиль", но такой синтаксис допустим стандартом.
[/smart]
## Создание методов в конструкторе
Использование функций для создания объекта дает большую гибкость. Можно передавать конструктору параметры, определяющие как его создавать, и он будет "клепать" объекты заданным образом.
Добавим в создаваемый объект ещё и метод.
Например, `new User(name)` создает объект с заданным значением свойства `name` и методом `sayHi`:
```js
//+ run
function User(name) {
this.name = name;
this.sayHi = function() {
alert("Моё имя: " + this.name);
};
}
*!*
var ivan = new User("Иван");
ivan.sayHi(); // Моё имя: Иван
*/!*
/*
ivan = {
name: "Иван",
sayHi: функция
}
*/
```
## Локальные переменные
В функции-конструкторе бывает удобно объявить вспомогательные локальные переменные и вложенные функции, которые будут видны только внутри:
```js
//+ run
function User(firstName, lastName) {
*!*
// вспомогательная переменная
var phrase = "Привет";
// вспомогательная вложенная функция
function getFullName() {
return firstName + " " + lastName;
}
*/!*
this.sayHi = function() {
alert(phrase + ", " + getFullName()); // использование
};
}
var vasya = new User("Вася", "Петров");
vasya.sayHi(); // Вася Петров
```
Мы уже говорили об этом подходе ранее, в главе [](/closures-usage).
Те функции и данные, которые должны быть доступны для внешнего кода, мы пишем в `this` -- и к ним можно будет обращаться, как например `vasya.sayHi()`, а вспомогательные, которые нужны только внутри самого объекта, сохраняем в локальной области видимости.
## Итого
Объекты могут быть созданы при помощи функций-конструкторов:
<ul>
<li>Любая функция может быть вызвана с `new`, при этом она получает новый пустой объект в качестве `this`, в который она добавляет свойства. Если функция не решит возвратить свой объект, то её результатом будет `this`.</li>
<li>Функции, которые предназначены для создания объектов, называются *конструкторами*. Их названия пишут с большой буквы, чтобы отличать от обычных.</li>
</ul>