ES2015(ES6)`class`语法有什么好处? [英] What benefits does ES2015 (ES6) `class` syntax provide?
问题描述
我对ES6类有很多疑问.
使用class
语法有什么好处?我读到public/private/static将成为ES7的一部分,这是一个原因吗?
此外,class
是另一种OOP还是JavaScript的原型继承?我可以使用.prototype
对其进行修改吗?还是它只是同一个对象,但是用两种不同的方式声明它.
有速度优势吗?如果您拥有像大型应用程序这样的大型应用程序,也许维护/理解起来会更容易?
对于 now 而言,新的class
语法主要是语法糖. (但是,您知道,好是一种糖.)在ES2015-ES2019中,没有任何class
可以做的事,而构造函数和Reflect.construct
都做不到(包括对Array
¹). ( 可能在ES2021中可以通过class
进行其他操作,否则无法进行其他操作:私有方法和静态字段/私有静态方法.)
此外,
class
是另一种OOP还是JavaScript的原型继承?
这是我们一直拥有的原型继承,只是使用更简洁,更方便的语法 if (如果您喜欢使用构造函数)(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
不是构造函数的有效对象,则使构造函数抛出异常)./p> -
使用新语法比使用旧语法(
super.method()
代替ParentConstructor.prototype.method.call(this)
或Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
)调用父原型方法的版本要简单得多.
这是层次结构的语法比较:
// ***ES2015+**
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();
// ...use `result` for something...
return result;
}
managerMethod() {
// ...
}
}
示例:
// ***ES2015+**
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.
// **ES5**
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);
// ...use `result` for something...
return result;
};
Manager.prototype.managerMethod = function() {
// ...
};
实时示例:
// **ES5**
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
)无法做到的事情"
示例:
// Creating an Error subclass:
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);
};
// Example use:
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;
}
I have many question about ES6 classes.
What's the benefit of using class
syntax? I read that public/private/static will be part of ES7, is that a reason?
Moreover, is class
a different kind of OOP or it still JavaScript's prototypical inheritance? Can I modify it using .prototype
? Or is it just the same object but two different ways to declare it.
Are there speed benefits? Maybe it's easier to maintain/understand if you have a big application like big app?
The new class
syntax is, for now, mostly syntactic sugar. (But, you know, the good kind of sugar.) There's nothing in ES2015-ES2019 that class
can do that you can't do with constructor functions and Reflect.construct
(including subclassing Error
and Array
¹). (There is likely to be some things in ES2021 that you can do with class
that you can't do otherwise: private fields, private methods, and static fields/private static methods.)
Moreover, is
class
a different kind of OOP or it still JavaScript's prototypical inheritance?
It's the same prototypical inheritance we've always had, just with cleaner and more convenient syntax if you like using constructor functions (new Foo
, etc.). (Particularly in the case of deriving from Array
or Error
, which you couldn't do in ES5 and earlier. You can now with Reflect.construct
[spec, MDN], but not with the old ES5-style.)
Can I modify it using
.prototype
?
Yes, you can still modify the prototype
object on the class's constructor once you've created the class. E.g., this is perfectly legal:
class Foo {
constructor(name) {
this.name = name;
}
test1() {
console.log("test1: name = " + this.name);
}
}
Foo.prototype.test2 = function() {
console.log("test2: name = " + this.name);
};
Are there speed benefits?
By providing a specific idiom for this, I suppose it's possible that the engine may be able to do a better job optimizing. But they're awfully good at optimizing already, I wouldn't expect a significant difference.
What benefits does ES2015 (ES6)
class
syntax provide?
Briefly: If you don't use constructor functions in the first place, preferring Object.create
or similar, class
isn't useful to you.
If you do use constructor functions, there are some benefits to class
:
The syntax is simpler and less error-prone.
It's much easier (and again, less error-prone) to set up inheritance hierarchies using the new syntax than with the old.
class
defends you from the common error of failing to usenew
with the constructor function (by having the constructor throw an exception ifthis
isn't a valid object for the constructor).Calling the parent prototype's version of a method is much simpler with the new syntax than the old (
super.method()
instead ofParentConstructor.prototype.method.call(this)
orObject.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
).
Here's a syntax comparison for a hierarchy:
// ***ES2015+**
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();
// ...use `result` for something...
return result;
}
managerMethod() {
// ...
}
}
Example:
// ***ES2015+**
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.
// **ES5**
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);
// ...use `result` for something...
return result;
};
Manager.prototype.managerMethod = function() {
// ...
};
Live Example:
// **ES5**
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());
As you can see, lots of repeated and verbose stuff there which is easy to get wrong and boring to retype (which is why I wrote a script to do it, back in the day).
¹ "There's nothing in ES2015-ES2018 that class
can do that you can't do with constructor functions and Reflect.construct
(including subclassing Error
and Array
)"
Example:
// Creating an Error subclass:
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);
};
// Example use:
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;
}
这篇关于ES2015(ES6)`class`语法有什么好处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!