现代JavaScript 教程( Object(对象):基础知识)总结

对象

对象是具有一些特殊特性的关联数组。

它们存储属性(键值对),其中:

  • 属性的键必须是字符串或者 symbol(通常是字符串)。
  • 值可以是任何类型。

我们可以用下面的方法访问属性:

  • 点符号: obj.property
  • 方括号 obj["property"],方括号允许从变量中获取键,例如 obj[varWithKey]

其他操作:

  • 删除属性:delete obj.prop
  • 检查是否存在给定键的属性:"key" in obj
  • 遍历对象:for(let key in obj) 循环。

对象的引用和复制

对象通过引用被赋值和拷贝。换句话说,一个变量存储的不是“对象的值”,而是一个对值的“引用”(内存地址)。因此,拷贝此类变量或将其作为函数参数传递时,所拷贝的是引用,而不是对象本身。

所有通过被拷贝的引用的操作(如添加、删除属性)都作用在同一个对象上。

为了创建“真正的拷贝”(一个克隆),我们可以使用 Object.assign 来做所谓的“浅拷贝”(嵌套对象被通过引用进行拷贝)

使用 Object.assign 方法,语法是:

Object.assign(dest, [src1, src2, src3...])
  • 第一个参数 dest 是指目标对象。
  • 更后面的参数 src1, ..., srcN(可按需传递多个参数)是源对象。
  • 该方法将所有源对象的属性拷贝到目标对象 dest 中。换句话说,从第二个开始的所有参数的属性都被拷贝到第一个参数的对象中。
  • 调用结果返回 dest

或者使用“深拷贝”函数,例如 _.cloneDeep(obj)

垃圾回收

  • 垃圾回收是自动完成的,不能强制执行或是阻止执行。
  • 当对象是可达状态时,它一定是存在于内存中的。
  • 被引用与可访问(从一个根)不同:一组相互连接的对象可能整体都不可达。

对象方法,"this"

  • 存储在对象属性中的函数被称为“方法”。
  • 方法允许对象进行像 object.doSomething() 这样的“操作”。
  • 方法可以将对象引用为 this

this 的值是在程序运行时得到的。

  • 一个函数在声明时,可能就使用了 this,但是这个 this 只有在函数被调用时才会有值。
  • 可以在对象之间复制函数。
  • 以“方法”的语法调用函数时:object.method(),调用过程中的 this 值是 object

注意箭头函数有些特别:它们没有 this。在箭头函数内部访问到的 this 都是从外部获取的。

构造器和操作符"new"

  • 构造函数,或简称构造器,就是常规函数,但大家对于构造器有个共同的约定,就是其命名首字母要大写。
  • 构造函数只能使用 new 来调用。这样的调用意味着在开始时创建了空的 this,并在最后返回填充了值的 this

构造器模式测试

💡可以使用 new.target 属性来检查它是否被使用 new 进行调用了。对于常规调用,它为空,对于使用 new 的调用,则等于该函数。

构造器的return

如果构造器有return 语句,则:带有对象的 return 返回该对象,在所有其他情况下返回 this

可选链"?."

可选链 ?. 语法有三种形式:

  1. obj?.prop —— 如果 obj 存在则返回 obj.prop,否则返回 undefined
  2. obj?.[prop] —— 如果 obj 存在则返回 obj[prop],否则返回 undefined
  3. obj.method?.() —— 如果 obj.method 存在则调用 obj.method(),否则返回 undefined

正如我们所看到的,这些语法形式用起来都很简单直接。?. 检查左边部分是否为 null/undefined,如果不是则继续运算。

?. 链使我们能够安全地访问嵌套属性。

但是,我们应该谨慎地使用 ?.,仅在当左边部分不存在也没问题的情况下使用为宜。以保证在代码中有编程上的错误出现时,也不会对我们隐藏。

?. 前的变量必须已声明

如果未声明变量 user,那么 user?.anything 会触发一个错误

Symbol类型

Symbol 是唯一标识符的基本类型

Symbol 是使用带有可选描述(name)的 Symbol() 调用创建的。

Symbol 总是不同的值,即使它们有相同的名字。如果我们希望同名的 Symbol 相等,那么我们应该使用全局注册表:Symbol.for(key) 返回(如果需要的话则创建)一个以 key 作为名字的全局 Symbol。使用 Symbol.for 多次调用 key 相同的 Symbol 时,返回的就是同一个 Symbol。

Symbol 有两个主要的使用场景:

  1. “隐藏” 对象属性。 如果我们想要向“属于”另一个脚本或者库的对象添加一个属性,我们可以创建一个 Symbol 并使用它作为属性的键。Symbol 属性不会出现在 for..in 中,因此它不会意外地被与其他属性一起处理。并且,它不会被直接访问,因为另一个脚本没有我们的 symbol。因此,该属性将受到保护,防止被意外使用或重写。

    因此我们可以使用 Symbol 属性“秘密地”将一些东西隐藏到我们需要的对象中,但其他地方看不到它。

  2. JavaScript 使用了许多系统 Symbol,这些 Symbol 可以作为 Symbol.* 访问。我们可以使用它们来改变一些内置行为。例如,在本教程的后面部分,我们将使用 Symbol.iterator 来进行 迭代 操作,使用 Symbol.toPrimitive 来设置 对象原始值的转换 等等。

从技术上说,Symbol 不是 100% 隐藏的。有一个内置方法 Object.getOwnPropertySymbols(obj) 允许我们获取所有的 Symbol。还有一个名为 Reflect.ownKeys(obj) 的方法可以返回一个对象的 所有 键,包括 Symbol。所以它们并不是真正的隐藏。但是大多数库、内置方法和语法结构都没有使用这些方法。

对象--原始值转换

对象到原始值的转换,是由许多期望以原始值作为值的内建函数和运算符自动调用的。

这里有三种类型(hint):

  • "string"(对于 alert 和其他需要字符串的操作)
  • "number"(对于数学运算)
  • "default"(少数运算符)

规范明确描述了哪个运算符使用哪个 hint。很少有运算符“不知道期望什么”并使用 "default" hint。通常对于内建对象,"default" hint 的处理方式与 "number" 相同,因此在实践中,最后两个 hint 常常合并在一起。

转换算法是:

  1. 调用 obj[Symbol.toPrimitive](hint) 如果这个方法存在,
  2. 否则,如果 hint 是"string"
    • 尝试 obj.toString()obj.valueOf(),无论哪个存在。
  3. 否则,如果 hint 是"number"或者"default"
    • 尝试 obj.valueOf()obj.toString(),无论哪个存在。

在实践中,为了便于进行日志记录或调试,对于所有能够返回一种“可读性好”的对象的表达形式的转换,只实现以 obj.toString() 作为全能转换的方法就够了。

原文地址:Object(对象):基础知识

posted @ 2021-10-31 10:36  xloading  阅读(285)  评论(0)    收藏  举报