JavaScript 中的 OOPS,包含易于理解的示例🔥🔥

2025-05-25

JavaScript 中的 OOPS,包含易于理解的示例🔥🔥

介绍

在本文中,我们将学习和使用 JavaScript 中的面向对象编程 (OOP) 概念。

如果您来自面向对象编程语言(如 C++ 或 Java),您可能希望在 javascript 中使用基于类的语法。

如果您不了解 OOP,请不要担心,我将通过易于理解的示例向您解释所有概念。

很高兴有

在 ES6 发布之前,我们一直使用构造函数来运用 OOP 概念。但现在,借助 ES6 类,我们可以使用更类似于 C++ 或 Java 的语法来运用 OOP 概念。
(ES6 类在幕后使用了相同的构造函数)

太酷了

但是面向对象编程是什么?🤔

这是 OOP 的流行定义

面向对象编程(OOP)是一种基于对象概念的编程范例。

意思是?🙄

这意味着我们在 OOP 语言中实现的一切都是通过对象来实现的,这里的对象定义了现实世界的实体,如学生或汽车(更多详细信息即将推出)。

好的!但是我们为什么需要 OOP?

好问题!

开发 OOP 的主要目标是组织代码结构。使用 OOP,你可以编写更模块化、更易于维护的代码。你可以将代码与现实世界的实体关联起来。

通过使用 OOP,您可以确保只有一组代码的授权成员才能被其他成员访问。这使得您的代码完全安全,可以防止未经身份验证的访问(在代码内部)。

得到它??

现在,让我们逐步了解面向对象编程的主要概念。

目的

正如我上面提到的,对象就像现实生活中的实体一样。它们有自己的属性和方法。

假设一辆汽车是一个对象。它有很多特性,例如颜色、公司名称、模式名称和价格等等。我们可以在汽车上执行启动、刹车和停止等操作。在这里,汽车的特性是属性,而操作是方法。

如果您使用 javascript 有一段时间了,您可能会在代码中多次使用对象,但可能不是以 OOP 的方式。

让我在这里创建一个用户对象。

const user = {
  name: 'Nehal Mahida',
  userName: 'nehal_mahida',
  password: 'password:)',
  login: function(userName, password) {
    if (userName === this.userName && password === this.password) {
      console.log('Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  },
};


user.login('nehal', 'nehal');
user.login('nehal_mahida', 'password:)');

// Authentication Failed!!
// Login Successfully
Enter fullscreen mode Exit fullscreen mode

上面的代码非常直观。我创建了一个用户对象,它拥有一些属性以及用户可以执行的操作。

没什么新鲜事吧?

让我们了解更多 OOP 概念。

班级

类是现实生活中实体的蓝图。它描述了对象的外观、特性以及我们可以对其执行的操作。

类只是一个模板。您无法对其执行任何操作。请将类视为您的网站用户体验设计(线框图)。您创建它是为了了解您的网站 UI 最终会是什么样子。用户无法像在实际网站上那样与您的线框图进行交互。

我们从一个类实例化一个对象。我们可以创建一个类的多个实例。

让我们举个例子。

class User {
  #password;
  constructor(name, userName, password) {
    this.name = name;
    this.userName = userName;
    this.#password = password;
  }

  login(userName, password) {
    if (userName === this.userName && password === this.#password) {
      console.log('Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  }

  setPassword(newPassword) {
    this.#password = newPassword;
  }
};

const nehal = new User('Nehal Mahida', 'nehal_mahida', 'password:)');
const js = new User('JavaScript', 'js', 'python:)');


nehal.login('nehal_mahida', 'password:)'); // Login Successfully
js.login('js', 'python:)'); // Login Successfully

console.log(nehal.name); // Nehal Mahida
console.log(nehal.password); // undefined
console.log(nehal.#password); // Syntax Error

nehal.setPassword('new_password:)');
nehal.login('nehal_mahida', 'password:)'); // Authentication Failed!!
nehal.login('nehal_mahida', 'new_password:)'); // Login Successfully
Enter fullscreen mode Exit fullscreen mode

这里我创建了一个名为 的类User,它有一些属性和方法。然后我使用new User()并传递所需属性的值来创建该类的实例。

您是否看到constructor我们在代码中从未调用过的一个方法?

事实上,该方法被称为🙄

当我们使用关键字 javascript 从类创建对象时,new内部会调用构造函数方法,该方法初始化类的公共和私有属性。此处的对象可以访问类的所有公共属性和方法。

什么是publicprivate属性??

默认情况下,类中声明的所有属性都是公共的,这意味着您可以从类外部调用和修改它们。您可以在构造函数内部或外部声明公共属性。这里的nameuserName是公共属性。

那么私人的呢?

再看一下代码。你注意到密码写在了构造函数方法的外面,并以 为前缀了吗#

Hash( #) 表示此属性是类的私有属性,只有在类内部声明的方法才能访问它。私有属性应在使用前声明。

当我尝试打印密码时,我得到的undefined结果是我没有任何名为“密码”的成员,然后我尝试使用“#password”,但出现语法错误,因为“#password”是私有的。

要打印/修改私有属性,我们需要getter/setter方法。这里我创建了一个设置新密码的方法。

以下概念是 OOP 语言的四大支柱。

封装

封装的定义是将数据和方法绑定到一个单元中,以防止外部访问。就像药丸的药衣内含有药物一样。

在类的上下文中,某些属性不能从类外部直接访问。您需要调用负责这些属性的方法。

听起来很熟悉?

是的,你猜对了。这就像为我们在类中声明的私有属性创建一个getter/setter方法。

在上面的例子中,我们已经使用了封装。我们将私有属性password与公共方法(逻辑上)绑定setPassword()。此外,还有一个 getter 方法,用于返回私有属性的当前值。

抽象

人们常常将封装抽象相混淆。抽象比封装更进一步。抽象的定义是只展示本质的东西,隐藏内部实现。

让我们以汽车为例。在汽车上,我们可以执行一些操作,例如启动、刹车和停止。每当您调用其中一个操作时,它都会返回一些结果。这些操作包含一些对您隐藏的子操作,但您无需关心这些子操作。

这就是汽车公司如何使用功能抽象来为客户提供流畅的体验。

让我们再举一个抽象的例子。假设你在前端项目中使用某个第三方 React 组件。该组件提供了许多 props 和方法供你自定义。这个组件本身并没有什么特别之处,它内部使用相同的 HTML 标签、CSS 和 JavaScript。但现在你无需担心这些事情。你只需要根据需求设置 props 和调用方法即可。这就是抽象。

让我们开始编码吧🤩

class User {
  name;
  email;
  #password;
  constructor() {}

  #validateEmail(email) {
    // check email is valid or not.
    return true;
  }

  #validatePassword(password) {
    // check password is satisfying the minimum requirements or not.
    return true;
  }

  signUp(name, email, password) {
    let isValidated = false;
    isValidated = this.#validateEmail(email);
    isValidated &&= this.#validatePassword(password);

    if (isValidated) {
      this.name = name;
      this.email = email;
      this.#password = password;
      // add user in your db.
      console.log('User registered successfuly');
    } else {
      console.log('Please enter correct Details!!');
    }
  }

  login(email, password) {
    if (email === this.email && password === this.#password) {
      console.log('Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  }

  #isRegisteredUser(email) {
    // check user is registered or not.
    return true;
  }

  resetPassword(email, newPassword) {
    if (this.#isRegisteredUser(email)) {
        this.#password = newPassword;
        console.log('Operation performed successfully');
    }
    else {
      console.log('No account found!');
    }
  }
};

const nehal = new User();
nehal.signUp('Nehal Mahida', 'nm@gmail.com', 'password:)'); // User registered successfuly

nehal.#validateEmail('nm@gmail.com'); // Syntax Error.

nehal.login('nm@gmail.com', 'password:)'); // Login Successfully
nehal.resetPassword('nm@gmail.com', ''); // Operation performed successfully
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,我们引入了一些私有方法。这些方法执行一些操作,并且不会暴露给类的外部。

这些方法由公开可用的方法调用。

作为开发人员,我只需要提供从 UI 收到的详细信息并调用负责的方法。

在Java等 OOP 语言中,我们有抽象类接口的概念。但这在 JavaScript 中是不可能的。

否则,我们可以创建一个抽象类,并且该类可以被另一个类使用来实现类似的功能。

所以基本上我们可以说我们正在使用封装来实现抽象。😊

遗产

当一个类继承了另一个类的属性和方法时,在 OOP 中称为继承。继承了属性的类称为子类被继承属性的类称为

为什么需要继承?

继承是面向对象编程 (OOP) 中一个非常重要的概念。继承的主要优势在于可重用性。当子类继承父类时,我们无需重复编写相同的代码。当我们需要更改属性时,只需在父类中进行更改,所有子类都会自动继承该更改,从而提高代码的可靠性。继承还能提高代码的可读性

让我们编码...

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

  login(email, password) {
    if (email === this.email && password === this.#password) {
      console.log('Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  }

  resetPassword(newPassword) {
    this.#password = newPassword;
  }

  logout() {
    console.log('Logout Successfully');
  }
}

class Author extends User {
  #numOfPost;

  constructor(email, password) {
    super(email, password);
    this.#numOfPost = 0;
  }

  createPost(content) {
    // add content to your DB. :)
    this.#numOfPost++;
  }

  getNumOfPost() {
    return this.#numOfPost;
  }
}

class Admin extends User {
  constructor(email, password) {
    super(email, password);
  }

  removeUser(userId) {
    // remove this userId from your DB.
    console.log('User Removed successfully.');
  }
}

const nehal = new Author('nm@gmail.com', 'password:)');
nehal.login('nm@gmail.com', 'password:)');
nehal.createPost('I hope you are enjoying this article. Don\'t forget to leave your feedback. :)');
nehal.createPost('I am tired, Do you wanna buy me a coffee? :)');
console.log(nehal.getNumOfPost()); // 2

const json = new Admin('jason@gmail.com', '[Object] [object]');
json.login('jason@gmail.com', '[Object] [object]');
json.resetPassword('{id: 1}');
json.login('jason@gmail.com', '{id: 1}');
json.removeUser(12);
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,Author和类使用关键字Admin继承了类的属性。Userextendssuper

关键字extends用于在两个类之间建立父子关系。在第一种情况下,Author成为子类,User成为父类。

子类可以访问超类的所有公共和受保护成员。此外,它还可以拥有自己的属性和方法。这就是我们通过继承实现可重用性的方式。

关键字super是一个特殊的关键字。调用子类的构造函数会调用父类的构造函数。这就是我们在和类super中初始化属性的方式AuthorAdmin

子类也可以覆盖父类的方法。这就引入了多态的概念。

多态性

多态意味着“不止一种形态”。像我们一样,软件工程师可以同时处理前端、后端、DevOps 甚至测试。😅

多态性有两种类型。

  1. 编译时多态性
  2. 运行时多态性

函数重载是编译时多态的一种。在这里,我们创建多个具有相同名称但参数或类型不同的函数。

JavaScript 不支持函数重载,因为如果创建同名函数,JavaScript 将用前面的函数覆盖最后定义的函数。

方法覆盖是一种运行时多态性。还记得我说过,可以在子类中覆盖父类的方法吗?这就是方法覆盖。

我们来举个例子。

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

  login(email, password) {
    if (email === this.email && password === this.password) {
      console.log('Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  }
}

class Author extends User {
  #numOfPost;

  constructor(email, password) {
    super(email, password);
    this.#numOfPost = 0;
  }

  createPost(content) {
    // add content to your DB. :)
    this.#numOfPost++;
  }

  getNumOfPost() {
    return this.#numOfPost;
  }
}

class Admin extends User {
  constructor(email, password) {
    super(email, password);
  }

  login(email, password) {
    // add extra layer of security as this is an admin account.
    const isValidAdmin = true; // we can have some 2FA type security check here.
    if (email === this.email && password === this.password && isValidAdmin) {
      console.log('Admin Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  }

  removeUser(userId) {
    // remove this userId from your DB.
    console.log('User Removed successfully.');
  }
}

const nehal = new Author('nm@gmail.com', 'password:)');
nehal.login('nm@gmail.com', 'password:)'); // Login Successfully

const json = new Admin('jason@gmail.com', '[Object] [object]');
json.login('jason@gmail.com', '[Object] [object]'); // Admin Login Successfully
Enter fullscreen mode Exit fullscreen mode

这里,AuthorAdmin都继承了 UserUser类。这两个类都包含loginUser 类的方法。现在我需要对管理员帐户进行一些额外的验证,因此我在 Admin 类中创建了一个 login 方法。它将覆盖父类的login方法。

当类的对象Admin调用该方法时,它将引发对该类方法的login函数调用loginAdmin

这就是我们如何通过方法覆盖实现多态性。

就这样。我们已经讲完了 JavaScript 中 OOP 的所有概念。🤩

:以上所有信息均基于我的知识和研究。如果您发现任何错误,请在评论区指正。祝您学习愉快 🙂

如果您喜欢这篇文章,请分享并标记🔖这篇文章!

如果您使用 Twitter,请关注我,我会分享学习 Web 开发的精彩资源。🙏🏻

欢迎您提供反馈。🤗

🏃‍♂️ 让我们联系👇

🕊 Twitter(Twitter 上见😃)

Github

🙌 支持

如果您喜欢我的文章,请考虑喝杯咖啡支持我。☕

文章来源:https://dev.to/nehal_mahida/oops-in-javascript-with-easy-to-understand-examples-2ppn
PREV
你必须知道的 7 个 JavaScript 数据结构
NEXT
如何不更新 React 中的状态!!