发布于 2026-01-06 4 阅读
0

JavaScript 中的面向对象编程 🤓

JavaScript 中的面向对象编程 🤓

嗨!编程可能会让人不知所措😫,但一旦你掌握了一些基本概念,它就会像一种超能力🦸‍♀️一样让你感觉自己拥有了超能力,而JavaScript是最酷的编程语言之一!💯

本文档概述了 JavaScript 中的面向对象编程。我们将涵盖以下内容:

  • 什么是面向对象编程?
  • JavaScript 中的面向对象编程
  • 课程
  • 原型模型
  • 指导原则

什么是面向对象编程?

当我们谈论面向对象编程(OOP)时,实际上是在讨论如何组织代码。很多时候,决定代码的存放位置并非易事。OOP 为我们提供了一种工作范式。

关键在于使用对象来模拟现实生活中的事物,这些对象可以包含数据或属性,并可以执行操作或方法。例如,一个人可以拥有姓名、年龄或国籍等多种属性,并且可以执行跑步或吃饭等多种操作。

如果我们想在代码中创建很多不同的人物,事情很快就会变得难以控制。

面向对象编程 (OOP) 包含多个概念,有助于我们保持代码的可维护性。我们绝不想要意大利面条式代码🍝。其中一些概念包括:

  • 抽象—— 我们只向外界提供必要信息,而隐藏其背景细节。随着构建的对象越来越复杂,抽象可以帮助我们简化事物。
  • 封装—— 指的是将所有数据和功能存储在一个单独的单元中。它也是限制对某些属性访问的一种方法。
  • 继承—— 它是指根据另一个对象赋予另一个对象数据和功能的能力。它能帮助我们编写更少的代码,并提高代码的可重用性。

JavaScript 中的面向对象编程

JavaScript 是一种非常灵活的语言,你可以使用不同的编程范式来编写代码。关于如何在 JavaScript 中使用面向对象编程 (OOP) 也存在很多不同的观点,因此本文并非操作指南,而是对 OOP 的概念以及如何利用它来发挥自身优势的介绍。

不同的编程语言有不同的实现方式,并不一定存在绝对更好的方法。在 JavaScript 中,你可以通过多种方式来利用面向对象编程 (OOP) 的特性。

JavaScript 中的对象就像现实生活中的对象一样,它们有属性(properties)和方法(methods)。

你可能听说过“一切皆对象”的说法。虽然这并不完全正确,但即使是非对象的东西,例如基本类型,有时也会表现得像对象一样,因为 JavaScript 会在后台将它们包装成对象。

let name = 'string' // primitive type

let name2 = new String('String object') // objects
Enter fullscreen mode Exit fullscreen mode

面向对象编程的核心思想是,我们并不局限于内置对象,我们可以创建自己的对象。

对象字面量表示法

我们可以使用对象字面量表示法构建自己的对象,并赋予它们我们想要的任何属性和方法。

let userOne = {
    email: 'some@email.com',
    name: 'Pepe',
    login() {
        console.log(this.email, 'has logged in')
    }
}
Enter fullscreen mode Exit fullscreen mode

this关键字位于对象内部时,它指的是对象本身。

我们可以使用点网络来更改对象中的数据。

userOne.name = 'A name'
Enter fullscreen mode Exit fullscreen mode

我们还可以使用括号表示法。

userOne['name'] = 'Another name'
Enter fullscreen mode Exit fullscreen mode

我们还可以使用点号或方括号表示法来创建或定义新的属性或方法,即使它们尚不存在。

userOne.age = 28
Enter fullscreen mode Exit fullscreen mode

然而,我们开始注意到一些问题。最好将所有内容都放在对象字面量表示法中,而不是在代码后面添加新属性,这样所有内容都能被封装起来

此外,如果我们想要创建多个用户对象实例,就需要重复编写大量代码,并且如果用户对象的属性和方法需要更改,而不是继承自同一个数据源,那么修改所有用户对象将会非常繁琐。这时,我们可以利用 JavaScript 的类、构造函数和原型等功能来简化操作。

原型模型与类

JavaScript 本身并没有真正意义上的类。它的底层完全基于原型模型,但 ES6 可以模拟类的概念,让代码更容易理解。这就是我们所说的语法糖。你可以选择使用类或原型模型,接下来我们会解释类和原型模型的工作原理。

课程

类是对象的蓝图,但它们并不具体。我们识别并定义对象将具有哪些特定属性,但我们并不指定这些属性的值。

它的妙处在于,当我们创建实例时,它们已经内置了所有基本功能,我们可以通过参数动态传递值。

要使用类,我们使用关键字class和类名来定义它们。按照惯例,类名首字母大写,并采用驼峰式命名法。类中包含所有数据和功能(属性和方法)。

class User {
}
Enter fullscreen mode Exit fullscreen mode

构造函数

尽管类和对象的语法可能看起来很相似,但它们之间有一个重要的区别,那就是构造函数方法。JavaScript 每次创建类的新实例时都会调用 `constructor()` 方法。

实例是一个对象,它包含类的属性名称和方法,但具有唯一的属性值。

class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}
Enter fullscreen mode Exit fullscreen mode

在构造函数 `constructor()` 方法内部,我们使用this关键字 `new`。在类的上下文中,this`new` 指的是该类的一个实例。

我们不想将数据硬编码到程序中,而是想将其作为参数传递。

要创建新实例,我们使用new关键字。

class User {
    constructor(name, email){
        this.name = name;
        this.email = email;
    }
}

let userOne = new User('el@pepebenitez.dev', 'Pepe')
Enter fullscreen mode Exit fullscreen mode

new关键词有 3 个作用:

  • 创建一个空对象 { }
  • 将值设置this为新的空对象
  • 调用构造函数方法,运行其中的代码,然后返回新实例。

类方法

要使用方法,我们不能在构造函数内部定义它们,而应该在构造函数外部定义。方法之间不能使用逗号。

this我们也可以在方法内部访问关键字。

class User {
    constructor(name, email){
        this.name = name;
        this.email = email;
    }
    logIn(){
        console.log(this.email, 'just logged in')
    }
    logOut(){
        console.log(this.email, 'just logged out')
    }
}

let userOne = new User('el@pepebenitez.dev', 'Pepe')

userOne.logIn()
// el@pepebenitez.dev just logged in
Enter fullscreen mode Exit fullscreen mode

调用实例上的方法和 getter 的语法与调用对象上的方法和 getter 的语法相同——在实例名称后加一个句点,然后是属性或方法名称。对于方法,还必须包含左右括号。

类继承

当多个类共享属性或方法时,它们就成为继承的候选对象——我们可以使用继承来减少需要编写的代码量。

通过继承,您可以创建一个父类(也称为超类),其中包含多个子类(也称为子类)共享的属性和方法。子类通过继承父类的属性和方法来实现这一点。

在类声明中使用 extends 关键字时,子类就可以访问父类的所有方法。除了继承的特性之外,子类还可以拥有自己的属性、getter、setter 和方法。

通过继承,我们可以轻松地将所有基本功能传递给其他类。

class Cat extends Animal {
  constructor(name, usesLitter) {
    super(name);
    this.usesLitter = usesLitter;
  }
}
Enter fullscreen mode Exit fullscreen mode

让我们特别注意一下我们的新关键词:extendssuper

extends关键字使得父类的方法可以在子类中使用。

super关键字会调用父类的构造函数。在本例中,`super(name)` 将 `Cat` 类的 `name` 参数传递给 `Animal` 类的构造函数。

usesLitter 是 Cat 类特有的一个新属性,因此我们在 Cat 构造函数中设置它。

IMPORTANT在构造函数中,必须先调用 `super` 方法才能使用 `this` 关键字——否则,JavaScript 会抛出引用错误。为了避免引用错误,最佳实践是在子类构造函数的第一行调用 `super`。

您可以在这里找到更多关于 Javascript 课程的资源:

类基本语法

类 - JavaScript | MDN

JavaScript 类

原型模型

请记住,我们只是在使用模拟类。在 class 关键字出现之前,JavaScript 原型模型是创建或模拟类的原始方法,而 JavaScript 底层仍然在使用原型模型。

有些人不喜欢在 JavaScript 中使用类。

ES6 中的“类”是新的“坏”部分吗?

因此,了解原型模型的工作原理将有助于我们成为更优秀的开发者,拥有更大的灵活性,并在调试方面更加高效。

构造函数

我们仍然需要使用构造函数。构造函数是用来创建对象的。

function User() {}

let userOne = new User()
Enter fullscreen mode Exit fullscreen mode

我们仍然可以使用该new关键字。它仍然执行相同的操作(创建一个新对象,将this关键字的上下文绑定到该对象,并将其传递给构造函数)。我们也可以访问该this关键字。

function User() {
    this.name = '';
    this.email = '';
    this.online = false;
    this.logIn = function() {
        console.log(this.email, 'has logged in')
    };
}

let userOne = new User()
Enter fullscreen mode Exit fullscreen mode

但是,我们通常不会把方法放在构造函数里。这时我们就需要用到原型属性。

原型属性

所有对象都有一个原型属性。原型就像一张映射表,记录了对象类型及其方法。我们使用原型属性来存储和定义我们的方法。

function User() {
    this.name = '';
    this.email = '';
    this.online = false;
}

User.prototype.logIn = function(){
    this.online = true;
    console.log(this.email, 'has logged in')
}

let userOne = new User()
Enter fullscreen mode Exit fullscreen mode

当我们使用类时,这一切都在后台进行。

原型继承

我们还可以将继承与原型结合使用。

function Admin(...args){ // here we are using a rest parameter
    console.log(args)
}

let admin = new Admin('admin name', 'admin@email.com')
Enter fullscreen mode Exit fullscreen mode

我们希望从 Admin 构造方法中调用 User 构造方法,以便它继承基本功能。

function User() {
    this.name = '';
    this.email = '';
    this.online = false;
}

function Admin(...args){ // here we are using a rest parameter
    User.apply() // takes the user constructor function and runs it
}

let admin = new Admin('admin name', 'admin@email.com')
Enter fullscreen mode Exit fullscreen mode

在 apply 方法中,我们需要传递两个参数:

  • 的上下文是什么this?听起来很奇怪,但我们只需要传递它,this因为我们在构造函数中调用它,所以this在这个上下文中,它指的是我们将新的继承属性和方法应用到的实例。
  • 我们实际收到的参数以数组形式呈现。
function User() {
    ...
}

function Admin(...args){ // here we are using a rest parameter
    User.apply(this, args) // takes the user constructor function and runs it
    this.role = 'Administrator'
}

let admin = new Admin('admin name', 'admin@email.com')
Enter fullscreen mode Exit fullscreen mode

如果要继承方法,可以使用子对象的 prototype 属性。

Admin.prototype = Object.create(User.prototype)
Enter fullscreen mode Exit fullscreen mode

你可以看出,使用类可以使一些事情变得更简单更容易,但了解实际发生的事情仍然非常重要。

指导原则

谈到面向对象编程(OOP),很难不提及SOLID原则。这些原则旨在指导我们设计代码结构。其中两个重要的目标是:每个对象只承担一个职责,并且每个对象都能独立运行,不依赖于其他对象。

单一职责原则

最重要的原则之一是单一职责原则,它指出一个类(或对象)应该只承担一项职责。这并不意味着一个对象只能做一件事,而是指一个对象所做的每一件事都应该属于同一项职责。

松散耦合对象

显然,我们所有的对象都是为了协同工作,最终构成我们的应用程序。但是,您应该注意确保每个对象尽可能独立运行。紧耦合的对象是指彼此依赖程度过高的对象,移除或更改其中一个对象将导致您必须完全更改另一个对象。

您可以点击此处阅读更多关于SOLID原则的内容:

让你成为优秀 JavaScript 开发人员的 5 项原则

SOLID:面向对象设计的前 5 个原则(使用 JavaScript)

奖金

静态方法

有时,你可能希望一个类拥有一些在单个实例中不可用的方法,但你可以直接从类中调用这些方法。你可以使用 static 关键字来定义静态方法,这些方法只能从类中调用,而不能从实例中调用。

class Animal {
  constructor(name) {
    this._name = name;
    this._behavior = 0;
  }

  static generateName() {
    const names = ['Angel', 'Spike', 'Buffy', 'Willow', 'Tara'];
    const randomNumber = Math.floor(Math.random()*5);
    return names[randomNumber];
  }
}
Enter fullscreen mode Exit fullscreen mode

由于使用了 static 关键字,我们只能通过将其附加到 Animal 类来访问 .generateName()。

console.log(Animal.generateName()); // returns a name
const tyson = new Animal('Tyson'); 
tyson.generateName(); // TypeError
Enter fullscreen mode Exit fullscreen mode

方法链

用更少的代码调用多个方法的小技巧。

userOne.logIn().logOut()
Enter fullscreen mode Exit fullscreen mode

为了实现这一点,我们需要返回对象的实例。实例存储在关键字中this。我们只需要this在每个方法的末尾返回该实例即可。

class User {
    constructor(name, email){
        this.name = name;
        this.email = email;
    }
    logIn(){
        console.log(this.email, 'just logged in')
        return this
    }
    logOut(){
        console.log(this.email, 'just logged out')
        return this
    }
}
Enter fullscreen mode Exit fullscreen mode

关于 Javascript 的实用资源

JavaScript | MDN

freeCodeCamp.org

JavaScript教程:免费学习JavaScript | Codecademy

JavaScript 代码


嗨!我叫佩佩👾,来自中美洲的巴拿马🌴🌞🌴。你可以在领英推特GitHub上找到我。

  • 如果您觉得这篇文章有用,欢迎分享!
  • 如果您有任何问题、建议或意见,请随时给我留言!
文章来源:https://dev.to/elpepebenitez/object-oriented-programming-in-javascript-51p9