类和构造函数:
1. 可以使用class关键字声明一个类,下面是关于 Person
类的一个声明:
class Person {
name;
constructor(name) {
this.name = name;
}
introduceSelf() {
console.log(`Hi! I'm ${this.name}`);
}
}
①在这个 Person
类的声明中,有:
- 一个
name
属性。 - 一个需要
name
参数的构造函数,这一参数用于初始化新的对象的name
属性。 - 一个
introduceSelf()
方法,使用this
引用了对象的属性。
②name;
这一声明是可选的:你可以省略它,因为在构造函数中的 this.name = name;
这行代码会在初始化 name
属性前自动创建它。但是,在类声明中明确列出属性可以方便阅读代码的人更容易确定哪些属性是这个类的一部分。
③你也可以在声明属性时,为其初始化一个默认值。就像这样:name = '';
。
④构造函数使用 constructor关键字来声明。就像在类声明外的构造函数一样,它会:
- 创建一个新的对象
- 将
this
绑定到这个新的对象,你可以在构造函数代码中使用this
来引用它 - 执行构造函数中的代码
- 返回这个新的对象
2. 上文中给出的类声明的代码,创建和使用一个新的 Person
实例:
const giles = new Person("Giles");
giles.introduceSelf(); // Hi! I'm Giles
注意:我们使用类的名字来调用构造函数,即示例中的 Person
。
3. 完整代码:
class Person{
name;
constructor(name){
this.name = name;
}
introduceSelf(){
console.log(`Hi!I'm${this.name}`);
}
}
const giles = new Person("Giles");
giles.introduceSelf();
结果展示:
4.省略构造函数:
如果你不需要任何特殊的初始化内容,你可以省略构造函数,默认的构造函数会被自动生成:
class Animal{
sleep(){
console.log("zzzz");
}
}
const spot = new Animal();
spot.sleep();
结果展示:
继承:
5. 继承:
对于上文给出的 Person
类,我们声明一个它的子类 Professor
。
class Professor extends Person {
teaches;
constructor(name, teaches) {
super(name);
this.teaches = teaches;
}
introduceSelf() {
console.log(
`My name is ${this.name}, and I will be your ${this.teaches} professor.`,
);
}
grade(paper) {
const grade = Math.floor(Math.random() * (5 - 1) + 1);
console.log(grade);
}
}
①使用extends关键字来声明这个类继承自另一个类。
②为 Professor
类添加了一个新的属性 teaches
,就像声明的那样。
③因为我们想在创建新的 Professor
时设置 teaches
,我们需要声明一个需要 name
和 teaches
参数的构造函数。构造函数中需要做的第一件事是使用 super()调用父类的构造函数,并传递 name
参数。父类的构造函数会设置 name
属性。然后 Professor
的构造函数接着设置 teaches
属性。
④备注: 如果子类有任何自己的初始化内容需要完成,它也必须先使用 super()
来调用父类的构造函数,并传递父类构造函数期望的任何参数。
⑤我们还覆盖了父类的 introduceSelf()
方法,并添加了一个新的方法 grade()
,来为论文打分。
有了这个声明,我们现在可以创建和使用 professor 实例了:
const walsh = new Professor("Walsh", "Psychology");
walsh.introduceSelf(); // 'My name is Walsh, and I will be your Psychology professor'
walsh.grade("my paper"); // 随机数
完整代码:
class Person{
name;
constructor(name){
this.name = name;
}
introduceSelf(){
console.log(`Hi! I'm${this.name}`);
}
}
class Professor extends Person{
teaches;
constructor(name,teaches){
super(name);
this.teaches = teaches;
}
introduceSelf(){
console.log(`My name is ${this.name},and I will be your ${this.teaches} professor.` );
}
grade(paper){
const grade = Math.floor(Math.random()*(5-1)+1);
console.log(grade);
}
}
const walsh = new Professor("Walsh","Psychology");
walsh.introduceSelf();
walsh.grade("my paper");
结果展示:
封装:
Student
的 year
属性变为私有的,可以在不破坏任何使用了 Student
类的代码的情况下,修改内容,声明了 Student
类:
class Student extends Person {
#year;
constructor(name, year) {
super(name);
this.#year = year;
}
introduceSelf() {
console.log(`Hi! I'm ${this.name}, and I'm in year ${this.#year}.`);
}
canStudyArchery() {
return this.#year > 1;
}
}
在这个类的声明中,#year
是一个私有数据属性。我们可以构造一个 Student
对象,然后在内部使用 #year
,但如果在类的外部尝试访问 #year
,浏览器将会抛出错误:
const summers = new Student("Summers", 2);
summers.introduceSelf(); // Hi! I'm Summers, and I'm in year 2.
summers.canStudyArchery(); // true
summers.#year; // SyntaxError
私有数据属性必须在类的声明中声明,而且其名称需以 #
开头。
完整代码:
class Person{
name;
constructor(name){
this.name = name;
}
introduceSelf(){
console.log(`Hi! I'm${this.name}`);
}
}
class Student extends Person{
#year;
constructor(name,year){
super(name);
this.#year = year;
}
introduceSelf(){
console.log(`Hi!I'm${this.name},and I'm in year ${this.#year}.`);
}
canStudyArchery(){
return this.#year>1;
}
}
const summers = new Student("Summers",2);
summers.introduceSelf();
summers.canStudyArchery();
结果展示:
控制台:公有私有都可以输出,所以对于summers.#year是可以输出的
如果在文件中输入summers.#year;会发现报错
控制台出现错误:
私有方法:
与私有数据属性一样,你也可以声明私有方法。而且名称也是以 #
开头,只能在类自己的方法中调用:
class Example {
somePublicMethod() {
this.#somePrivateMethod();
}
#somePrivateMethod() {
console.log("You called me?");
}
}
const myExample = new Example();
myExample.somePublicMethod(); // 'You called me?'
//myExample.#somePrivateMethod(); // SyntaxError
展示结果:
如果在文件中输入:myExample.#somePrivateMethod();出现错误
控制台出现错误: