学习 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() {}
}
使用new
关键字
var objectName = new Object()
使用create( )
方法
var newObjectName = Object.create(existingObjectName)
访问对象的属性
访问对象属性的方法有很多种。本文概述了几种常用的方法,但您也可以使用 for..in 循环遍历对象属性,也可以访问嵌套循环的属性(实现这一点只需使用点运算符,但您需要添加一个额外的点)。
点运算符(对于设置和删除属性也很有用)
在 JavaScript 中,可以使用点运算符访问对象字面量。要访问任何属性,应首先提及对象的名称,然后是点运算符,然后是封装在该对象中的属性的名称。
这里我们可以看到点运算符的语法:
objectName.functionName()
以下是如何使用点运算符访问属性的示例:
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
使用方括号(对于设置和删除属性也很有用)
访问值的另一种方法是使用方括号[ ]
。要访问的属性名称以字符串形式写在方括号内。
这里我们可以看到方括号方法的语法:
objectName['functionName']()
以下是如何使用方括号访问属性的示例:
/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"
有用的关键字: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
}
从上面可以看出:
- 关键字function用于定义函数。
- 构造函数名称应该大写,就像上面代码片段中的 FunctionName 一样。
- 该函数的主体基本上是函数的构造函数部分,因为它通过将属性设置为等于传递给函数的各个参数来初始化属性。
以下是构造函数的示例:
function Employee(_name, _age, _designation){
this.name = _name
this.age = _age
this.designation = _designation
}
请注意,所有创建的对象都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)
这里我们可以看到,当 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
}
构造函数和基于类的实现之间的区别之一是,在前者中,函数主体充当构造函数,其中定义了所有属性,而在后者中,在类内部定义了一个单独的构造函数,用于初始化属性。
从类创建对象实例
这里我们可以看到如何从类创建对象实例的示例:
//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)
由于employee
本身就是一个构造函数,因此从类创建对象实例的方法与 ES5 版本完全相同。new
关键字 用于初始化一个新对象。然后,employeeObj
该constructor
方法将为该对象运行,并将传递给它的值赋给属性。
在类中定义方法
每当在类内部声明一个方法时,它都会在该类的原型上定义。这意味着,每当对象实例访问它时,它都会从相应类的原型中获取。
以下是一个例子:
//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
}
}
以下是上述代码中发生的情况:
- 该
getAge
函数在第 15 行的构造函数外部定义。 - 所有这些方法都存储在员工的原型对象中。
- 因此,新对象(例如
employeeObj
)可以访问类中定义的所有方法。 employeeObj
当该方法被调用时,getAge
它取自 employee.prototype。
后续步骤
虽然 JavaScript 可能不被认为是一种面向对象编程语言 (OOP),但使用 ES6 版本(因为使用了类)会让你体会到使用更传统的面向对象编程语言(例如 C/C++)编写代码的感觉。ES5 和 ES6 之间的主要区别在于语法的增加和简化。
这篇文章只是粗略地介绍了面向对象的 JavaScript。还有很多内容需要介绍:静态方法、属性保护以及数据封装等等。如果您有兴趣了解更多细节,可以学习JavaScript 中面向对象编程的所有基本知识。
进一步阅读
文章:成为前端开发人员的路线图
文章:Web 开发初学者指南
免费课程:从零开始学习 Web 开发
课程:Web 开发:入门
鏂囩珷鏉ユ簮锛�https://dev.to/educative/learn-javascript-oop-a-primer-for-web-development-dl8