» »

Что такое конструктор в js. JavaScript. Создание объектов. Добавление метода к объекту

05.01.2024

Всем привет. В сегодняшней статье мы разберём, что такое Объекты, конструкторы и прототипы в JavaScript . JavaScript очень отличается от других объектно-ориентированных языков программирования, как, например, C++, Java, PHP и т.д. В этих языках используются классы , на основе которых потом создаются объекты . В JavaScript же классов нет, но есть объекты . Всё кроме null, undefined, string, number, boolean в JavaScript является объектом , поэтому очень важно знать, как они работают. Что же, давайте начнём.

Объект - это набор свойств и методов . Рассмотрим пример:

Var person = {};
var person = new Object();

Здесь мы создали пустой объект. 1 и 2 случай идентичны, но первый короче и поэтому используется чаще. Давайте заполним наш объект какими-то свойствами

Var person = {
name: "Alex",
age: 27
};

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

Console.log(person.name); // выводит в консоль имя
console.log(person["name"]); // аналогично первому случаю
person.age = 30; // изменили свойство age с 27 на 30
person.gender = "male"; // добавили новое свойство gender со значением male

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

Var k = "name";
console.log(person.k); // Ошибка!
console.log(person[k]); // выведет значение

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

Console.log(person.height); // Такого свойства нет - undefined

Теперь разберём, что же такое методы.
Методы - это просто функции в объекте.

Var person = {
name: "Alex",
greet: function() {
console.log("Hello! My name is " + this.name);
}
};

В объекте person мы создали метод greet , который выводит в консоль приветствие. This в коде означает текущий объект, т.е. мы могли бы написать person.name и это также прекрасно работало бы, но что если нам нужно, например, поменять имя объекта? Тогда нам пришлось везде бы менять person на новое имя. С использованием this таких проблем нет.

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

Var Person = function(name, age) {
this.name = name;
this.age = age;
};
var human = new Person("Alex", 27);

Интепретатор JavaScript видит ключевое слово new и запускает функцию, которая создаёт пустой объект, на который ссылается this . Дальше функция просто присваивает свойствам name и age переданные значения, а затем отдаёт новый объект, на который и передаётся ссылка в переменную human. Да-да! Я не случайно написал ссылка. Дело в том, что все объекты хранятся где-то в памяти, а в переменную попадает лишь ссылка на него, но не он сам.

Var a = 5;
var b = 7;
a = b;
console.log(a, b);

В данном примере мы переменной a присваиваем значение переменной b, поэтому в консоль выведется "7 7". Теперь давайте попробуем сделать так же и с объектами

Var a = {
name: "Alex"
};

Var b = {
name: "Bob"
};

B.name = "John";
console.log(a.name);

Если вы запустите данный пример, то увидите John, т.к. переменная a и b ссылаются на один и тот же объект.

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

Var person = {
name: "Alex"
};
var object = Object.create(person);
console.log(object.name);

В данном примере мы создаём новый объект object, который наследует все свойства от его прототипа person с помощью функции create.

Теперь поговорим о том, зачем нам всё это нужно? Допустим, в вашей программе вам нужно создавать много однотипных объектов

Var person = {
name: "Alex",
age: 27,
greet: function() {

}
};

Var person2 = {
name: "John",
age: 17,
greet: function() {
console.log("My name is " + this.name);
}
};

Var person3 = {
name: "Jessica",
age: 37,
greet: function() {
console.log("My name is " + this.name);
}
};

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

Var Person = {
constructor: function(name, age) {
this.name = name;
this.age = age;
return this;
},

Greet: function() {
console.log("My name is " + this.name);
}
};

Var person, person2, person3;

Person = Object.create(Person).constructor("Alex", 27);
person2 = Object.create(Person).constructor("John", 17);
person3 = Object.create(Person).constructor("Jessica", 37);

Наш код стал короче и более производительным. Давайте теперь разберёмся, что же мы сделали. Для начала мы вынесли общий для всех объектов метод greet в прототип Person. Теперь у нас не 3 функции, а только одна, что хорошо скажется на производительности. Значения name и age у нас для всех объектов разные, поэтому мы создали метод constructor , в котором просто написали функцию, которая инициализирует новый объект и возвращает его. Дальше мы создаём новый объект при помощи Object.create() и сразу вызываем его метод constructor , куда передаём данные. Так мы можем создавать сколько угодно новых объектов, обращаться к их свойствам и вызывать их методы.

Console.log(person.name); // Alex
console.log(person2.age); // 17
console.log(person3.name); // Jessica

Person.greet(); // My name is Alex
person2.greet(); // My name is John
person3.greet(); // My name is Jessica

Класс в языке JavaScript это чисто условное понятие и под классом понимают всего лишь множество всех объектов, которые наследуют свои свойства от одного прототипа. Т.е. в нашем случае эти 3 объекта(person, person2, person3) имеют один класс, потому что они наследуют свойства от одного прототипа.

Для того, чтобы определить является ли объект прототипом другого объекта, есть метод isPrototypeOf

Person.isPrototypeOf(person); // true

Итак, сегодня вы узнали такие основные вещи, как объекты, конструкторы и прототипы . Надеюсь, вы всё поняли, но если всё-таки остались вопросы - оставляйте их в комментариях. До скорого!

Гибкость Javascript позволяет создавать объекты множеством способов. Но как это нередко случается, разнообразие таит в себе множество подводных камней. Из этой статьи Вы узнаете о том, как разглядеть и обогнуть эти опасные рифы.

Основы основ

Нелишним будет напомнить, что из себя представляют объекты в Javascript и как их можно создавать. Объект в Javascript - это всего лишь хэш-таблица ключей и значений. Если значения представляют собой базовые типы или другие объекты, их называют свойствами , если же это функции, их называют методами объекта.

Объекты, созданные пользователем, можно изменить в любой точке выполнения скрипта. Многие свойства встроенных в язык объектов также изменяемы. То есть можно просто создать пустой объект и добавлять к нему свойства и методы по мере необходимости. Проще всего это сделать с помощью литеральной нотации :
//создаем пустой объект var cat = {}; //добавляем свойство: cat.name = "Garfield"; //или метод: cat.getName = function() { return cat.name; };
Другим способом создания объекта является использование функций-конструкторов:
// литеральная нотация: var cat = {name: "Garfield"}; // конструктор-функция: var cat = new Object(); cat.name = "Garfield";
Очевидно, что литеральная нотация короче конструктора. Есть и философская причина предпочитать литеральную нотацию конструкторам: она подчеркивает, что объект - это всего лишь изменяемый хэш, а не нечто, создаваемое по шаблону, заданному классом.

Кроме того, использование конструктора Object вынуждает интерпретатор проверять, не переопределена ли эта функция в локальном контексте.

Подводный камень конструктора Object

Причин использовать конструктор Object нет. Но все мы знаем, что иногда приходится использовать какой-то старый код, и в этом случае полезно знать об одной особенности этого конструктора. Он принимает аргумент, и в зависимости от его типа может поручить создание объекта другому встроенному в язык конструктору; в итоге мы получим не тот объект, что ожидали:
//пустой объект var o = new Object(); o.constructor === Object; // true var o = new Object(1); o.constructor === Number; //true var o = new Object("string"); o.constructor === String; //true //мы не предполагали, что созданный объект будет иметь этот метод: typeof o.substring; // "function"
Такое поведение конструктора Object может привести к неожиданным результатам, если мы передаем в него значение, неизвестное на этапе выполнения.

Мораль очевидна: не используйте конструктор Object .

Собственные конструкторы

Мы можем определять собственные конструкторы. Использование их выглядит так:
var cat = new Cat("Garfield"); cat.say(); // "I am Garfield"
Синтаксис похож на конструктор Java, но в Javascript конструктор является обычной функцией и поэтому определяется так:
var Cat = function(name) { this.name = name; this.say = function() { return "I am" + this.name; } }
При вызове этого конструктора с оператором new внутри функции происходит следующее:
  • создается пустой объект, на который указывает переменная this ; этот объект наследует прототип функции;
  • к объекту, хранимому в this , добавляются свойства и методы;
  • объект, хранимый в this , неявно возвращается в конце функции (т.к. мы ничего не возвращали явно).
Простоты ради в примере метод say() добавлен к объекту this . Это не очень хорошо, так как каждый раз при вызове new Person() в памяти будет создаваться новая функция. Так как метод say() одинаков для всех объектов, создаваемых с помощью этого конструктора, лучше добавить его к прототипу Cat:
Cat.prototype.say = function() { return "I am " + this.name; };
Кроме того, не совсем корректно утверждать, что объект this , неявно создаваемый в конструкторе, пуст: он наследуется от прототипа Cat , однако рассмотрение прототипов выходит за рамки этой статьи.

Что возвращает конструктор

При использовании оператора new , конструктор всегда возвращает объект. По умолчанию, это объект, на который ссылается this . Конструктор возвращает this неявно, однако мы можем явно вернуть любой другой объект, например:
var Cat = function() { this.name = "I am Garfield"; var that = {}; that.name = "I am Cat-woman"; return that; }; var cat = new Cat(); cat.name // "I am Cat-woman"
Таким образом, мы можем вернуть из конструктора любое значение, но лишь при условии, что это объект. Если мы попытаемся вернуть, скажем, строку или false , это не приведет к ошибке, но оператор возврата будет проигнорирован, и конструктор вернет this .

Коварный new

Конструкторы - это всего лишь функции, вызываемые с оператором new . Что случится, если забыть этот оператор? Интерпретатор не выдаст предупреждений, но это приведет к логическим ошибкам. Переменная this будет указывать не на объект, унаследованный от прототипа конструктора, а на глобальный объект (window в случае браузера):
function Cat() { this.name = "Garfield"; } // новый объект var cat = new Cat(); typeof cat; // "object" cat.name; // "Garfield" //забываем new: var cat = Cat(); typeof cat; // "undefined" window.name; // "Garfield"
В строгом режиме стандарта ECMAScript 5 this в этом случае не будет указывать на глобальный объект. Посмотрим, как можно избежать этой ошибки, если ECMAScript 5 недоступен.
Соглашения об именовании функций
Самым простым способом является неукоснительное соблюдение соглашений об именовании функций: начинаем обычные функции со строчной буквы (myFunction()), а функции-конструкторы - с заглавной (MyConstruction()). К сожалению, такой способ почти ни от чего не спасает.
Явный возврат объекта
Конструкторы могут возвращать любые объекты. Программисты могут воспользоваться этим:
function Cat() { var that = {}; that.name = "Garfield"; return that; }
Имя переменной that выбрано произвольно, это не часть спецификации. С тем же успехом мы можем назвать возвращаемый объект me или self или как Вам заблагорассудится.

Для простых объектов, вроде создаваемого в примере, мы можем вообще обойтись без дополнительных переменных, используя литеральную нотацию:
function Cat() { return { name: "Garfield" }; }
Такой конструктор будет всегда возвращать объект, независимо от того, как его вызывать:
var first = new Cat(), second = Cat(); first.name; // "Garfield" second.name; // "Garfield"
У этого способа есть серьезный недостаток: объект не наследует прототип конструктора, то есть методы и свойства, добавленные непосредственно к Cat , будут недоступны создаваемым с его помощью объектам.

Самовызывающий конструктор
Для решения этой проблемы достаточно проверить, является ли this в теле конструктора экземляром этого самого конструктора, и если нет, вызывать себя снова, но на этот раз с оператором new . Звучит страшно, но на деле просто:
function Cat() { if (!(this instanceof Cat)) { return new Cat(); } this.name = "Garfield"; } Cat.prototype.meow = "Meow!"; var first = new Cat(), second = Cat(); first.name; // "Garfield" second.name; // "Garfield" first.meow; // "Meow!" second.meow; // "Meow!"
Если наш конструктор будет в дальнейшем переименован, придется править его тело. Избежать этого можно проверкой arguments.callee вместо имени конструктора:
if (!(this instanceof arguments.callee)) { return new arguments.callee(); }
Здесь мы воспользовались тем, что внутри каждой функции создается объект arguments , содержащий все параметры, передаваемые функции в момент вызова. Свойство callee этого объекта указывает на вызываемую функцию. Но и здесь нужно проявить осторожность: строгий режим ECMAScript 5 вызывает исключение TypeError при обращении к этому свойству, поэтому стоит заранее сделать выбор между удобством рефакторинга и светлым завтра.

Вместо заключения

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

The constructor method is a special method for creating and initializing an object created within a class .

The source for this interactive example is stored in a GitHub repository. If you"d like to contribute to the interactive examples project, please clone https://github.com/mdn/interactive-examples and send us a pull request.

Syntax

constructor([arguments ]) { ... }

Description

There can be only one special method with the name "constructor" in a class. Having more than one occurrence of a constructor method in a class will throw a SyntaxError error.

Class Square extends Polygon { constructor(length) { // Here, it calls the parent class" constructor with lengths // provided for the Polygon"s width and height super(length, length); // Note: In derived classes, super() must be called before you // can use "this". Leaving this out will cause a reference error. this.name = "Square"; } get area() { return this.height * this.width; } set area(value) { this.area = value; } }

Another example

Take a look at this code snippet

Class Polygon { constructor() { this.name = "Polygon"; } } class Square extends Polygon { constructor() { super(); } } class Rectangle {} Object.setPrototypeOf(Square.prototype, Rectangle.prototype); console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true let newInstance = new Square(); console.log(newInstance.name); //Polygon

Here the prototype of Square class is changed but still the constructor of the previous base class Polygon is called when a new instance of a square is being created.

Default constructors

As stated, if you do not specify a constructor method a default constructor is used. For base classes the default constructor is:

Constructor() {}

For derived classes, the default constructor is:

Constructor(...args) { super(...args); }

Specifications

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
Standard Initial definition.
ECMAScript Latest Draft (ECMA-262)
The definition of "Constructor Method" in that specification.
Draft

Browser compatibility

The compatibility table on this page is generated from structured data. If you"d like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.

Update compatibility data on GitHub

Desktop Mobile Server
Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internet Node.js
constructor Chrome Full support 49

Notes

Full support 49

Notes

Notes
Edge Full support 13 Firefox Full support 45 IE No support No Opera Full support 36 Safari Full support 9 WebView Android Full support 49

Notes

Full support 49

Notes

Notes From Chrome 42 to 48 strict mode is required. Non-strict mode support can be enabled using the flag "Enable Experimental JavaScript".
Chrome Android Full support Yes Firefox Android Full support 45 Opera Android ? Safari iOS Full support 9 Samsung Internet Android Full support Yes nodejs Full support 6.0.0 Full support 6.0.0 Full support 4.0.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

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

  • Оператор new
  • Литеральная нотация
  • Конструкторы объектов
  • Ассоциативные массивы

Используем оператор new

Это, наверное, самый легкий способ создания объекта. Вы просто создаете имя объекта и приравниваете его к новому объекту Javascript.

//Создаем наш объект var MyObject = new Object(); //Переменные MyObject.id = 5; //Число MyObject.name = "Sample"; //Строка //Функции MyObject.getName = function() { return this.name; }

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

//Используем наш объект alert(MyObject.getName());

Литеральная нотация

Литеральная нотация является несколько непривычным способом определения новых объектов, но достаточно легким для понимания. Литеральная нотация работает с версии Javascript 1.3.

//Создаем наш объект с использованием литеральной нотации MyObject = { id: 1, name: "Sample", boolval: true, getName: function() { return this.name; } }

Как видите, это довольно просто.

Объект = { идентификатор: значение, ... }

И пример использования:

Alert(MyObject.getName());

Конструкторы объектов

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

Function MyObject(id, name) { }

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

Var MyFirstObjectInstance = new MyObject(5,"Sample"); var MySecondObjectInstace = new MyObject(12,"Othe Sample");

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

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

Function MyObject(id, name) { //Значения переданные пользователем this._id = id; this._name = name; //Значение по умолчанию this.defaultvalue = "MyDefaultValue"; }

Аналогичным образом мы можем создавать и функции.

Function MyObject(id,name) { this._id = id; this._name = name; this.defaultvalue = "MyDefaultValue"; //Получение текущего значения this.getDefaultValue = function() { return this.defaultvalue; } //Установка нового значения this.setDefaultValue = function(newvalue) { this.defaultvalue = newvalue; } //Произвольная функция this.sum = function(a, b) { return (a+b); } }

Ассоциативные массивы

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

Var MyObject = new Number(); MyObject["id"] = 5; MyObject["name"] = "SampleName";

Для обхода таких объектов можно использовать такой цикл:

For (MyElement in MyObject) { //Код обхода //В MyElement - идентификатор записи //В MyObject - содержание записи }

По материалу подготовлена небольшая схема.

Вы можете её посмотреть в форматах.