The new class
语法大部分(尽管不完全)是语法糖(但是,你知道,good一种糖)。它显着简化了构造函数的编写以及它们作为原型分配给它们创建的对象的对象,特别是在设置继承层次结构时,这在 ES5 语法中很容易出错。但与旧方式不同的是,class
语法还允许super.example()
对于超级调用(众所周知,用旧方法很难做到)以及财产申报 https://github.com/tc39/proposal-class-fields, 私人领域 https://github.com/tc39/proposal-class-fields, and 私有方法 https://github.com/tc39/proposal-private-methods(包括静态的 http://github.com/tc39/proposal-static-class-features/).
(有时人们说你必须使用class
如果你想子类化语法Error
or Array
[在 ES5 中无法正确子类化]。这不是真的,你可以使用不同的 ES2015 功能,Reflect.construct
[spec https://tc39.github.io/ecma262/#sec-reflect.construct, MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct],如果你不想使用class
语法。
而且,是class
一种不同类型的 OOP 或者它仍然是 JavaScript 的原型继承?
它与我们一直拥有的原型继承相同,只是具有更清晰、更方便且不易出错的语法if你喜欢使用构造函数(new Foo
等),加上一些附加功能。
我可以使用修改它吗.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);
};
有速度优势吗?
通过为此提供一个特定的习语,我想它是possible引擎可能能够更好地进行优化。但他们已经非常擅长优化,我不认为会有显着的差异。特别值得一提的是class
语法是如果你使用财产申报 https://github.com/tc39/proposal-class-fields,你可以最小化形状变化对象在构造时会经历,这可以使解释和稍后编译代码更快一些。但话又说回来,规模不会很大。
ES2015(ES6)有什么好处class
语法提供?
简而言之:如果您一开始不使用构造函数,则更喜欢Object.create
或类似的,class
对你没有用。
如果您确实使用构造函数,那么有一些好处class
:
-
语法更简单并且不易出错。
-
It's much使用新语法比使用旧语法更容易(并且更不容易出错)设置继承层次结构。
-
class
保护您免受未能使用的常见错误的影响new
与构造函数(通过让构造函数抛出异常)。
-
使用新语法调用方法的父原型版本比旧语法要简单得多(super.method()
代替ParentConstructor.prototype.method.call(this)
or Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
).
-
属性声明可以使创建的实例的形状更加清晰,将其与构造函数逻辑分开。
-
您可以使用私有字段和方法(实例和静态)class
语法,而不是 ES5 语法。
这是层次结构的语法比较(没有私有成员):
// ***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() {
// ...
};
实例:
// **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());
正如你所看到的,那里有很多重复和冗长的东西,很容易出错并且重新输入很无聊(我以前使用过一个脚本,早在一天之前,之前class
伴随着)。
我应该注意到,在 ES2015 代码中,Person
函数的原型是Employee
函数,但 ES5 代码中并非如此。在 ES5 中,没有办法做到这一点;所有功能都使用Function.prototype
作为他们的原型。一些环境支持__proto__
不过,伪属性可能允许改变这一点。在这些环境中,您可以这样做:
Employee.__proto__ = Person; // Was non-standard in ES5
如果出于某种原因你想这样做function
语法而不是class
在 ES2015+ 环境中,您可以使用标准Object.setPrototypeOf
反而:
Object.setPrototypeOf(Employee, Person); // Standard ES2015+
但我看不出在 ES2015+ 环境中使用旧语法有任何强烈的动机(除了尝试了解管道的工作原理)。
(ES2015还定义了__proto__访问器属性 https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.prototype.__proto__这是一个包装器Object.setPrototypeOf
and Object.getPrototypeOf
以便这些非标准环境中的代码成为标准,但它仅为遗留代码定义,并且是“规范可选”,意味着不需要环境来提供它。)
1 以下是您的使用方法Reflect.construct
子类化Error
(例如)如果你不想使用class
syntax:
// 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;
}