Новий class
синтаксис, для тепер , в основному синтаксичного цукру. (Але, ви знаєте, хороший сорт цукру.) У ES2015-ES2020 class
немає нічого такого, що не можна робити з функціями конструктора та Reflect.construct
(включаючи підкласифікацію Error
та Array
¹). (Це є , ймовірно , будуть якісь - то речі в ES2021 , що ви можете зробити з , class
що ви не можете зробити інакше: приватні поля , приватні методи і статичні поля / приватні статичні методи .)
Більше того, це class
інший тип ООП, чи це все-таки прототипове успадкування JavaScript?
Це те саме прототипове успадкування, яке ми завжди мали, лише з більш чистим та зручним синтаксисом, якщо вам подобається використовувати функції конструктора ( new Foo
тощо). (Зокрема, у випадку походження з Array
або Error
, чого ви не могли зробити в ES5 і раніше. Тепер ви можете з Reflect.construct
[ специфікацією , MDN ], але не зі старим стилем ES5.)
Чи можу я змінити його за допомогою .prototype
?
Так, ви все ще можете змінити prototype
об’єкт у конструкторі класу, як тільки ви створили клас. Наприклад, це цілком законно:
class Foo {
constructor(name) {
this.name = name;
}
test1() {
console.log("test1: name = " + this.name);
}
}
Foo.prototype.test2 = function() {
console.log("test2: name = " + this.name);
};
Чи є переваги в швидкості?
Надаючи конкретну ідіому для цього, я припускаю, що можливо, що двигун зможе зробити кращу роботу з оптимізації. Але вони вже дуже добре оптимізують, я не очікував би суттєвої різниці.
Які переваги надає синтаксис ES2015 (ES6) class
?
Коротко: Якщо ви спочатку не використовуєте функції конструктора, віддавати перевагу Object.create
чи подібні class
вам не корисні.
Якщо ви використовуєте функції конструктора, є деякі переваги class
:
Синтаксис простіший і менш схильний до помилок.
Це набагато простіше (і знову, менш схильні до помилок) , щоб створити ієрархії успадкування , використовуючи новий синтаксис , ніж зі старим.
class
захищає вас від поширеної помилки відсутності використання new
з функцією конструктора (завдяки тому, що конструктор викидає виняток, якщо this
не є дійсним об'єктом для конструктора).
Викликати версію методу батьківського прототипу набагато простіше з новим синтаксисом, ніж старим ( super.method()
замість ParentConstructor.prototype.method.call(this)
або Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
).
Ось порівняння синтаксису для ієрархії:
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
personMethod() {
}
}
class Employee extends Person {
constructor(first, last, position) {
super(first, last);
this.position = position;
}
employeeMethod() {
}
}
class Manager extends Employee {
constructor(first, last, position, department) {
super(first, last, position);
this.department = department;
}
personMethod() {
const result = super.personMethod();
return result;
}
managerMethod() {
}
}
Приклад:
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
personMethod() {
return `Result from personMethod: this.first = ${this.first}, this.last = ${this.last}`;
}
}
class Employee extends Person {
constructor(first, last, position) {
super(first, last);
this.position = position;
}
personMethod() {
const result = super.personMethod();
return result + `, this.position = ${this.position}`;
}
employeeMethod() {
}
}
class Manager extends Employee {
constructor(first, last, position, department) {
super(first, last, position);
this.department = department;
}
personMethod() {
const result = super.personMethod();
return result + `, this.department = ${this.department}`;
}
managerMethod() {
}
}
const m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");
console.log(m.personMethod());
проти
var Person = function(first, last) {
if (!(this instanceof Person)) {
throw new Error("Person is a constructor function, use new with it");
}
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
};
var Employee = function(first, last, position) {
if (!(this instanceof Employee)) {
throw new Error("Employee is a constructor function, use new with it");
}
Person.call(this, first, last);
this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.employeeMethod = function() {
};
var Manager = function(first, last, position, department) {
if (!(this instanceof Manager)) {
throw new Error("Manager is a constructor function, use new with it");
}
Employee.call(this, first, last, position);
this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
var result = Employee.prototype.personMethod.call(this);
return result;
};
Manager.prototype.managerMethod = function() {
};
Живий приклад:
var Person = function(first, last) {
if (!(this instanceof Person)) {
throw new Error("Person is a constructor function, use new with it");
}
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
return "Result from personMethod: this.first = " + this.first + ", this.last = " + this.last;
};
var Employee = function(first, last, position) {
if (!(this instanceof Employee)) {
throw new Error("Employee is a constructor function, use new with it");
}
Person.call(this, first, last);
this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.personMethod = function() {
var result = Person.prototype.personMethod.call(this);
return result + ", this.position = " + this.position;
};
Employee.prototype.employeeMethod = function() {
};
var Manager = function(first, last, position, department) {
if (!(this instanceof Manager)) {
throw new Error("Manager is a constructor function, use new with it");
}
Employee.call(this, first, last, position);
this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
var result = Employee.prototype.personMethod.call(this);
return result + ", this.department = " + this.department;
};
Manager.prototype.managerMethod = function() {
};
var m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");
console.log(m.personMethod());
Як бачите, там багато повторюваних і багатослівних речей, які легко помилитися і нудно переписати (саме тому я написав сценарій для цього ще в той же день).
¹ "У ES2015-ES2018 class
немає нічого такого, що не можна робити з функціями конструктора та Reflect.construct
(включаючи підкласи Error
та Array
)"
Приклад:
function MyError(...args) {
return Reflect.construct(Error, args, this.constructor);
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
MyError.prototype.myMethod = function() {
console.log(this.message);
};
function outer() {
function inner() {
const e = new MyError("foo");
console.log("Callng e.myMethod():");
e.myMethod();
console.log(`e instanceof MyError? ${e instanceof MyError}`);
console.log(`e instanceof Error? ${e instanceof Error}`);
throw e;
}
inner();
}
outer();
.as-console-wrapper {
max-height: 100% !important;
}