Skip to content

JavaScript 是一种面向对象的编程语言。JavaScript 中的一切都是对象,具有其属性和方法。我们创建类来创建对象。类就像一个对象构造器,或者是创建对象的"蓝图"。我们实例化一个类来创建对象。类定义了对象的属性和行为,而对象则代表类。

一旦我们创建了一个类,我们就可以随时从中创建对象。从类创建对象称为类实例化。

在对象部分,我们看到了如何创建对象字面量。对象字面量是单例的。如果我们想要获得类似的对象,我们必须编写它。然而,类允许创建许多对象。这有助于减少代码量和代码重复。

定义类

要在 JavaScript 中定义类,我们需要关键字 class,类名使用 驼峰命名法 和代码块(两个大括号)。让我们创建一个名为 Person 的类。

js
// 语法
class ClassName {
    //  代码放在这里
}

示例:

js
class Person {
  // 代码放在这里
}

我们已经创建了一个 Person 类,但它里面没有任何内容。

类实例化

实例化类意味着从类创建对象。我们需要关键字 new,并在 new 关键字后调用类的名称。

让我们从 Person 类创建一个 person 对象。

js
class Person {
  // 代码放在这里
}
const person = new Person()
console.log(person)
sh
Person {}

如你所见,我们已经创建了一个 person 对象。由于类还没有任何属性,所以对象也是空的。

让我们使用类构造器为类传递不同的属性。

类构造器

构造器是一个内置函数,它允许我们为对象创建蓝图。构造器函数以关键字 constructor 开始,后跟括号。在括号内,我们将对象的属性作为参数传递。我们使用 this 关键字将构造器参数与类连接起来。

以下 Person 类构造器具有 firstName 和 lastName 属性。这些属性使用 this 关键字附加到 Person 类。This 指的是类本身。

js
class Person {
  constructor(firstName, lastName) {
    console.log(this) // 检查这里的输出
    this.firstName = firstName
    this.lastName = lastName
  }
}

const person = new Person()

console.log(person)
sh
Person {firstName: undefined, lastName:undefined}

对象的所有键都是 undefined。每当我们实例化时,我们应该传递属性的值。让我们在实例化类时传递值。

js
class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
}

const person1 = new Person('Asabeneh', 'Yetayeh')

console.log(person1)
sh
Person {firstName: "Asabeneh", lastName: "Yetayeh"}

正如我们在一开始就说过的,一旦我们创建了一个类,我们就可以使用该类创建许多对象。现在,让我们使用 Person 类创建许多 person 对象。

js
class Person {
  constructor(firstName, lastName) {
    console.log(this) // 检查这里的输出
    this.firstName = firstName
    this.lastName = lastName
  }
}

const person1 = new Person('Asabeneh', 'Yetayeh')
const person2 = new Person('Lidiya', 'Tekle')
const person3 = new Person('Abraham', 'Yetayeh')

console.log(person1)
console.log(person2)
console.log(person3)
sh
Person {firstName: "Asabeneh", lastName: "Yetayeh"}
Person {firstName: "Lidiya", lastName: "Tekle"}
Person {firstName: "Abraham", lastName: "Yetayeh"}

使用 Person 类,我们创建了三个 person 对象。如你所见,我们的类没有很多属性,让我们为类添加更多属性。

js
class Person {
  constructor(firstName, lastName, age, country, city) {
    console.log(this) // 检查这里的输出
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.country = country
    this.city = city
  }
}

const person1 = new Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')

console.log(person1)
sh
Person {firstName: "Asabeneh", lastName: "Yetayeh", age: 250, country: "Finland", city: "Helsinki"}

构造器的默认值

构造器函数属性可能有默认值,就像其他常规函数一样。

js
class Person {
  constructor(
    firstName = 'Asabeneh',
    lastName = 'Yetayeh',
    age = 250,
    country = 'Finland',
    city = 'Helsinki'
  ) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.country = country
    this.city = city
  }
}

const person1 = new Person() // 它将采用默认值
const person2 = new Person('Lidiya', 'Tekle', 28, 'Finland', 'Espoo')

console.log(person1)
console.log(person2)
sh
Person {firstName: "Asabeneh", lastName: "Yetayeh", age: 250, country: "Finland", city: "Helsinki"}
Person {firstName: "Lidiya", lastName: "Tekle", age: 28, country: "Finland", city: "Espoo"}

类方法

类内部的构造器是一个内置函数,它允许我们为对象创建蓝图。在类中,我们可以创建类方法。方法是类内部的 JavaScript 函数。让我们创建一些类方法。

js
class Person {
  constructor(firstName, lastName, age, country, city) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.country = country
    this.city = city
  }
  getFullName() {
    const fullName = this.firstName + ' ' + this.lastName
    return fullName
  }
}

const person1 = new Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
const person2 = new Person('Lidiya', 'Tekle', 28, 'Finland', 'Espoo')

console.log(person1.getFullName())
console.log(person2.getFullName())
sh
Asabeneh Yetayeh
Lidiya Tekle

具有初始值的属性

当我们为某些属性创建类时,我们可能有一个初始值。例如,如果你在玩游戏,你的起始分数将为零。所以,我们可能有一个起始分数或分数为零。换句话说,我们可能有一个初始技能,我们将在一段时间后获得一些技能。

js
class Person {
  constructor(firstName, lastName, age, country, city) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.country = country
    this.city = city
    this.score = 0
    this.skills = []
  }
  getFullName() {
    const fullName = this.firstName + ' ' + this.lastName
    return fullName
  }
}

const person1 = new Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
const person2 = new Person('Lidiya', 'Tekle', 28, 'Finland', 'Espoo')

console.log(person1.score)
console.log(person2.score)

console.log(person1.skills)
console.log(person2.skills)
sh
0
0
[]
[]

方法可以是常规方法、getter 或 setter。让我们看看 getter 和 setter。

getter

get 方法允许我们从对象访问值。我们使用关键字 get 后跟函数来编写 get 方法。我们不是直接从对象访问属性,而是使用 getter 来获取值。请看下面的示例

js
class Person {
  constructor(firstName, lastName, age, country, city) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.country = country
    this.city = city
    this.score = 0
    this.skills = []
  }
  getFullName() {
    const fullName = this.firstName + ' ' + this.lastName
    return fullName
  }
  get getScore() {
    return this.score
  }
  get getSkills() {
    return this.skills
  }
}

const person1 = new Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
const person2 = new Person('Lidiya', 'Tekle', 28, 'Finland', 'Espoo')

console.log(person1.getScore) // 我们不需要括号来调用 getter 方法
console.log(person2.getScore)

console.log(person1.getSkills)
console.log(person2.getSkills)
sh
0
0
[]
[]

setter

setter 方法允许我们修改某些属性的值。我们使用关键字 set 后跟函数来编写 setter 方法。请看下面的示例。

js
class Person {
  constructor(firstName, lastName, age, country, city) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.country = country
    this.city = city
    this.score = 0
    this.skills = []
  }
  getFullName() {
    const fullName = this.firstName + ' ' + this.lastName
    return fullName
  }
  get getScore() {
    return this.score
  }
  get getSkills() {
    return this.skills
  }
  set setScore(score) {
    this.score += score
  }
  set setSkill(skill) {
    this.skills.push(skill)
  }
}

const person1 = new Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
const person2 = new Person('Lidiya', 'Tekle', 28, 'Finland', 'Espoo')

person1.setScore = 1
person1.setSkill = 'HTML'
person1.setSkill = 'CSS'
person1.setSkill = 'JavaScript'

person2.setScore = 1
person2.setSkill = 'Planning'
person2.setSkill = 'Managing'
person2.setSkill = 'Organizing'

console.log(person1.score)
console.log(person2.score)

console.log(person1.skills)
console.log(person2.skills)
sh
1
1
["HTML", "CSS", "JavaScript"]
["Planning", "Managing", "Organizing"]

不要被常规方法和 getter 之间的区别所困惑。如果你知道如何制作常规方法,你就很好了。让我们在 Person 类中添加一个名为 getPersonInfo 的常规方法。

js
class Person {
  constructor(firstName, lastName, age, country, city) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.country = country
    this.city = city
    this.score = 0
    this.skills = []
  }
  getFullName() {
    const fullName = this.firstName + ' ' + this.lastName
    return fullName
  }
  get getScore() {
    return this.score
  }
  get getSkills() {
    return this.skills
  }
  set setScore(score) {
    this.score += score
  }
  set setSkill(skill) {
    this.skills.push(skill)
  }
  getPersonInfo() {
    let fullName = this.getFullName()
    let skills =
      this.skills.length > 0 &&
      this.skills.slice(0, this.skills.length - 1).join(', ') +
        ` and ${this.skills[this.skills.length - 1]}`
    let formattedSkills = skills ? `He knows ${skills}` : ''

    let info = `${fullName} is ${this.age}. He lives ${this.city}, ${this.country}. ${formattedSkills}`
    return info
  }
}

const person1 = new Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
const person2 = new Person('Lidiya', 'Tekle', 28, 'Finland', 'Espoo')
const person3 = new Person('John', 'Doe', 50, 'Mars', 'Mars city')

person1.setScore = 1
person1.setSkill = 'HTML'
person1.setSkill = 'CSS'
person1.setSkill = 'JavaScript'

person2.setScore = 1
person2.setSkill = 'Planning'
person2.setSkill = 'Managing'
person2.setSkill = 'Organizing'

console.log(person1.getScore)
console.log(person2.getScore)

console.log(person1.getSkills)
console.log(person2.getSkills)
console.log(person3.getSkills)

console.log(person1.getPersonInfo())
console.log(person2.getPersonInfo())
console.log(person3.getPersonInfo())
sh
1
1
["HTML", "CSS", "JavaScript"]
["Planning", "Managing", "Organizing"]
[]
Asabeneh Yetayeh is 250. He lives Helsinki, Finland. He knows HTML, CSS and JavaScript
Lidiya Tekle is 28. He lives Espoo, Finland. He knows Planning, Managing and Organizing
John Doe is 50. He lives Mars city, Mars.

静态方法

static 关键字为类定义静态方法。静态方法不在类的实例上调用。相反,它们在类本身上调用。这些通常是实用函数,例如创建或克隆对象的函数。静态方法的一个例子是 Date.now()now 方法直接从类调用。

js
class Person {
  constructor(firstName, lastName, age, country, city) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.country = country
    this.city = city
    this.score = 0
    this.skills = []
  }
  getFullName() {
    const fullName = this.firstName + ' ' + this.lastName
    return fullName
  }
  get getScore() {
    return this.score
  }
  get getSkills() {
    return this.skills
  }
  set setScore(score) {
    this.score += score
  }
  set setSkill(skill) {
    this.skills.push(skill)
  }
  getPersonInfo() {
    let fullName = this.getFullName()
    let skills =
      this.skills.length > 0 &&
      this.skills.slice(0, this.skills.length - 1).join(', ') +
        ` and ${this.skills[this.skills.length - 1]}`

    let formattedSkills = skills ? `He knows ${skills}` : ''

    let info = `${fullName} is ${this.age}. He lives ${this.city}, ${this.country}. ${formattedSkills}`
    return info
  }
  static favoriteSkill() {
    const skills = ['HTML', 'CSS', 'JS', 'React', 'Python', 'Node']
    const index = Math.floor(Math.random() * skills.length)
    return skills[index]
  }
  static showDateTime() {
    let now = new Date()
    let year = now.getFullYear()
    let month = now.getMonth() + 1
    let date = now.getDate()
    let hours = now.getHours()
    let minutes = now.getMinutes()
    if (hours < 10) {
      hours = '0' + hours
    }
    if (minutes < 10) {
      minutes = '0' + minutes
    }

    let dateMonthYear = date + '.' + month + '.' + year
    let time = hours + ':' + minutes
    let fullTime = dateMonthYear + ' ' + time
    return fullTime
  }
}

console.log(Person.favoriteSkill())
console.log(Person.showDateTime())
sh
Node
15.1.2020 23:56

静态方法是可以用作实用函数的方法。

继承

使用继承,我们可以访问父类的所有属性和方法。这减少了代码的重复。如果你记得,我们有一个 Person 父类,我们将从中创建子类。我们的子类可以是学生、老师等。

js
// 语法
class ChildClassName extends ParentClassName {
 // 代码放在这里
}

让我们从 Person 父类创建一个 Student 子类。

js
class Student extends Person {
  saySomething() {
    console.log('I am a child of the person class')
  }
}

const s1 = new Student('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
console.log(s1)
console.log(s1.saySomething())
console.log(s1.getFullName())
console.log(s1.getPersonInfo())
sh
Student {firstName: "Asabeneh", lastName: "Yetayeh", age: 250, country: "Finland", city: "Helsinki", …}
I am a child of the person class
Asabeneh Yetayeh
Asabeneh Yetayeh is 250. He lives Helsinki, Finland.

重写方法

如你所见,我们设法访问了 Person 类中的所有方法,并在 Student 子类中使用了它。我们可以自定义父方法,我们可以向子类添加其他属性。如果我们想要自定义方法并且想要添加额外的属性,我们也需要在子类中使用构造器函数。在构造器函数内部,我们调用 super() 函数来访问父类的所有属性。Person 类没有性别,但现在让我们为子类 Student 提供性别属性。如果在子类中使用相同的方法名,父方法将被重写。

js
class Student extends Person {
  constructor(firstName, lastName, age, country, city, gender) {
    super(firstName, lastName, age, country, city)
    this.gender = gender
  }

  saySomething() {
    console.log('I am a child of the person class')
  }
  getPersonInfo() {
    let fullName = this.getFullName()
    let skills =
      this.skills.length > 0 &&
      this.skills.slice(0, this.skills.length - 1).join(', ') +
        ` and ${this.skills[this.skills.length - 1]}`

    let formattedSkills = skills ? `He knows ${skills}` : ''
    let pronoun = this.gender == 'Male' ? 'He' : 'She'

    let info = `${fullName} is ${this.age}. ${pronoun} lives in ${this.city}, ${this.country}. ${formattedSkills}`
    return info
  }
}

const s1 = new Student(
  'Asabeneh',
  'Yetayeh',
  250,
  'Finland',
  'Helsinki',
  'Male'
)
const s2 = new Student('Lidiya', 'Tekle', 28, 'Finland', 'Helsinki', 'Female')
s1.setScore = 1
s1.setSkill = 'HTML'
s1.setSkill = 'CSS'
s1.setSkill = 'JavaScript'

s2.setScore = 1
s2.setSkill = 'Planning'
s2.setSkill = 'Managing'
s2.setSkill = 'Organizing'

console.log(s1)

console.log(s1.saySomething())
console.log(s1.getFullName())
console.log(s1.getPersonInfo())

console.log(s2.saySomething())
console.log(s2.getFullName())
console.log(s2.getPersonInfo())
sh
Student {firstName: "Asabeneh", lastName: "Yetayeh", age: 250, country: "Finland", city: "Helsinki", …}
Student {firstName: "Lidiya", lastName: "Tekle", age: 28, country: "Finland", city: "Helsinki", …}
I am a child of the person class
Asabeneh Yetayeh
Asabeneh Yetayeh is 250. He lives in Helsinki, Finland. He knows HTML, CSS and JavaScript
I am a child of the person class
Lidiya Tekle
Lidiya Tekle is 28. She lives in Helsinki, Finland. She knows Planning, Managing and Organizing

现在,getPersonInfo 方法已被重写,它识别该人是男性还是女性。

🌕 你表现出色。现在,你知道了类,你有能力将一切转化为对象。你已经走到了通往伟大之路的一半。现在做一些练习来锻炼你的大脑和肌肉。

练习

练习:第1级

  1. 创建一个 Animal 类。该类将具有 name、age、color、legs 属性并创建不同的方法
  2. 从 Animal 类创建 Dog 和 Cat 子类。

练习:第2级

  1. 重写你在 Animal 类中创建的方法

练习:第3级

  1. 让我们尝试开发一个程序,计算样本的集中趋势度量(均值、中位数、众数)和变异性度量(范围、方差、标准差)。除了这些度量之外,还要找到样本的最小值、最大值、计数、百分位数和频率分布。你可以创建一个名为 Statistics 的类,并创建所有进行统计计算的函数作为 Statistics 类的方法。检查下面的输出。
js
ages = [31, 26, 34, 37, 27, 26, 32, 32, 26, 27, 27, 24, 32, 33, 27, 25, 26, 38, 37, 31, 34, 24, 33, 29, 26]

console.log('Count:', statistics.count()) // 25
console.log('Sum: ', statistics.sum()) // 744
console.log('Min: ', statistics.min()) // 24
console.log('Max: ', statistics.max()) // 38
console.log('Range: ', statistics.range()) // 14
console.log('Mean: ', statistics.mean()) // 30
console.log('Median: ',statistics.median()) // 29
console.log('Mode: ', statistics.mode()) // {'mode': 26, 'count': 5}
console.log('Variance: ',statistics.var()) // 17.5
console.log('Standard Deviation: ', statistics.std()) // 4.2
console.log('Variance: ',statistics.var()) // 17.5
console.log('Frequency Distribution: ',statistics.freqDist()) // [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)]
sh
// 你的输出应该看起来像这样
console.log(statistics.describe())
Count: 25
Sum:  744
Min:  24
Max:  38
Range:  14
Mean:  30
Median:  29
Mode:  (26, 5)
Variance:  17.5
Standard Deviation:  4.2
Frequency Distribution: [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)]
  1. 创建一个名为 PersonAccount 的类。它具有 firstname、lastname、incomes、expenses 属性,并且具有 totalIncome、totalExpense、accountInfo、addIncome、addExpense 和 accountBalance 方法。Incomes 是一组收入及其描述,expenses 也是一组支出及其描述。

🎉 恭喜!🎉