Более Гибкие Конструкторы
Конструкторы функций не позволяют специфицировать значения свойств при создании экземпляра. Как и в Java, Вы можете предоставлять конструктору аргументы для инициализации значений свойств экземпляров. На рисунке показан один из способов реализации этого.
Рисунок 8.5 Специфицирование свойств в конструкторе, шаг 1

В таблице даны определения Java и JavaScript для этих объектов.
function Employee (name, dept) { this.name = name ""; this.dept = dept "general"; } |
public class Employee { public String name; public String dept; public Employee () { this("", "general"); } public Employee (name) { this(name, "general"); } public Employee (name, dept) { this.name = name; this.dept = dept; } } |
function WorkerBee (projs) { this.projects = projs []; } WorkerBee.prototype = new Employee; |
public class WorkerBee extends Employee { public String[] projects; public WorkerBee () { this(new String[0]); } public WorkerBee (String[] projs) { this.projects = projs; } } |
function Engineer (mach) { this.dept = "engineering"; this.machine = mach ""; } Engineer.prototype = new WorkerBee; |
public class Engineer extends WorkerBee { public String machine; public WorkerBee () { this.dept = "engineering"; this.machine = ""; } public WorkerBee (mach) { this.dept = "engineering"; this.machine = mach; } } |
Эти определения JavaScript используют специальную идиому для установки значений по умолчанию:
this.name = name "";
Операция JavaScript "логическое ИЛИ" () вычисляет свой первый аргумент. Если он конвертируется в true, операция возвращает его. Иначе, операция возвращает значение второго аргумента. Следовательно, эта строка кода проверяет, имеет ли name используемое значение для свойства name. Если это так, в this.name устанавливается это значение. В ином случае, в this.name устанавливается пустая строка. В этой главе используется эта идиома используется для краткости; однако это может на первый взгляд показаться непонятным.
Имея эти определения при создании экземпляра объекта, Вы можете специфицировать значения для локально определяемых свойств. Как показано на , Вы можете использовать следующий оператор для создания нового Engineer:
jane = new Engineer("belau");
Jane-свойства теперь:
jane.name == "";
jane.dept == "general";
jane.projects == [];
jane.machine == "belau"
Заметьте, что с помощью этих определений Вы не можете специфицировать начальное значение наследуемого свойства, такого как name. Если Вы не хотите специфицировать начальные значения наследуемых свойств в JavaScript, Вам нужно добавить дополнительный код в конструктор функции.
Пока что конструктор функции создал общий объект и специфицировал локальные свойства и значения для нового объекта. Вы можете заставить конструктор добавить свойства, непосредственно вызывая конструктор функции для объект, стоящего выше в цепочке прототипов. Следующий рисунок показывает эти новые определения.
Рисунок 8.6   Специфицирование свойств в конструкторе, шаг 2

Давайте рассмотрим одно из этих определений подробнее. Вот новое определение конструктора Engineer:
function Engineer (name, projs, mach) {
this.base = WorkerBee;
this.base(name, "engineering", projs);
this.machine = mach "";
}
Предположим, Вы создаёте новый Engineer-объект:
jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
JavaScript выполняет следующие шаги:
- Оператор new создаёт общий объект и устанавливает в его свойство __proto__ значение Engineer.prototype.
Имя свойства base не является специальным. Вы можете использовать любое правильное имя свойства; base просто более понятно в данной ситуации.
Вы можете подумать, что, имея вызов конструктора WorkerBee из конструктора Engineer, Вы установили соответствующее наследование для Engineer-объектов, но это не так. Вызов конструктора WorkerBee гарантирует, что Engineer-объект стартует со свойствами, специфицированными во всех конструкторах функций, которые были вызваны. Однако, если Вы позднее добавите свойства к прототипам Employee или WorkerBee, эти свойства не будут наследоваться Engineer-объектом. Например, мы имеем следующие операторы:
function Engineer (name, projs, mach) {
this.base = WorkerBee;
this.base(name, "engineering", projs);
this.machine = mach "";
}
jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
Employee.prototype.specialty = "none";
Объект jane не наследует свойство specialty. Вы всё ещё должны явно установить прототип, чтобы гарантировать динамическое наследование. Предположим, у нас есть такие операторы:
function Engineer (name, projs, mach) {
this.base = WorkerBee;
this.base(name, "engineering", projs);
this.machine = mach "";
}
Engineer.prototype = new WorkerBee;
jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
Employee.prototype.specialty = "none";
Теперь значение свойства specialty объекта jane установлено в "none".