网页 综合 更新时间 2026-10-15 06:09:04

使用类 - JavaScript | MDN

自动蜘蛛 developer.mozilla.org 正文约 2466 字
HTML: Markup language
CSS: Styling language
JavaScript: Scripting language
Web APIs: Programming interfaces
Learn web development
Get to know MDN better
此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。
View in English Always switch to English
JavaScript 是一个基于原型的语言——一个对象的行为取决于它自身的属性及其原型的属性。但是,对类来说,相较于与其他面向对象的语言,譬如 Java,创建对象的多层级结构及其属性的继承关系需要更多的代码行。本节,我们将展示如何利用类创建对象。
在许多其他语言中,类(或构造函数)与对象(或实例),是两个不同的概念。在 JavaScript 中,类可以看作是已有的原型继承机制的一种抽象——所有语法都可以转换为原型继承。类本身也是普通的 JavaScript 值,它们有其自己的原型链。事实上,大多数 JavaScript 纯函数都可用作构造函数——你可以用 new 运算符来调用一个构造函数以创建出一个新的对象。
本教程中,我们将研究类模型的方方面面。如果你想深入了解底层原型系统,请参阅继承与原型链指南。
本章节假定你已熟悉 JavaScript 并能使用常规的对象。
如果你已经有动手实践过 JavaScript 的经历,或是阅读指南一路过来,你可能已经用过类了,即便你还没有自己创建过。例如,你可能会对这个很熟悉:
在第一行,我们创建了一个 Date 类的实例,并将其命名为 bigDay。在第二行,我们在 bigDay 实例上调用了 toLocaleDateString() 方法,其会返回一个字符串。接下来,我们对比了两个数字:一个来自于方法 getTime() 的返回值,另一个来自于对 Date 类本身的直接调用,本例为 Date.now()。
Date 是一个 JavaScript 的内建类。从这个例子中,我们可以得到一些关于类的基本概念:
如果你用过早于 ES6 的版本,你可能更熟悉使用函数作为构造函数。上面的模式大致可以转换为以下函数构造器:
备注:私有字段和方法是类中的新特性,在函数构造器中并没有与之等价的语法。
在声明一个类之后,你可以使用 new 运算符来创建它的实例。
典型函数构造器可以使用 new 来构造,也可以不使用 new 来调用。然而,对于类的“调用”则必须使用 new,否则会导致错误。
与函数声明不同,类声明并不会被提升(或者,在某些解释器中,可以被提升,但是有暂时性死区的限制),这意味着你不能在声明之前使用类。
该行为与使用 let 和 const 声明变量类似。
类表达式也可以有名字。表达式的名字只在类主体内可见。
类最重要的工作之一就是作为对象的“工厂”。例如,当我们使用 Date 构造函数时,我们期望它给我们一个新的对象,这个对象代表了我们传入的日期数据,而且我们可以使用该实例所暴露的其他方法来操作它。在类中,实例的创建是通过构造函数来完成的。
例如,我们创建一个名为 Color 的类,它代表了一个特定的颜色。用户通过传入一个 RGB 三元组来创建颜色。
打开你的浏览器的开发者工具,将上面的代码粘贴到控制台中,然后创建一个实例:
你已经成功创建了一个 Color 实例,该实例有一个 values 属性,它是一个包含了你传入的 RGB 值的数组。这与下面的代码几乎是等价的:
构造函数的语法与普通函数完全相同——这意味着你可以使用其他语法,例如剩余参数:
每一次调用 new 都将创建一个新的实例。
在类的构造函数里,this 的值指向新创建的实例。你可以赋予它新的属性,或者读取已有的属性(尤其是方法——我们将在下一节中介绍)。
this 的值将自动作为 new 的结果返回。不建议从构造函数中返回任何值——因为如果你返回一个非原始类型的值,它将成为 new 表达式的值,而 this 的值将被丢弃。你可以在 new 运算符的描述中阅读更多有关它的内容。
如果一个类只有构造函数,那么它与一个只创建普通对象的 createX 工厂函数并没有太大的区别。然而,类的强大之处在于它们可以作为“模板”,自动将方法分配给实例。
例如,对于 Date 实例,你可以用一系列方法来获取日期的不同部分,例如年份、月份、星期几等等。你也可以通过 setX 方法来设置这些值,例如 setFullYear。
对于我们的 Color 类,我们可以添加一个方法来获取红色值:
没有方法的帮助,你可能会尝试在构造函数内部定义该函数:
这也是可以的。然而,这会导致每次创建 Color 实例时都会创建一个新的函数,即使它们都做着同样的事情!
与之相反地,如果你使用方法,它将在所有实例之间共享。一个函数可以在所有实例之间共享,且在不同实例调用时其行为也不同,因为 this 的值不同。你也许好奇这个方法存储在哪里——它被定义在所有实例的原型上,即 Color.prototype,详情参阅继承与原型链。
相似地,我们也可以添加一个 setRed 方法来设置红色值:
你或许会好奇:为什么我们要费心使用 getRed 和 setRed 方法,而不是直接访问实例上的 values 数组呢?
在面向对象编程中,有一个叫做“封装”的哲学。这是说你不应该访问对象的底层实现,而是使用抽象方法来与之交互。例如,如果我们突然决定将颜色表示为 HSL 而不是 RGB:
用户对 values 数组代表 RGB 值的假设不再成立,这可能会打破他们的代码逻辑。因此,如果你是一个类的实现者,你应该隐藏实例的内部数据结构,以保持 API 的简洁性,并防止在你做了一些“无害的重构”时,用户代码不至于崩溃。在类中,这是通过私有字段来实现的。
访问原文 返回搜索 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_classes
本页为82搜索生成的网页快照,内容来自站内索引;演示数据的原文链接仅作示例。