学习 JavaScript OOP:Web 开发入门

2025-06-08

学习 JavaScript OOP:Web 开发入门

当有人提到 OOP 语言时,人们可能不会想到 JavaScript,但事实上它对 OOP 有很好的支持 - 只是需要先了解它的复杂性。

如果您使用 JavaScript 编写代码,熟悉 OOP 原则可以让您的生活更轻松,原因如下:

  • 使用对象和类时,调试代码会更容易。
  • 您可以使用封装和继承等技术。
  • 您将更容易被聘用在使用 OOP 原则编写代码的团队中。

本文将学习 ES5 和 ES6 中面向对象 JavaScript 的基础知识,以便了解两者之间的比较以及 JavaScript 如何趋向于 OOP 风格。首先,本文将介绍 ES5 中的 OOP 以及你需要了解的基础知识,例如对象、构造函数以及访问对象属性的相关语法。

文章的后半部分将探讨 ES6 中的 OOP 以及类、原型属性和方法的使用。如果您有兴趣深入了解 JavaScript 中的 OOP 以及文中提到的概念,可以查看学习 JavaScript 中的 OOP


什么是OOP(面向对象编程)?

如果您熟悉其他语言(例如 C# 和 Java),那么您可能听说过面向对象编程 (OOP) 这个术语。

面向对象编程是一种编程风格,而非一种工具。正因如此,尽管它是一种较为古老的编程风格,却依然广受欢迎且被广泛使用。这种风格将程序分解成多个可以相互通信的对象片段。每个对象都由一组属性定义,这些属性可以通过各种操作进行访问和修改。

替代文本

上图是现实世界中员工记录的示例,其中每个员工都可以被视为一个“对象”,并且由于每个员工都有姓名、年龄和职位,因此这些都可以被视为该员工的属性。

JavaScript 中的 OOP(ES5)

JavaScript 中的 OOP 与其他语言的 OOP 工作方式不同。因此,如果您熟悉其他语言中的 OOP,请务必暂时将其放在一边,因为坚持这些概念可能会让您感到困惑。

你可能已经注意到,其他语言(例如 C++、Java 和 C#)使用关键字 class 来定义类。类的每个实例都拥有属性和方法。在这种情况下,类充当了对象的蓝图。

JavaScript 与其他语言的不同之处在于,它无需使用类即可实现面向对象编程(稍后会详细介绍)。在 ES2015 版本发布之前,JavaScript 仍然依赖于基于原型的编程。在这种编程风格中,对象封装了属性,即方法和数据,而不是类。您可以随时向此对象添加新属性。因此,对象可以是一个独立的个体,而不是类的实例,这意味着如果您想要一个对象,只需轻松创建一个,而无需先创建一个类。

替代文本

基于原型和基于类的 OOP 都有其优点和缺点。

基于原型更为直接,因为您不需要事先创建蓝图,而蓝图需要在创建对象之前预先规划所需的属性类型。

由于无需创建类,您可以直接创建对象。这也提供了灵活性;因此,在使用对象时可以轻松快速地对其进行任何更改。

虽然基于原型的编程具备这些优势,但由于容易发生突然更改,因此出错的风险更高。而基于类的方法中,蓝图会预先制定计划,从而降低出现错误的可能性。

JavaScript 中的对象

对象是 JavaScript 的重要组成部分,因为 JavaScript 中几乎所有东西都是对象。例如,函数、数组、正则表达式、日期,甚至布尔值和字符串等数据类型,如果使用关键字 new 声明,都可以被视为 JavaScript 对象。

什么是对象?

在现实生活中,对象随处可见,因此这些现实场景也可以映射到面向对象的代码中。

让我们看一个如何使用对象的例子:假设您有三个需要找到面积的形状:正方形、长方形和圆形。

如果您要编写代码来计算每个面积,您会怎么做?

在面向对象编程 (OOP) 风格中,您可以通过为每种形状(正方形、矩形和圆形)创建对象来转换代码。每个对象都有自己的一组属性,包括:

  • 数据值
  • 功能

替代文本

我们需要长度、宽度和半径。这些值将被封装在该特定形状的对象中。

类似地,还需要一个计算面积的函数。这也将作为对象属性的一部分封装在对象中。

替代文本

如何创建对象字面量

可以创建一个对象文字:

  • 在声明中使用数字括号 {...}。
  • 使用 new 关键字。
  • 基于现有对象,使用 create() 方法。

所有这些方法都做同样的事情。语法如下:

使用数字括号

var objectName = { 

 //properties defined
 propertyName1 : propertyValue1,
 propertyName2 : propertyValue2,
 functionName() {}

}
Enter fullscreen mode Exit fullscreen mode

使用new关键字

var objectName = new Object()
Enter fullscreen mode Exit fullscreen mode

使用create( )方法

var newObjectName = Object.create(existingObjectName)
Enter fullscreen mode Exit fullscreen mode

访问对象的属性

访问对象属性的方法有很多种。本文概述了几种常用的方法,但您也可以使用 for..in 循环遍历对象属性,也可以访问嵌套循环的属性(实现这一点只需使用点运算符,但您需要添加一个额外的点)。

点运算符(对于设置和删除属性也很有用)

在 JavaScript 中,可以使用点运算符访问对象字面量。要访问任何属性,应首先提及对象的名称,然后是点运算符,然后是封装在该对象中的属性的名称。

这里我们可以看到点运算符的语法:

objectName.functionName()
Enter fullscreen mode Exit fullscreen mode

以下是如何使用点运算符访问属性的示例:

Here’s an example of how to access properties using the dot operator:

//creating an object named shape

var shape = {
 //defining properties of the object
 //setting data values
 name : 'square',
 sides : 4

}

//accessing the properties using the dot operator

console.log("Name is:", shape.name) //using dot operator to access "name"

console.log("Number of sides are:", shape.sides) //using dot operator to access "sides
Enter fullscreen mode Exit fullscreen mode

使用方括号(对于设置和删除属性也很有用)

访问值的另一种方法是使用方括号[ ]。要访问的属性名称以字符串形式写在方括号内。

这里我们可以看到方括号方法的语法:

objectName['functionName']()
Enter fullscreen mode Exit fullscreen mode

以下是如何使用方括号访问属性的示例:

/creating an object named shape

var shape = {
 //defining properties of the object
 //setting data values
 name : 'square',
 sides : 4

}

//accessing the properties using square brackets

console.log("Name is:", shape['name']) //using square brackets to access "name"
console.log("Number of sides are:", shape['sides']) //using square brackets to access "sides"
Enter fullscreen mode Exit fullscreen mode

有用的关键字:Get、Set、This

Get
关键字get将对象属性绑定到一个函数。当查找此属性时,将调用 getter 函数。getter 函数的返回值决定返回哪个属性。

设置
语法set将对象属性绑定到当尝试设置该属性时要调用的函数。


this关键字指向一个对象,以便您可以访问对象内的属性。它还可以用于设置对象内属性的值。

函数作为对象

构造函数

在 JavaScript 中,函数也属于对象。这是因为函数和对象一样,拥有自己的属性和方法。函数也可以用来构造对象,这类函数被称为构造函数。

构造函数本质上消除了为类似任务创建单独对象字面量的需要。它们很有用,因为你经常会遇到不知道要创建多少个对象的情况;构造函数提供了一种高效地创建所需数量对象的方法。

以下是实现构造函数的语法:

function FunctionName(parameter1, parameter2,...){
   //all the properties of the object are initialized here
   //functions to be provided by objects are defined here
}
Enter fullscreen mode Exit fullscreen mode

从上面可以看出:

  • 关键字function用于定义函数。
  • 构造函数名称应该大写,就像上面代码片段中的 FunctionName 一样。
  • 该函数的主体基本上是函数的构造函数部分,因为它通过将属性设置为等于传递给函数的各个参数来初始化属性。

以下是构造函数的示例:

function Employee(_name, _age, _designation){
  this.name = _name
  this.age = _age
  this.designation = _designation
}
Enter fullscreen mode Exit fullscreen mode

请注意,所有创建的对象都Employee将包含属性名称、年龄和名称,其中关键字this可以分配特定值,即使它们是同一属性的一部分。

原型对象

原型对象是向构造函数添加新方法/属性的一种更简单的方法。

对象中的原型属性

除了你创建的属性之外,还有一个隐藏属性,称为[[Prototype]]property,它存在于每个由构造函数创建的对象中。prototype 属性要么指向另一个对象,要么为 null。

以下是使用 Prototype 属性的示例:

//Shape object

var Shape={
 name: 'Rectangle',
 sides: 4
}

//Rectangle object
var Rectangle = {
 length: 3,
 width: 5
}

//setting [[Prototype]] of Rectangle equal to Shape
Rectangle.__proto__ = Shape

//creating an object instance using Shape and Rectangle

console.log("Name of shape is:",Rectangle.name)
console.log("Number of sides are",Rectangle.sides)
console.log("Length is:",Rectangle.length)
console.log("Width is:",Rectangle.width)
Enter fullscreen mode Exit fullscreen mode

这里我们可以看到,当 Rectangle 的原型属性设置为 Shape 时,它​​能够访问 Shape 中的所有属性。如果在对象中找不到某个属性,例如name在 Rectangle 中找不到该属性,JavaScript 会自动从该对象的原型 Shape 中获取该属性。这被称为原型继承,其中第 20 行和第 21 行被称为继承属性;这基于原型链的概念。


ES6 中的面向对象 JavaScript

JavaScript ES6 带来了一些新功能和改进。其中一项改进就是引入了关键字 class。您可以在这里探索 ES6 的所有其他细微差别

在 JavaScript ES5 中,函数构造函数用于实现类的概念。然而,在 ES6 版本中,使用了 class 关键字,它简化了实现相同概念的语法,使其更易于理解。

在 JavaScript ES6 中声明一个类

语法如下:

class ClassName {
  constructor() {
    //initializing class properties
  }
  //class methods defined
}
Enter fullscreen mode Exit fullscreen mode

构造函数和基于类的实现之间的区别之一是,在前者中,函数主体充当构造函数,其中定义了所有属性,而在后者中,在类内部定义了一个单独的构造函数,用于初始化属性。

从类创建对象实例

这里我们可以看到如何从类创建对象实例的示例:

//creating a class named employee

class employee{
 //creating the constructor function

 constructor(name,age,designation){
   //all properties defined as they were in the constructor function

   this.name = name
   this.age = age
   this.designation = designation
   this.displayName = function() {
     console.log("Name is:",this.name)
   }
 }
}

//creating an object instance named "employeeObj"

var employeeObj = new employee('Joe',22,'Developer')

//displaying the properties of employeeObj

employeeObj.displayName()
console.log("Age is",employeeObj.age)
console.log("Designation is:",employeeObj.designation)
Enter fullscreen mode Exit fullscreen mode

由于employee本身就是一个构造函数,因此从类创建对象实例的方法与 ES5 版本完全相同。new关键字 用于初始化一个新对象。然后,employeeObjconstructor方法将为该对象运行,并将传递给它的值赋给属性。

在类中定义方法

每当在类内部声明一个方法时,它都会在该类的原型上定义。这意味着,每当对象实例访问它时,它都会从相应类的原型中获取。

以下是一个例子:

//creating a class named employee

class employee{

 //creating the constructor function

 constructor(name,age,designation){
   //all properties defined as they were in the constructor function

   this.name = name
   this.age = age
   this.designation = designation
   this.displayName = function() {
     console.log("Name is:",this.name)
   }
 }
 //defining methods in a class

 //getAge method returning the age of the current object
 getAge(){
   return this.age
 }
}
Enter fullscreen mode Exit fullscreen mode

以下是上述代码中发生的情况:

  • getAge函数在第 15 行的构造函数外部定义。
  • 所有这些方法都存储在员工的原型对象中。
  • 因此,新对象(例如employeeObj)可以访问类中定义的所有方法。
  • employeeObj当该方法被调用时,getAge它取自 employee.prototype。

后续步骤

虽然 JavaScript 可能不被认为是一种面向对象编程语言 (OOP),但使用 ES6 版本(因为使用了类)会让你体会到使用更传统的面向对象编程语言(例如 C/C++)编写代码的感觉。ES5 和 ES6 之间的主要区别在于语法的增加和简化。

这篇文章只是粗略地介绍了面向对象的 JavaScript。还有很多内容需要介绍:静态方法、属性保护以及数据封装等等。如果您有兴趣了解更多细节,可以学习JavaScript 中面向对象编程的所有基本知识。

进一步阅读

文章:成为前端开发人员的路线图

文章:Web 开发初学者指南

文章:Web 开发人员常见问题解答

免费课程:从零开始学习 Web 开发

课程:Web 开发:入门

鏂囩珷鏉ユ簮锛�https://dev.to/educative/learn-javascript-oop-a-primer-for-web-development-dl8
PREV
系统设计基础:什么是 CAP 定理?
NEXT
Java interview prep: 15 Java interview questions Q1: What is meant by Java being platform independent? Q2: Explain the concepts of JRE, JDK, and JVM Q3: How would you mark an entity package private in Java? Q4: Why should you avoid the finalize() method in the Object class? What are some alternatives? Q5: Can you change the contents of a final array as shown in the code snippet below? Q6: Explain the difference between an interface and an abstract class? When should you use one or the other? Q7: What is polymorphism? Can you give an example? Q8: Can the main method be overloaded? Q9: How can you pass multiple arguments to a method on each invocation call? Q10: Can a semaphore act as a mutex? Q11: Explain the Externalizable interface Q12: If a code block throws more than one exception, how can it be handled? Q13: If you were to use a set, how would you determine between a HashSet and a TreeSet? Q14: What are a few ways you can improve the memory footprint of a Java application? Q15: What is the best way to implement a singleton class? Gaining a mastery