РобÑекÑно-оÑиенÑиÑованном пÑогÑаммиÑовании клаÑÑ â ÑÑо ÑаÑÑиÑÑемÑй Ñаблон кода Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ð±ÑекÑов, коÑоÑÑй ÑÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð² Ð½Ð¸Ñ Ð½Ð°ÑалÑнÑе знаÑÐµÐ½Ð¸Ñ (ÑвойÑÑва) и ÑеализаÑÐ¸Ñ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ (меÑодÑ).
Ðа пÑакÑике нам ÑаÑÑо надо ÑоздаваÑÑ Ð¼Ð½Ð¾Ð³Ð¾ обÑекÑов одного вида, напÑÐ¸Ð¼ÐµÑ Ð¿Ð¾Ð»ÑзоваÑелей, ÑоваÑÑ Ð¸Ð»Ð¸ ÑÑо-Ñо еÑÑ.
Ðак Ð¼Ñ Ñже знаем из Ð³Ð»Ð°Ð²Ñ ÐонÑÑÑÑкÑоÑ, опеÑаÑÐ¾Ñ "new", Ñ ÑÑим Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð¼Ð¾ÑÑ new function.
Ðо в ÑовÑеменном JavaScript еÑÑÑ Ð¸ более пÑодвинÑÑÐ°Ñ ÐºÐ¾Ð½ÑÑÑÑкÑÐ¸Ñ Â«class», коÑоÑÐ°Ñ Ð¿ÑедоÑÑавлÑÐµÑ Ð½Ð¾Ð²Ñе возможноÑÑи, полезнÑе Ð´Ð»Ñ Ð¾Ð±ÑекÑно-оÑиенÑиÑованного пÑогÑаммиÑованиÑ.
СинÑакÑÐ¸Ñ Â«class»
ÐазовÑй ÑинÑакÑÐ¸Ñ Ð²ÑглÑÐ´Ð¸Ñ Ñак:
class MyClass {
// меÑÐ¾Ð´Ñ ÐºÐ»Ð°ÑÑа
constructor() { ... }
method1() { ... }
method2() { ... }
method3() { ... }
...
}
ÐаÑем иÑполÑзÑйÑе вÑзов new MyClass() Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ обÑекÑа Ñо вÑеми пеÑеÑиÑленнÑми меÑодами.
ÐÑи ÑÑом авÑомаÑиÑеÑки вÑзÑваеÑÑÑ Ð¼ÐµÑод constructor(), в нÑм Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иниÑиализиÑоваÑÑ Ð¾Ð±ÑекÑ.
ÐапÑимеÑ:
class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
// ÐÑполÑзование:
let user = new User("Ðван");
user.sayHi();
Ðогда вÑзÑваеÑÑÑ new User("Ðван"):
- СоздаÑÑÑÑ Ð½Ð¾Ð²Ñй обÑекÑ.
constructorзапÑÑкаеÑÑÑ Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñм аÑгÑменÑом и ÑÐ¾Ñ ÑанÑÐµÑ ÐµÐ³Ð¾ вthis.name.
â¦ÐаÑем можно вÑзÑваÑÑ Ð½Ð° обÑекÑе меÑодÑ, Ñакие как user.sayHi().
ЧаÑÑÐ°Ñ Ð¾Ñибка наÑинаÑÑÐ¸Ñ ÑазÑабоÑÑиков â ÑÑавиÑÑ Ð·Ð°Ð¿ÑÑÑÑ Ð¼ÐµÐ¶Ð´Ñ Ð¼ÐµÑодами клаÑÑа, ÑÑо пÑÐ¸Ð²Ð¾Ð´Ð¸Ñ Ðº ÑинÑакÑиÑеÑкой оÑибке.
СинÑакÑÐ¸Ñ ÐºÐ»Ð°ÑÑов оÑлиÑаеÑÑÑ Ð¾Ñ Ð»Ð¸ÑеÑалов обÑекÑов, не пÑÑайÑе Ð¸Ñ . ÐнÑÑÑи клаÑÑов запÑÑÑе не ÑÑебÑÑÑÑÑ.
ЧÑо Ñакое клаÑÑ?
ÐÑак, ÑÑо же Ñакое class? ÐÑо не полноÑÑÑÑ Ð½Ð¾Ð²Ð°Ñ ÑзÑÐºÐ¾Ð²Ð°Ñ ÑÑÑноÑÑÑ, как Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÐºÐ°Ð·Ð°ÑÑÑÑ Ð½Ð° пеÑвÑй взглÑд.
ÐавайÑе Ñазвеем вÑÑ Ð¼Ð°Ð³Ð¸Ñ Ð¸ поÑмоÑÑим, ÑÑо Ñакое клаÑÑ Ð½Ð° Ñамом деле. ÐÑо Ð¿Ð¾Ð¼Ð¾Ð¶ÐµÑ Ð² понимании Ð¼Ð½Ð¾Ð³Ð¸Ñ ÑложнÑÑ Ð°ÑпекÑов.
Ð JavaScript клаÑÑ â ÑÑо ÑазновидноÑÑÑ ÑÑнкÑии.
ÐзглÑниÑе:
class User {
constructor(name) { this.name = name; }
sayHi() { alert(this.name); }
}
// доказаÑелÑÑÑво: User - ÑÑо ÑÑнкÑиÑ
alert(typeof User); // function
ÐÐ¾Ñ ÑÑо на Ñамом деле Ð´ÐµÐ»Ð°ÐµÑ ÐºÐ¾Ð½ÑÑÑÑкÑÐ¸Ñ class User {...}:
- СоздаÑÑ ÑÑнкÑÐ¸Ñ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼
User, коÑоÑÐ°Ñ ÑÑановиÑÑÑ ÑезÑлÑÑаÑом обÑÑÐ²Ð»ÐµÐ½Ð¸Ñ ÐºÐ»Ð°ÑÑа. Ðод ÑÑнкÑии беÑÑÑÑÑ Ð¸Ð· меÑодаconstructor(она бÑÐ´ÐµÑ Ð¿ÑÑÑой, еÑли Ñакого меÑода неÑ). - СоÑ
ÑанÑÐµÑ Ð²Ñе меÑодÑ, Ñакие как
sayHi, вUser.prototype.
ÐÑи вÑзове меÑода обÑекÑа new User он бÑÐ´ÐµÑ Ð²Ð·ÑÑ Ð¸Ð· пÑоÑоÑипа, как опиÑано в главе F.prototype. Таким обÑазом, обÑекÑÑ new User имеÑÑ Ð´Ð¾ÑÑÑп к меÑодам клаÑÑа.
Ðа каÑÑинке показан ÑезÑлÑÑÐ°Ñ Ð¾Ð±ÑÑÐ²Ð»ÐµÐ½Ð¸Ñ class User:
Ðожно пÑовеÑиÑÑ Ð²ÑÑеÑказанное и пÑи помоÑи кода:
class User {
constructor(name) { this.name = name; }
sayHi() { alert(this.name); }
}
// клаÑÑ - ÑÑо ÑÑнкÑиÑ
alert(typeof User); // function
// ...или, еÑли ÑоÑнее, ÑÑо меÑод constructor
alert(User === User.prototype.constructor); // true
// ÐеÑÐ¾Ð´Ñ Ð½Ð°Ñ
одÑÑÑÑ Ð² User.prototype, напÑимеÑ:
alert(User.prototype.sayHi); // sayHi() { alert(this.name); }
// в пÑоÑоÑипе Ñовно 2 меÑода
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
Ðе пÑоÑÑо ÑинÑакÑиÑеÑкий ÑÐ°Ñ Ð°Ñ
Ðногда говоÑÑÑ, ÑÑо class â ÑÑо пÑоÑÑо «ÑинÑакÑиÑеÑкий ÑаÑ
аÑ» в JavaScript (ÑинÑакÑÐ¸Ñ Ð´Ð»Ñ ÑлÑÑÑÐµÐ½Ð¸Ñ ÑиÑаемоÑÑи кода, но не делаÑÑий ниÑего пÑинÑипиалÑно нового), поÑÐ¾Ð¼Ñ ÑÑо Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ ÑделаÑÑ Ð²ÑÑ Ñо же Ñамое без конÑÑÑÑкÑии class:
// пеÑепиÑем клаÑÑ User на ÑиÑÑÑÑ
ÑÑнкÑиÑÑ
// 1. СоздаÑм ÑÑнкÑÐ¸Ñ constructor
function User(name) {
this.name = name;
}
// каждÑй пÑоÑоÑип ÑÑнкÑии Ð¸Ð¼ÐµÐµÑ ÑвойÑÑво constructor по ÑмолÑаниÑ,
// поÑÑÐ¾Ð¼Ñ Ð½Ð°Ð¼ Ð½ÐµÑ Ð½ÐµÐ¾Ð±Ñ
одимоÑÑи его ÑоздаваÑÑ
// 2. ÐобавлÑем меÑод в пÑоÑоÑип
User.prototype.sayHi = function() {
alert(this.name);
};
// ÐÑполÑзование:
let user = new User("Ðван");
user.sayHi();
РезÑлÑÑÐ°Ñ ÑÑого кода оÑÐµÐ½Ñ Ð¿Ð¾Ñ
ож. ÐоÑÑомÑ, дейÑÑвиÑелÑно, еÑÑÑ Ð¿ÑиÑинÑ, по коÑоÑÑм class можно ÑÑиÑаÑÑ ÑинÑакÑиÑеÑким ÑаÑ
аÑом Ð´Ð»Ñ Ð¾Ð¿ÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½ÑÑÑÑкÑоÑа вмеÑÑе Ñ Ð¼ÐµÑодами пÑоÑоÑипа.
Ðднако еÑÑÑ Ð²Ð°Ð¶Ð½Ñе оÑлиÑиÑ:
-
Ðо-пеÑвÑÑ , ÑÑнкÑиÑ, ÑÐ¾Ð·Ð´Ð°Ð½Ð½Ð°Ñ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
class, помеÑена ÑпеÑиалÑнÑм внÑÑÑенним ÑвойÑÑвом[[IsClassConstructor]]: true. ÐоÑÑÐ¾Ð¼Ñ ÑÑо не ÑовÑем Ñо же Ñамое, ÑÑо ÑоздаваÑÑ ÐµÑ Ð²ÑÑÑнÑÑ.РоÑлиÑие Ð¾Ñ Ð¾Ð±ÑÑнÑÑ ÑÑнкÑий, конÑÑÑÑкÑÐ¾Ñ ÐºÐ»Ð°ÑÑа не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²Ñзван без
new:class User { constructor() {} } alert(typeof User); // function User(); // Error: Class constructor User cannot be invoked without 'new'ÐÑоме Ñого, ÑÑÑоковое пÑедÑÑавление конÑÑÑÑкÑоÑа клаÑÑа в болÑÑинÑÑве движков JavaScript наÑинаеÑÑÑ Ñ Â«class â¦Â»
class User { constructor() {} } alert(User); // class User { ... } -
ÐеÑÐ¾Ð´Ñ ÐºÐ»Ð°ÑÑа ÑвлÑÑÑÑÑ Ð½ÐµÐ¿ÐµÑеÑиÑлимÑми. ÐпÑеделение клаÑÑа ÑÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ñлаг
enumerableвfalseÐ´Ð»Ñ Ð²ÑÐµÑ Ð¼ÐµÑодов в"prototype".Ð ÑÑо Ñ Ð¾ÑоÑо, Ñак как еÑли Ð¼Ñ Ð¿ÑÐ¾Ñ Ð¾Ð´Ð¸Ð¼ÑÑ Ñиклом
for..inпо обÑекÑÑ, Ñо обÑÑно Ð¼Ñ Ð½Ðµ Ñ Ð¾Ñим пÑи ÑÑом полÑÑаÑÑ Ð¼ÐµÑÐ¾Ð´Ñ ÐºÐ»Ð°ÑÑа. -
ÐлаÑÑÑ Ð²Ñегда иÑполÑзÑÑÑ
use strict. ÐеÑÑ ÐºÐ¾Ð´ внÑÑÑи клаÑÑа авÑомаÑиÑеÑки Ð½Ð°Ñ Ð¾Ð´Ð¸ÑÑÑ Ð² ÑÑÑогом Ñежиме.
Также в дополнение к оÑновной, опиÑанной вÑÑе, ÑÑнкÑионалÑноÑÑи, ÑинÑакÑÐ¸Ñ class даÑÑ ÑÑд дÑÑгиÑ
инÑеÑеÑнÑÑ
возможноÑÑей, Ñ ÐºÐ¾ÑоÑÑми Ð¼Ñ Ð¿Ð¾Ð·Ð½Ð°ÐºÐ¾Ð¼Ð¸Ð¼ÑÑ ÑÑÑÑ Ð¿Ð¾Ð·Ð¶Ðµ.
Class Expression
Ðак и ÑÑнкÑии, клаÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ опÑеделÑÑÑ Ð²Ð½ÑÑÑи дÑÑгого вÑÑажениÑ, пеÑедаваÑÑ, возвÑаÑаÑÑ, пÑиÑваиваÑÑ Ð¸ Ñ.д.
ÐÑÐ¸Ð¼ÐµÑ Class Expression (по аналогии Ñ Function Expression):
let User = class {
sayHi() {
alert("ÐÑивеÑ");
}
};
ÐналогиÑно Named Function Expression, Class Expression Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð¸Ð¼Ñ.
ÐÑли Ñ Class Expression еÑÑÑ Ð¸Ð¼Ñ, Ñо оно видно ÑолÑко внÑÑÑи клаÑÑа:
// "Named Class Expression"
// (в ÑпеÑиÑикаÑии Ð½ÐµÑ Ñакого ÑеÑмина, но пÑоиÑÑ
одÑÑее поÑ
оже на Named Function Expression)
let User = class MyClass {
sayHi() {
alert(MyClass); // Ð¸Ð¼Ñ MyClass видно ÑолÑко внÑÑÑи клаÑÑа
}
};
new User().sayHi(); // ÑабоÑаеÑ, вÑÐ²Ð¾Ð´Ð¸Ñ Ð¾Ð¿Ñеделение MyClass
alert(MyClass); // оÑибка, Ð¸Ð¼Ñ MyClass не видно за пÑеделами клаÑÑа
ÐÑ Ð´Ð°Ð¶Ðµ можем динамиÑеÑки ÑоздаваÑÑ ÐºÐ»Ð°ÑÑÑ Â«Ð¿Ð¾ запÑоÑÑ»:
function makeClass(phrase) {
// обÑÑвлÑем клаÑÑ Ð¸ возвÑаÑаем его
return class {
sayHi() {
alert(phrase);
};
};
}
// СоздаÑм новÑй клаÑÑ
let User = makeClass("ÐÑивеÑ");
new User().sayHi(); // ÐÑивеÑ
ÐеÑÑеÑÑ/ÑеÑÑеÑÑ, дÑÑгие ÑокÑаÑениÑ
Ðак и в лиÑеÑалÑнÑÑ Ð¾Ð±ÑекÑÐ°Ñ , в клаÑÑÐ°Ñ Ð¼Ð¾Ð¶Ð½Ð¾ обÑÑвлÑÑÑ Ð²ÑÑиÑлÑемÑе ÑвойÑÑва, геÑÑеÑÑ/ÑеÑÑеÑÑ Ð¸ Ñ.д.
ÐÐ¾Ñ Ð¿ÑÐ¸Ð¼ÐµÑ user.name, Ñеализованного Ñ Ð¸ÑполÑзованием get/set:
class User {
constructor(name) {
// вÑзÑÐ²Ð°ÐµÑ ÑеÑÑеÑ
this.name = name;
}
get name() {
return this._name;
}
set name(value) {
if (value.length < 4) {
alert("ÐÐ¼Ñ ÑлиÑком коÑоÑкое.");
return;
}
this._name = value;
}
}
let user = new User("Ðван");
alert(user.name); // Ðван
user = new User(""); // ÐÐ¼Ñ ÑлиÑком коÑоÑкое.
ÐÑи обÑÑвлении клаÑÑа геÑÑеÑÑ/ÑеÑÑеÑÑ ÑоздаÑÑÑÑ Ð½Ð° User.prototype, Ð²Ð¾Ñ Ñак:
Object.defineProperties(User.prototype, {
name: {
get() {
return this._name
},
set(name) {
// ...
}
}
});
ÐÑÐ¸Ð¼ÐµÑ Ñ Ð²ÑÑиÑлÑемÑм ÑвойÑÑвом в ÑкобкаÑ
[...]:
class User {
['say' + 'Hi']() {
alert("ÐÑивеÑ");
}
}
new User().sayHi();
СвойÑÑва клаÑÑов
СвойÑÑва клаÑÑов Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ Ð² ÑзÑк недавно.
РпÑиведÑнном вÑÑе пÑимеÑе Ñ ÐºÐ»Ð°ÑÑа User бÑли ÑолÑко меÑодÑ. ÐавайÑе добавим ÑвойÑÑво:
class User {
name = "Ðноним";
sayHi() {
alert(`ÐÑивеÑ, ${this.name}!`);
}
}
new User().sayHi();
СвойÑÑво name не ÑÑÑанавливаеÑÑÑ Ð² User.prototype. ÐмеÑÑо ÑÑого оно ÑоздаÑÑÑÑ Ð¾Ð¿ÐµÑаÑоÑом new пеÑед запÑÑком конÑÑÑÑкÑоÑа, ÑÑо именно ÑвойÑÑво обÑекÑа.
ÐÑого
ÐазовÑй ÑинÑакÑÐ¸Ñ Ð´Ð»Ñ ÐºÐ»Ð°ÑÑов вÑглÑÐ´Ð¸Ñ Ñак:
class MyClass {
prop = value; // ÑвойÑÑво
constructor(...) { // конÑÑÑÑкÑоÑ
// ...
}
method(...) {} // меÑод
get something(...) {} // геÑÑеÑ
set something(...) {} // ÑеÑÑеÑ
[Symbol.iterator]() {} // меÑод Ñ Ð²ÑÑиÑлÑемÑм именем (здеÑÑ - Ñимволом)
// ...
}
MyClass ÑеÑ
ниÑеÑки ÑвлÑеÑÑÑ ÑÑнкÑией (Ñой, коÑоÑÑÑ Ð¼Ñ Ð¾Ð¿ÑеделÑем как constructor), в Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº меÑодÑ, геÑÑеÑÑ Ð¸ ÑеÑÑеÑÑ Ð·Ð°Ð¿Ð¸ÑÑваÑÑÑÑ Ð² MyClass.prototype.
Ð ÑледÑÑÑÐ¸Ñ Ð³Ð»Ð°Ð²Ð°Ñ Ð¼Ñ Ñзнаем болÑÑе о клаÑÑÐ°Ñ , вклÑÑÐ°Ñ Ð½Ð°Ñледование и дÑÑгие возможноÑÑи.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)