Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык программирования javascript 16.02.12.doc
Скачиваний:
7
Добавлен:
31.08.2019
Размер:
2.86 Mб
Скачать

Более гибкие конструкторы

Показанная функция-конструктор не даёт возможности создавать экземпляры. Как и в Java, Вы можете предоставлять аргументы конструктору для инициализации значений свойств экземпляров. На рисунке показан один из способов сделать это.

Рисунок 8.5 Специфицирование свойств в конструкторе, этап 1

В таблице показаны определения Java и JavaScript для этих объектов.

JavaScript

Java

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 устанавливается пустая строка. Эта идиома используется в данной главе для краткости; однако она может, на первый взгляд, показаться непонятной.

При помощи этих определений Вы можете при создании объекта специфицировать значения локально определяемых свойств. Как видно на Рисунке 8.5, Вы можете использовать следующий оператор для создания нового Engineer:

jane = new Engineer("belau");

Jane-свойства будут теперь:

jane.name == ""; jane.dept == "general"; jane.projects == []; jane.machine == "belau"

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

Итак, функция-конструктор создала общий (родовой/generic) объект и затем специфицировала локальные свойства и значения для этого нового объекта. Вы можете заставить конструктор добавить дополнительные свойства, непосредственно вызвав функцию-конструктор для объекта, стоящего выше в цепочке прототипов. На рисунке показаны эти новые определения.

Рисунок 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 выполняет следующее:

  1. Операция new создаёт общий объект и присваивает его свойство __proto__Engineer.prototype.

  2. Операция new передаёт этот новый объект Engineer-конструктору как значение ключевого слова this.

  3. Конструктор создаёт новое свойство base для этого объекта и присваивает значение конструктора WorkerBee свойству base. Это делает конструктор WorkerBee методомEngineer-объекта.

Имя свойства base не является специальным. Вы может использовать любое верное имя свойства; base просто подходит по смыслу.

  1. Конструктор вызывает метод base, передавая ему в качестве аргументов два аргумента из переданных конструктору ("Doe, Jane" и ["navigator", "javascript"]), а также строку "engineering". Явное использование "engineering" в конструкторе указывает, что все Engineer-объекты имеют одно значение для наследуемого свойства dept, и что это значение переопределяет значение, наследуемое из Employee.

  2. Поскольку base это метод из Engineer, внутри вызова base JavaScript связывает ключевое слово this с объектом, созданным на Этапе 1. Таким образом, функцияWorkerBee в свою очередь передаёт аргументы "Doe, Jane" и ["navigator", "javascript"] в функцию-конструктор Employee. После возвращения из функции-конструктора Employee, функция WorkerBee использует оставшийся аргумент для установки свойства projects.

  3. После возвращения из метода base, конструктор Engineer инициализирует свойствоmachine объекта значением "belau".

  4. После возвращения из конструктора, JavaScript присваивает новый объект переменной jane.

Вы можете подумать, что, вызвав конструктор 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".