菜单

对象与类

相关源文件

目的与范围

本文档涵盖了 JavaScript 的对象系统、原型继承机制和类语法。它探讨了对象如何构成 JavaScript 核心支柱之一(原型)的基础,this 关键字如何实现动态上下文绑定,以及 class 语法如何提供一种更具声明性的方式来表达面向对象设计。这是理解 JavaScript 程序中数据和行为如何组织的关键知识。

有关原始类型和类型强制的详细信息,请参阅类型与语法。有关作用域和闭包的更多信息,请参阅作用域与闭包

对象系统概述

JavaScript 的对象机制是一种灵活而强大的容器类型,它允许您存储和组织数据与行为。尽管 JavaScript 中并非所有事物都是对象(与普遍的误解相反),但对象是 JavaScript 三大支柱之一:原型系统的基础。

JavaScript 中的对象系统由几个关键组件组成

  1. 对象字面量 - 创建对象的主要方式
  2. 原型继承 - 对象可以通过原型链委托行为
  3. - 用于创建构造函数和原型的语法糖
  4. this 绑定 - 方法调用的动态上下文

对象系统图

来源:objects-classes/ch1.md12-18 objects-classes/ch2.md8-13 objects-classes/ch3.md8-18 objects-classes/ch4.md8-22

对象基础

JavaScript 中的对象是键/值对的集合,其中键(属性名)通常是字符串,值可以是任何有效的 JavaScript 值。对象可以通过对象字面量语法或通过构造函数创建。

属性可以通过点表示法(object.property)或括号表示法(object["property"])访问。当属性名包含特殊字符或在运行时计算时,需要使用括号表示法。

有关对象基础的更多详细信息,请参阅对象基础

来源:objects-classes/ch1.md32-50 objects-classes/ch1.md61-75 objects-classes/ch1.md313-326

对象如何工作

JavaScript 中的对象遵循一套被称为“元对象协议”(MOP)的规则。该协议定义了属性的行为方式以及对象之间如何交互。

属性描述符

对象上的每个属性都由一个属性描述符描述——一个控制属性行为的元数据对象

属性描述符允许对属性行为进行细粒度控制

  • value:属性的实际值
  • enumerable:控制属性是否出现在枚举中
  • writable:控制属性的值是否可以更改
  • configurable:控制属性的描述符是否可以修改

属性也可以定义为带有 getter 和 setter 的“访问器属性”,而不是简单的值。

原型链

JavaScript 对象最重要的特性之一是原型链,在规范中表示为 [[Prototype]]。这种内部链接允许对象将属性访问委托给其他对象

来源:objects-classes/ch2.md14-123 objects-classes/ch2.md268-308

JavaScript 中的类

JavaScript 类于 ES6 (2015) 引入,为创建具有共享行为的对象提供了更清晰、更具声明性的语法。虽然最初主要是在现有原型系统之上的语法糖,但类后来演变为一个更强大的功能,具有更多能力。

类定义

类可以使用类声明或类表达式来定义

类组件图

来源:objects-classes/ch3.md66-104

构造函数和方法

每个类都有一个构造函数方法,当使用 new 关键字创建新实例时会调用该方法。构造函数初始化实例

在类方法中,this 指向当前实例。方法定义在原型对象上,而不是直接在每个实例上,这意味着它们在所有实例之间共享。

来源:objects-classes/ch3.md109-133 objects-classes/ch3.md182-202

类实例上下文与 this

类方法中的 this 关键字指向调用该方法的当前实例

这使得方法可以访问同一实例中的实例属性和其他方法。

来源:objects-classes/ch3.md204-233

公共字段

类可以直接在类体中声明公共字段,这些字段对应于将在每个实例上创建的属性

公共字段可以有默认值,并且可以使用 this 相互引用。

来源:objects-classes/ch3.md235-274

类扩展

JavaScript 类通过 extends 关键字支持继承

extends 关键字创建了子类-父类关系,子类从父类继承方法和属性。子类可以覆盖继承的属性和方法,并且可以使用 super 关键字访问父类的实现。

来源:objects-classes/ch3.md374-407

使用 super 进行方法重写

子类可以重写其父类的方法,并且仍然可以使用 super 访问父类的实现

当子类提供自己的构造函数时,它必须在使用 this 之前调用 super()

来源:objects-classes/ch3.md422-486 objects-classes/ch3.md489-521

静态类成员

类可以定义静态属性和方法,这些属性和方法直接在类本身上访问,而不是在实例上访问

静态成员被子类继承,并且可以使用子类名称访问。

来源:objects-classes/ch3.md710-765

类继承与委托

来源:objects-classes/ch3.md15-18 objects-classes/ch5.md8-22

this 关键字

JavaScript 中的 this 关键字为函数调用提供了动态上下文。与许多其他编程语言不同,this 的值不是在函数编写时确定的,而是在其调用时确定的。

this 绑定规则

this 的值根据以下四条规则确定,按优先级顺序排列

  1. new 绑定:当函数与 new 一起调用时,this 指向新创建的对象
  2. 显式绑定:当函数与 call()apply()bind() 一起调用时,this 被显式设置
  3. 隐式绑定:当函数作为对象的方法调用时,this 指向该对象
  4. 默认绑定:在非严格模式下,this 指向全局对象;在严格模式下,它是 undefined

有关 this 绑定的更多详细信息,请参阅“this”关键字

来源:objects-classes/ch4.md22-87 objects-classes/ch4.md89-137

委托模式

虽然类是 JavaScript 中组织代码最常见的方式,但该语言也通过其原型机制支持对象委托。这使得对象可以将行为委托给其他对象,而无需使用类继承。

对象委托方法

在这种方法中,对象通过原型链连接,方法从一个对象委托给另一个对象。这创建了一个灵活的组合模型,与经典继承不同。

有关委托模式的更多信息,请参阅委托模式

来源:objects-classes/ch5.md254-326

方法比较

JavaScript 提供了多种组织代码和行为的方式

方法优点缺点最佳用途
对象字面量简单、直接重用受限一次性对象
工厂函数封装,无需 new内存使用(每个实例都有自己的方法)隐私,数据闭包
熟悉的 OOP 模式,方法共享复杂性,僵化继承结构复杂领域模型,团队熟悉 OOP
委托灵活组合,运行时适应性不那么主流,更抽象动态行为共享,避免深度继承

您选择的方法取决于您的具体需求、团队偏好以及项目要求。

来源:objects-classes/ch3.md20-64 objects-classes/ch5.md26-45

总结

JavaScript 的对象和类系统为组织代码提供了灵活的基础

  1. 对象用作数据和行为的容器
  2. 原型通过委托实现行为共享
  3. 提供了创建构造函数/原型组合的熟悉语法
  4. this 关键字允许动态上下文绑定

理解这些概念对于高效的 JavaScript 编程至关重要,因为它们构成了该语言的三大支柱之一。

来源:objects-classes/ch1.md12-18 objects-classes/ch3.md8-18 objects-classes/ch4.md8-22