Что такое конструктор в js. JavaScript Конструкторы объектов. Явный возврат объекта

function User(name, age) { this.name = name; this.age = age; this.sayHi = function () { console.log("Hello!"); } } let user = new User("Homer", 33); console.log(user.name);

У каждого объекта, созданного с помощью конструктора, есть неявно добавленное свойство constructor , содержащее ссылку на конструктор, с помощью которого был создан объект:

Console.log(user.constructor === User); // true

Свойство constructor предназначено для идентификации типа объекта. Тоже самое позволяет сделать оператор instanceof :

Console.log(user instanceof User); // true

При использовании конструктора для создания объекта, для каждого созданного объекта создаётся своя копия свойств и методов.

Шаблон "Прототип"

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

Вместо того, чтобы указывать свойства и методы в конструкторе, их можно указать непосредственно прототипу:

Function User() {} User.prototype.name = "Homer"; User.prototype.age = "33"; User.prototype.sayHi = function () { console.log("Hello!"); }; let user = new User(); console.log(user.name);

По умолчанию все прототипы имеют только свойство constructor , содержащее ссылку на функцию, к которой оно относится:

Function foo() {} console.log(foo.prototype.constructor === foo); // true

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

Function foo() {} let obj = new foo(); console.log(Object.getPrototypeOf(obj) === foo.prototype); // true

При чтении свойства объекта начинается его поиск. Сначала свойство с указанным именем ищется в самом объекте. Если оно обнаруживается у объекта, возвращается значение свойства, если свойства с таким именем нет у объекта, поиск продолжается в прототипе. В случае обнаружения свойства у прототипа возвращается его значение. Так прототипы обеспечивают совместное использование свойств и методов у объектов.

Если в объект добавить свойство с именем, как у свойства прототипа, то у объекта будет создано собственное свойство, в этом случае при следующем чтении свойства будет использоваться свойство объекта, а не прототипа.

Чтобы писать меньше кода, можно перезаписать прототип литералом объекта, содержащим все свойства и методы:

Function User() {} User.prototype = { name: "Homer", age: 33, sayHi: function () { console.log("Hello!"); } }; // Восстановление свойства constructor Object.defineProperty(User.prototype, "constructor", { enumerable: false, value: User });

В этом примере свойству User.prototype присваивается новый объект, созданный с помощью литерала. Он полностью заменяет собою объект, предлагаемый по умолчанию. Результат получается таким же, как и в предыдущем примере, за одним исключением: свойство constructor больше не указывает на функцию User . Явное добавление свойства constructor со значением User в литерал объекта решает эту проблему. Свойство constructor у встроенных объектов по умолчанию неперечислимо, поэтому для его добавления использовался метод Object.defineProperty() .

Объединение шаблонов "конструктор" и "прототип"

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

Function User(name, age) { this.name = name; this.age = age; } User.prototype.sayHi = function () { console.log("Hello!"); }

Сразу после того, как мы создали функцию, у нее есть свойство prototype , куда записан некоторый объект:

Var Foo = function() {} alert(Foo.prototype) //

Правда, это свойство как тот суслик, который есть несмотря на то, что его не видишь:

Var Foo = function() {} Foo.prop = "ololo"; for (var i in Foo) { alert("Foo."+i + " = " + Foo[i]) } // выведет "Foo.prop = ololo" // и НЕ выведет никакого Foo.prototype

Если попытаться изучить, как устроен объект, который сидит в этом свойстве, может показаться, что он - пустой:

Var Foo = function() {} for (var i in Foo.prototype) { alert("Foo.prototype."+i + " = " + Foo.prototype[i]) } alert("КОНЕЦ!") // покажет только "КОНЕЦ!"

На самом деле в нем тоже сидит невидимый суслик, в виде свойства Foo.prototype.constructor, куда записана ссылка на саму функцию:

Function Foo() {} alert(Foo.prototype.constructor === Foo) // true

Когда же может пригодиться свойство Foo.prototype? Тогда, когда Foo используется в качестве конструктора, то есть с оператором new. Конструктор создает объекты, все это знают. В JavaScript это тоже так, но логика создания слегка запутанная. Вот перед нами простой с виду код:

Var Foo = function() {} var a = new Foo; alert(a)

Любой пыхарь с уверенностью скажет "Мы создали объект а, являющийся экземпляром класса Foo". На самом деле в 7 символах "new Foo " заключена следующая магия:

  1. Мы создаем пустой объект (как если бы написали a = {} )
  2. Прототипом этого объекта назначается то, что сидит в Foo.prototype
  3. Этот объект привязывается к this в теле Foo
  4. Исполняется функция Foo
  5. Оператор new возвращает созданный объект, если Foo не вернула что-либо другое.

"Прототип" из пункта 2 - это такой объект, где будут искаться свойства созданного объекта a , которые он сам в явном виде не содержит. Код ниже иллюстрирует все это более развернуто:

Var Foo = function() { alert("я - фу!") this.prop = "lol" } // добавляем свойство к Foo.prototype Foo.prototype.bar = "trololo" var a = new Foo // исполняется Foo, видим алерт "я - фу" // в переменную a записывается созданный объект // когда Foo исполнялась, this указывало на него alert(a.prop) // например, через this-ссылку мы добавили свойство prop alert(a.bar) // а свойство bar берется из прототипа

ОК, вроде разобрались, что такое "прототип объекта", откуда он берется и зачем нужен. А как его посмотреть? В идеальном мире мы могли бы обратиться к obj.prototype и получить прототип объекта. Но увы, как мы видели выше, свойство с таким названием используется иначе - хранит то, что функция-конструктор сделает прототипом объекта. Напрашивается вывод, что можно получить прототип через .prototype конструктора. Попробуем:

Var Foo = function() {} Foo.prototype.prop = "ololo" var a = new Foo() alert(a.prop); // берем из прототипа неявно alert(a.constructor.prototype.prop); // а теперь - явно!

Вроде бы работает. Но что, если мы пытались изобразить наследование, расширив Foo другим "классом"?

Function Foo() {} function Bar() { this.prop = "ololo" } Foo.prototype = new Bar // типа наследуемся var a = new Foo alert(a.prop) // работает alert(a.constructor.prototype.prop) // undefined - ой:(// а кстати, что у нас в a.constructor? alert(a.constructor) // Bar!

Самое время задуматься, куда, собственно, указывает a.constructor. А, собственно, никуда не указывает, потому что у a нету такого свойства, оно берется из цепочки прототипов. В примере выше "прототип a" - это экземпляр Bar (потому что в Foo.prototype результат выполнения new Bar). У экземпляра Bar тоже нету свойства constructor. Зато оно есть у прототипа экземпляра Bar - потому что Bar.prototype (прототип экземпляра Bar) имеет свойство.constructor, указывающее на Bar ("свойство-суслик", о котором я писал в самом начале).

Если подумать, факап в этом примере случился из-за того, что мы "расширили" "класс" "экземпляром" (да, все - в кавычках!). Логичнее "расширять" "класс" "классом", но сути это не меняет - на obj.constructor.prototype в поисках прототипа мы полагаться не можем. Потому что obj.constructor - это не "функция, создавшая obj", а в лучшем случае - "функция, создавшая прототип obj" (так сформулировано в ). В лучшем случае - потому что, вообще-то, там может быть что угодно:

// "Класс", создающий компанию с ключевыми сотрудниками function Company (team) { for (var profession in team) { this = team } } var AvtoVAZ = new Company({ president:"Игорь Комаров", constructor:"Сергей Кудрюк " // главный конструктор АвтоВАЗа }) alert(AvtoVAZ.constructor) // упаси Бог пытаться создать новую компанию так: // var KAMAZ = new AvtoVAZ.constructor()

В общем, догадаться самостоятельно не получается, надо лезть в доки, маны и прочую матчасть. Там мы обнаруживаем совершенно курьезную ситуацию: JavaScript, прототипно-ориентированный язык, обзавелся нормальным способом получения прототипа только на 14-м году своей жизни, в версии 1.8.1! Этот способ называется Object.getPrototypeOf() и не поддерживается IE младше 9.

Function Foo() {} function Bar() { this.prop = "boo" } var b = new Bar Foo.prototype = b var a = new Foo // получаем прототип var aproto = Object.getPrototypeOf(a) alert(aproto.prop) // boo из экземпляра Bar // меняем в прототипе aproto.prop = "woo" alert(a.prop) // woo - "меняется" и в экземпляре // меняем в прототипе неявно b.prop = "zoo" alert(a.prop) // zoo - работает! // потому что Foo.prototype, aproto и b - все указывают на один и тот же объект

До появления этой штуки у разработчиков было только свойство.__proto__, которое работает только в Mozilla-образных браузерах.

Function Foo() {} var proto = {prop:"woo"} Foo.prototype = proto var a = new Foo alert(a.__proto__.prop) // свойство есть в прототипе proto.prop = "zoo" alert(a.__proto__.prop) // поменяли прототип, отразилось на экземпляре a.__proto__.prop = "boo" alert(proto.prop) // и в обратную сторону работает

Настало время для типа-саммари.

Что такое "прототип объекта obj"?
Это объект, к которому JS обращается за свойствами, которых нету у самого obj.

Что такое obj.prototype?
Если obj - это функция, то obj.prototype - то, что станет прототипом объекта при вызове new obj().


Что такое obj.constructor?
Если очень повезет - ссылка на функцию, создавшую obj, или прототип obj. А так вообще - что угодно:)

Что такое obj.__proto__?
Это прототип объекта obj, если у вас мозилла

Что такое Object.getPrototypeOf(obj)
Это способ получить ссылку на прототип объекта obj, который станет кроссбраузерным после смерти IE8 (ну FF до 3.5)

Зачем мне все это знать? о_0
Если создание сайтов - ваша работа, то... вам это все знать нафиг не нужно:) Если только для общей образованности, ну и чтоб голову поломать на досуге.

Function Person(first, last, age, eye) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eye; }

Считается хорошей практикой программирования, чтобы название функции конструкторов начиналось с большой буквы.

Объектные типы (Шаблоны) (Классы)

Примеры из предыдущих глав значительно ограничены. В них создается только одиночные объекты.

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

Для создания "объектного типа" и используется функция конструктора объекта .

В приведенном в начале этой главы примере функция Person() является функцией конструктора объекта.

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

Var myFather = new Person("John", "Doe", 50, "blue"); var myMother = new Person("Sally", "Rally", 48, "green");

Ключевое слово this

В JavaScript ключевое слово this обозначает объект, которому "принадлежит" данный код.

Значением ключевого слова this , когда оно используется в объекте, является сам объект.

В функции конструктора у ключевого слова this нет значения. Это "подстановка" для нового объекта. Когда будет создан новый объект, тогда значением ключевого слова this и станет этот новый объект.

Обратите внимание, что this это не переменная, а ключевое слово. Вы не можете изменять его значение.

Добавление свойства к объекту

Добавить новое свойство к существующему объекту очень просто:

MyFather.nationality = "English";

Свойство будет добавлено к объекту myFather, но не к объекту myMother. (Или какому-либо другому объекту типа person).

Добавление метода к объекту

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

MyFather.name = function () { return this.firstName + " " + this.lastName; };

Метод будет добавлен к объекту myFather, но не к объекту myMother. (Или какому-либо другому объекту типа person).

Добавление свойства к конструктору объекта

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

Чтобы добавить новое свойство к конструктору, вы должны добавить его в функцию конструктора:

Function Person(first, last, age, eyecolor) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eyecolor; this.nationality = "English"; }

При этом свойствам объекта можно устанавливать значения по умолчанию.

Добавление метода к конструктору объекта

Функция конструктора также может определять методы:

Function Person(first, last, age, eyecolor) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eyecolor; this.name = function() {return this.firstName + " " + this.lastName;}; }

Нельзя добавлять новые методы к конструктору объекта тем же способом, как это делается в случае с существующим объектом. Добавление методов к объекту должно происходить внутри функции конструктора:

Function Person(firstName, lastName, age, eyeColor) { this.firstName = firstName; this.lastName = lastName; this.age = age; this.eyeColor = eyeColor; this.changeName = function (name) { this.lastName = name; }; }

Функция changeName() присваивает значение параметра name свойству lastName объекта person:

MyMother.changeName("Doe");

JavaScript знает, о каком объекте идет речь, "подставляя" в ключевое слово this объект myMother .

Встроенные конструкторы JavaScript

В JavaScript есть встроенные конструкторы для собственных объектов:

Var x1 = new Object(); // Новый объект Object var x2 = new String(); // Новый объект String var x3 = new Number(); // Новый объект Number var x4 = new Boolean(); // Новый объект Boolean var x5 = new Array(); // Новый объект Array var x6 = new RegExp(); // Новый объект RegExp var x7 = new Function(); // Новый объект Function var x8 = new Date(); // Новый объект Date

В этом списке нет объекта Math(), так как это глобальный объект. Ключевое слово new нельзя использовать с объектом Math.

А вы знали?

Как видно из приведенного выше кода, в JavaScript есть объектные версии примитивных типов данных String, Number и Boolean. Однако нет никаких причин создавать для этих типов комплексные объекты. Примитивные значения работают быстрее.

Таким образом:

  • используйте объектные литералы { } вместо new Object().
  • используйте строковые литералы "" вместо new String().
  • используйте числовые литералы 12345 вместо new Number().
  • используйте логические литералы true / false вместо new Boolean().
  • используйте литералы-массивы вместо new Array().
  • используйте литералы-шаблоны /()/ вместо new RexExp().
  • используйте выражения функций () {} вместо new Function().
var x1 = {}; // новый объект Object var x2 = ""; // новая примитивная строка var x3 = 0; // новое примитивное число var x4 = false; // новое примитивное логическое значение var x5 = ; // новый объект Array var x6 = /()/ // новый объект RegExp var x7 = function(){}; // новый объект Function

контент переехал из сниппетов в статьи

При помощи оператора new можно создать объект (объект Function).
За оператором new необходимо указать имя функции-конструктора; данная функция-конструктор выполняет инициализацию свойств объекта.
В функцию-конструктор передается ключевое слово this , которое ссылается на только что созданный объект.

Существуют встроенные конструкторы javascript, например: Array() , Date() , RegExp() . Стоит отметить: конструктор Object() создает пустой объект, что равнозначно использованию литерала объекта {} .

Прототип – это значение свойства prototype функции конструктора. Каждая функция имеет свойство prototype , данное свойство ссылается на предопределенный объект-прототип. Этот объект работает только в том случае, если функция используется как конструктор, то есть совместно с оператором new.

Каждый объект имеет свойство constructor ; это свойство ссылается на функцию-конструктор, которая, как говорилось выше, выполняет инициализацию свойств объекта.

Как видите, свойство r_method всегда ссылается на неизменяемую (в отличие от свойств, которые уникальны для каждого объекта) функцию. Поэтому рациональнее добавить ее к прототипу. Мы можем сделать простой вывод: объект-прототип подходящее место для констант и методов. Так как любой объект наследует свойства своего прототипа, то наша функция (r_method) автоматически добавится всем объектам, инициализированным конструктором (example_constr).

Классы javascript

Javascript не поддерживает классы как таковые. Однако вы можете создавать псевдоклассы, используя функции-конструкторы и прототипы объектов. Конструктор – это класс.

Назначение конструктора - создать новый объект, установить и возвратить его в качестве значения конструктора.

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

Пример создания объекта,
определение конструктора,
и установка свойства для прототипа:

// объект var opa = {}; var opa_ = {x:0, y:"yes"} var D = new Date(); // текущая дата /* Свойство constructor */ document.write(D.constructor); // function Date() { } D.constructor == Date // true // определяем конструктор: function example_constr(r,t) { this.ad = r; this.ak = t; // метод, но лучше определить как св-во прототипа /* this.r_method = function () { this.qu = this.ad - this.ak; }*/ // метод, но внутри метода не используем свойства объекта this.a_method = function (x,y) { alert(x+y); } } // объявляем метод (r_method) в прототипе // это предпочтительнее, чем использовать r_method в ф-и конструкторе // по причине того, что ф-я r_method не имеет уникальных св-в, в отличие // от вышеприведенных свойств (ad,ak) example_constr.prototype.r_method = function () { this.qu = this.ad - this.ak; } // вызываем конструктор и создаем объект example_constr (krot) var krot = new example_constr(14,15); // что равнозначно krot = {ad:14,ak:15} krot.r_method(); // выведет: //alert(krot.qu); // -1 //krot.a_method(11,11); // выведет: // 22

Дополнение:
Чтобы создать собственный конструктор, достаточно описать функцию, в которой ключевое слово this будет ссылаться на объекты (которые создаются посредством функции конструктора). Смотрите выше на примере example_constr .

console.dir

js

console.dir(obj); // выведет все свойства объекта в консоли

Объекты в javascript позволяют воссоздать концепцию объектно-ориентированного программирования

Для того чтобы создавать объекты одного типа используют функции-конструкторы. Отличие конструктора от обычной функции в том, что конструктор вызывается через специальный оператор new .

При использовании new в функции-конструкторе return может вернуть только объект, причем этот объект заменит возвращаемый по умолчанию объект this .

Приватные переменные и функции

У функции-конструктора могут быть как приватные данные (такие данные внешний код может получить, но изменить не может), так и публичные.

javascript

// определяем конструктор: function example_constr(r,t,name) { // this = {} создается автоматически this.ad = r; this.ak = t; this.a_method = function (x,y) { alert(x+y); } // функция-конструктор и без всякого return // возвращает объект this // приватная переменная (то есть из внешнего кода ее можно получить, // но нельзя изменить): this.getName = function(){ return name; } // также можно использовать обычные переменные, // которые будут доступны в лишь пределах функции-конструктора: var page, password; var ogo = function(){ //................ }; } var newObj = new example_constr(1,2,"Вася"); console.dir(newObj); console.log(newObj.getName()); //

знать

  • ОБЪЕКТЫ javascript работают только со строковыми свойствами, то есть, если свойство не указано как строка, то оно все равно станет строкой.

Последнее обновление: 27.03.2018

Кроме создания новых объектов JavaScript предоставляет нам возможность создавать новые типы объектов с помощью конструкторов . Так, одним из способов создания объекта является применение конструктора типа Object:

Var tom = new Object();

После создания переменной tom она будет вести себя как объект типа Object.

Конструктор позволяет определить новый тип объекта. Тип представляет собой абстрактное описание или шаблон объекта. Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке - наличие двух рук, двух ног, головы, пищеварительной, нервной системы и т.д. Есть некоторый шаблон - этот шаблон можно назвать типом. Реально же существующий человек является объектом этого типа.

Определение типа может состоять из функции конструктора, методов и свойств.

Для начала определим конструктор:

Function User(pName, pAge) { this.name = pName; this.age = pAge; this.displayInfo = function(){ document.write("Имя: " + this.name + "; возраст: " + this.age + "
"); }; }

Конструктор - это обычная функция за тем исключением, что в ней мы можем установить свойства и методы. Для установки свойств и методов используется ключевое слово this :

This.name = pName;

В данном случае устанавливаются два свойства name и age и один метод displayInfo.

Как правило, названия конструкторы в отличие от названий обычных функций начинаются с большой буквы.

После этого в программе мы можем определить объект типа User и использовать его свойства и методы:

Var tom = new User("Том", 26); console.log(tom.name); // Том tom.displayInfo();

Чтобы вызвать конструктор, то есть создать объект типа User, надо использовать ключевое слово new .

Подобным образом мы можем определить и другие типы и использовать их вместе:

// конструктор типа Car function Car(mName, mYear){ this.name = mName; this.year = mYear; this.getCarInfo = function(){ document.write("Модель: " + this.name + " Год выпуска: " + this.year + "
"); }; }; // конструктор типа User function User(pName, pAge) { this.name = pName; this.age = pAge; this.driveCar = function(car){ document.write(this.name + " ведет машину " + car.name + "
"); }; this.displayInfo = function(){ document.write("Имя: " + this.name + "; возраст: " + this.age + "
"); }; }; var tom = new User("Том", 26); tom.displayInfo(); var bently = new Car("Бентли", 2004); tom.driveCar(bently);

Оператор instanceof

Оператор instanceof позволяет проверить, с помощью какого конструктора создан объект. Если объект создан с помощью определенного конструктора, то оператор возвращает true:

Var tom = new User("Том", 26); var isUser = tom instanceof User; var isCar = tom instanceof Car; console.log(isUser); // true console.log(isCar); // false