菜单

对象与原型

相关源文件

本文探讨了 JavaScript 中对象和原型的基本概念,这是使 JavaScript 独一无二的核心机制之一。我们将研究对象创建、原型链、继承模式以及在 JavaScript 问答库中展示的属性访问方法。

有关函数和 this 绑定的信息,请参阅函数和 this 上下文。有关对象相关的类型强制转换,请参阅类型强制转换和运算符

JavaScript 中的对象是什么?

在 JavaScript 中,对象是属性和方法的动态集合。与原始类型(如数字或字符串)不同,对象是引用类型,JavaScript 中几乎所有非原始类型都是对象,包括函数和数组。

来源:README.md371-372

创建和使用对象

对象创建方法

JavaScript 提供了多种创建对象的方式

方法描述示例
对象字面量创建对象最简单的方式const obj = { key: 'value' }
构造函数new 关键字一起使用的函数const obj = new Person()
ES6 类构造函数的语法糖const obj = new MyClass()
Object.create()创建具有特定原型的对象const obj = Object.create(proto)

属性访问

JavaScript 提供了两种主要的访问对象属性的方式

  1. 点表示法object.property
  2. 方括号表示法object["property"]

方括号表示法更灵活,因为它:

  • 允许访问带有特殊字符的属性
  • 允许使用变量作为键
  • 在访问属性之前评估表达式

如仓库示例所示,尝试使用点表示法访问不存在的属性可能导致错误

来源:README.md151-167

对象属性与引用

JavaScript 中的对象通过引用进行交互。当你将一个对象赋值给一个变量时,你复制的是对该对象的引用,而不是对象本身。

这意味着通过一个变量对对象进行的更改会影响到所有对该对象的引用

来源:README.md188-201 zh-TW/README_zh-TW.md207-215

原型系统

什么是原型?

每个 JavaScript 对象都有一个特殊的隐藏属性,叫做 [[Prototype]](在浏览器中也称为 __proto__),它指向另一个对象。这个被引用的对象就是原型,原始对象从中继承属性和方法。

原型链

当访问一个对象的属性时,JavaScript 首先会在对象本身上查找该属性。如果未找到,它会检查对象的原型,然后是该原型的原型,依此类推,形成一个“原型链”。

来源:README.md482-483 zh-TW/README_zh-TW.md446-449

基对象

在 JavaScript 中,除了基对象(Object.prototype)之外,所有对象都有原型。这在问题 14 中有解释。

来源:README.md472-483 zh-TW/README_zh-TW.md439-450

函数作为对象

在 JavaScript 中,函数是特殊类型的对象。这意味着你可以像对待普通对象一样向函数添加属性。

这是因为函数是具有可调用功能的特殊对象。这是 JavaScript 基于原型的系统的一个独特方面。

来源:README.md349-371 zh-TW/README_zh-TW.md332-336

构造函数和继承

构造函数

构造函数是与 new 关键字一起用于创建对象的普通函数。它们为对象设置初始状态并隐式返回该对象。

当你用 new 调用构造函数时:

  1. 创建一个新的空对象
  2. this 绑定到该新对象
  3. 对象链接到构造函数的原型
  4. 函数执行
  5. 返回新对象(除非函数返回其他内容)

如果你忘记了 new 关键字,this 会指向全局对象(在严格模式下为 undefined

来源:README.md372-447 zh-TW/README_zh-TW.md387-412

向原型添加方法

要向构造函数创建的所有对象实例添加方法,应将它们添加到构造函数的原型上,而不是构造函数本身。

这更节省内存,因为方法只存在于内存中的一个位置(在原型上),而不是在每个实例上重复复制。

来源:README.md379-413 zh-TW/README_zh-TW.md345-377

静态方法

静态方法属于类/构造函数本身,而不属于实例。它们不能在类的实例上调用。

静态方法设计用于直接在构造函数/类上使用:Chameleon.colorChange('orange')

来源:README.md241-270 zh-TW/README_zh-TW.md254-282

对象键和属性访问

所有对象键都是字符串或符号

在 JavaScript 中,所有对象键都是字符串或符号,即使你没有将它们定义为字符串。

这种自动字符串转换解释了为什么当对象作为其他对象的键时,它们会被转换为字符串 "[object Object]"

来源:README.md759-780 README.md884-912 zh-TW/README_zh-TW.md738-741 zh-TW/README_zh-TW.md846-871

对象字面量中的重复键

当使用重复键定义对象时,最后一个键会覆盖前面的键。

来源:README.md784-804 zh-TW/README_zh-TW.md748-764

对象比较

对象通过引用而不是内容进行比较。两个具有相同属性的对象除非引用内存中的同一个对象,否则不相等。

发生这种情况是因为传递给函数的对象和比较中的对象是内存中不同的对象,即使它们看起来相同。

来源:README.md553-618 zh-TW/README_zh-TW.md552-583

原始值包装器

JavaScript 有特殊的“原始值包装器”对象类型,允许原始值被当作对象对待。

原始值包装器(NumberStringBoolean)允许原始值拥有方法。当你调用原始值的方法时,JavaScript 会暂时将其包装成一个对象。

来源:README.md207-236 README.md854-875 zh-TW/README_zh-TW.md222-247 zh-TW/README_zh-TW.md816-838

最佳实践

  1. 使用对象字面量处理简单的数据结构。
  2. 使用构造函数或类创建具有共享行为的多个实例。
  3. 将方法添加到原型而不是单个实例以节省内存。
  4. 使用构造函数时始终使用 new 关键字
  5. 注意对象比较 - 直接比较属性而不是对象本身。
  6. 复制或修改对象时注意对象引用

常见陷阱

  1. 使用构造函数时忘记 new 关键字,导致 this 指向全局对象。
  2. 将方法添加到构造函数而不是它们的原型。
  3. 直接使用 ===== 比较对象,而不是比较它们的属性。
  4. 混淆对象方法中 this 的上下文,尤其是在使用箭头函数时。
  5. 在不理解字符串转换的情况下,将对象用作其他对象的键

理解对象和原型是掌握 JavaScript 的基础,因为该语言的大部分功能都建立在这些概念之上。