Nowa class
składnia to na razie głównie cukier syntaktyczny. (Ale wiesz, dobry rodzaj cukru.) W ES2015-ES2020 nie ma niczego class
, czego nie można zrobić z funkcjami konstruktora Reflect.construct
(łącznie z podklasami Error
i Array
¹). (Jest to prawdopodobnie będzie kilka rzeczy w ES2021, że można zrobić z class
, że nie można zrobić inaczej: prywatne pola , metody prywatne i Pola statyczne / prywatne metody statyczne ).
Co więcej, czy jest class
to inny rodzaj OOP, czy nadal jest to prototypowe dziedziczenie JavaScript?
Jest to to samo prototypowe dziedziczenie, które zawsze mieliśmy, tylko z czystszą i wygodniejszą składnią, jeśli lubisz używać funkcji konstruktorów ( new Foo
itp.). (Szczególnie w przypadku wywodzenia się z Array
lub Error
, czego nie mogłeś zrobić w ES5 i wcześniejszych. Możesz teraz z Reflect.construct
[ spec , MDN ], ale nie ze starym stylem ES5.)
Czy mogę go zmodyfikować za pomocą .prototype
?
Tak, prototype
po utworzeniu klasy nadal możesz modyfikować obiekt w konstruktorze klasy. Np. Jest to całkowicie legalne:
class Foo {
constructor(name) {
this.name = name;
}
test1() {
console.log("test1: name = " + this.name);
}
}
Foo.prototype.test2 = function() {
console.log("test2: name = " + this.name);
};
Czy są korzyści związane z szybkością?
Poprzez zapewnienie idiom specyficzne dla tego, Przypuszczam, że to możliwe , że silnik może być w stanie zrobić lepszą optymalizację pracy. Ale już teraz są okropnie dobrzy w optymalizacji, nie spodziewałbym się znaczącej różnicy.
Jakie korzyści class
zapewnia składnia ES2015 (ES6) ?
W skrócie: jeśli w pierwszej kolejności nie używasz funkcji konstruktora, preferowanie Object.create
lub class
coś podobnego nie jest dla ciebie przydatne.
Jeśli używasz funkcji konstruktora, istnieją pewne korzyści z class
:
Składnia jest prostsza i mniej podatna na błędy.
O wiele łatwiej (i znowu mniej podatne na błędy) jest konfigurowanie hierarchii dziedziczenia przy użyciu nowej składni niż w przypadku starej.
class
chroni Cię przed typowym błędem polegającym na niepowodzeniu użycia new
funkcji konstruktora (przez wywołanie przez konstruktora wyjątku, jeśli this
nie jest prawidłowym obiektem dla konstruktora).
Wywołanie wersji metody prototypu nadrzędnego jest znacznie prostsze w przypadku nowej składni niż starej ( super.method()
zamiast ParentConstructor.prototype.method.call(this)
lub Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
).
Oto porównanie składni dla hierarchii:
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() {
}
}
Przykład:
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());
vs.
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() {
};
Przykład na żywo:
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());
Jak widać, jest tam wiele powtarzających się i rozwlekłych rzeczy, które łatwo się pomylić i nudne do przepisania (dlatego napisałem kiedyś skrypt, który to robi ).
¹ „W ES2015-ES2018 class
nie ma nic, czego nie można zrobić za pomocą funkcji konstruktora i Reflect.construct
(w tym podklasy Error
i Array
)”
Przykład:
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;
}