第 6 章 集合引用类型



前言

虽然之前在课堂上已经学过 JavaScript 的相关用法了,但是现在要开始找工作的时候才发现好多知识点都忘记了(正所谓基础不牢,地动山摇😂),而且有些知识点学校教材上都没有,便有了要写这个 JavaScript 学习系列文章的想法。

由于博主只是做知识点总结与学习笔记分享,导致本系列文章对于 JavaScript 的使用方面介绍较少,还望读者能够自己多勤学苦练。废话不多说,让我们开始第 6 章 集合引用类型 的学习吧。


一、Object

显式地创建 Object 的实例有两种方式。第一种是使用 new 操作符和 Object 构造函数,如下所示:

let person = new Object(); 
person.name = "Nicholas"; 
person.age = 29; 

另一种方式是使用对象字面量(object literal)表示法。对象字面量是对象定义的简写形式,目的是为了简化包含大量属性的对象的创建。比如,下面的代码定义了与前面示例相同的 person 对象,但使用的是对象字面量表示法:

let person = { 
  name: "Nicholas", 
  age: 29 
};

二、Array

1.创建数组

有几种基本的方式可以创建数组。一种是使用 Array 构造函数,比如:

let colors = new Array(); 

// 如果知道数组中元素的数量,那么可以给构造函数传入一个数值,然后 length 属性就会被自动创建并设置为这个值。
let colors = new Array();

// 给 Array 构造函数传入要保存的元素
let colors = new Array("red", "blue", "green");

// 创建数组时给构造函数传一个值,就无法实现预期效果了
let colors = new Array(3); // 创建一个包含 3 个元素的数组
let names = new Array("Greg"); // 创建一个只包含一个元素,即字符串"Greg"的数组

在使用 Array 构造函数时,也可以省略 new 操作符。结果是一样的。

另一种创建数组的方式是使用数组字面量(array literal)表示法。数组字面量是在中括号([])中包含以逗号分隔的元素列表,如下面的例子所示:

let colors = ["red", "blue", "green"]; // 创建一个包含 3 个元素的数组
let names = []; // 创建一个空数组
let values = [1,2,]; // 创建一个包含 2 个元素的数组

Array 构造函数还有两个 ES6 新增的用于创建数组的静态方法:from()of()from()用于将类数组结构转换为数组实例,而 of()用于将一组参数转换为数组实例。

Array.from()的第一个参数是一个类数组对象,即任何可迭代的结构,或者有一个 length 属性和可索引元素的结构。

// 字符串会被拆分为单字符数组
console.log(Array.from("Matt")); // ["M", "a", "t", "t"] 

// 可以使用 from()将集合和映射转换为一个新数组
const m = new Map().set(1, 2) 
 .set(3, 4); 
const s = new Set().add(1) 
 .add(2) 
 .add(3) 
 .add(4); 
 
console.log(Array.from(m)); // [[1, 2], [3, 4]] 
console.log(Array.from(s)); // [1, 2, 3, 4] 

// Array.from()对现有数组执行浅复制
const a1 = [1, 2, 3, 4]; 
const a2 = Array.from(a1); 

console.log(a1); // [1, 2, 3, 4] 
alert(a1 === a2); // false
 
// 可以使用任何可迭代对象
const iter = { 
 *[Symbol.iterator]() { 
 yield 1; 
 yield 2; 
 yield 3; 
 yield 4; 
 } 
}; 
console.log(Array.from(iter)); // [1, 2, 3, 4]

// arguments 对象可以被轻松地转换为数组
function getArgsArray() { 
 return Array.from(arguments); 
} 
console.log(getArgsArray(1, 2, 3, 4)); // [1, 2, 3, 4] 

// from()也能转换带有必要属性的自定义对象
const arrayLikeObject = { 
 0: 1, 
 1: 2, 
 2: 3, 
 3: 4, 
 length: 4 
}; 
console.log(Array.from(arrayLikeObject)); // [1, 2, 3, 4]

还接收第二个可选的映射函数参数。这个函数可以直接增强新数组的值,而无须像调用 Array.from().map()那样先创建一个中间数组。还可以接收第三个可选参数,用于指定映射函数中 this 的值。但这个重写的 this 值在箭头函数中不适用。

Array.of()可以把一组参数转换为数组。这个方法用于替代在 ES6之前常用的 Array.prototype. slice.call(arguments),一种异常笨拙的将 arguments 对象转换为数组的写法:

console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4] 
console.log(Array.of(undefined)); // [undefined]

2.数组空位

使用数组字面量初始化数组时,可以使用一串逗号来创建空位(hole)。ECMAScript 会将逗号之间相应索引位置的值当成空位,ES6 规范重新定义了该如何处理这些空位。

可以像下面这样创建一个空位数组:

const options = [,,,,,]; // 创建包含 5 个元素的数组
console.log(options.length); // 5 
console.log(options); // [,,,,,]

ES6 新增的方法和迭代器与早期 ECMAScript 版本中存在的方法行为不同。ES6 新增方法普遍将这些空位当成存在的元素,只不过值为 undefined

3.数组索引

在中括号中提供的索引表示要访问的值。如果索引小于数组包含的元素数,则返回存储在相应位置的元素(索引值从0开始)。

由于数组 length 属性不是只读的,所以通过修改 length 属性,可以从数组末尾删除或添加元素。

4.检测数组

一个经典的 ECMAScript 问题是判断一个对象是不是数组。在只有一个网页(因而只有一个全局作用域)的情况下,使用 instanceof 操作符就足矣:

if (value instanceof Array){ 
 // 操作数组
} 

ECMAScript 提供了 Array.isArray()方法。这个方法的目的就是确定一个值是否为数组,而不用管它是在哪个全局执行上下文中创建的。来看下面的例子:

if (Array.isArray(value)){ 
 // 操作数组
}

5.迭代器方法

在 ES6 中,Array 的原型上暴露了 3 个用于检索数组内容的方法:keys()、values()和 entries()。keys()返回数组索引的迭代器,values()返回数组元素的迭代器,而 entries()返回索引/值对的迭代器:

const a = ["foo", "bar", "baz", "qux"]; 

// 因为这些方法都返回迭代器,所以可以将它们的内容
// 通过 Array.from()直接转换为数组实例
const aKeys = Array.from(a.keys()); 
const aValues = Array.from(a.values()); 
const aEntries = Array.from(a.entries()); 

console.log(aKeys); // [0, 1, 2, 3] 
console.log(aValues); // ["foo", "bar", "baz", "qux"] 
console.log(aEntries); // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]

使用 ES6 的解构可以非常容易地在循环中拆分键/值对:

const a = ["foo", "bar", "baz", "qux"]; 
for (const [idx, element] of a.entries()) { 
 alert(idx); 
 alert(element); 
} 
// 0 
// foo 
// 1 
// bar 
// 2 
// baz 
// 3 
// qux

6.复制和填充方法

ES6 新增了两个方法:批量复制方法 copyWithin(),以及填充数组方法 fill()。这两个方法的函数签名类似,都需要指定既有数组实例上的一个范围,包含开始索引,不包含结束索引。使用这个方法不会改变数组的大小。

使用 fill()方法可以向一个已有的数组中插入全部或部分相同的值。开始索引用于指定开始填充的位置,它是可选的。如果不提供结束索引,则一直填充到数组末尾。负值索引从数组末尾开始计算。也可以将负索引想象成数组长度加上它得到的一个正索引。静默忽略超出数组边界、零长度及方向相反的索引范围。

fill()不同,copyWithin()会按照指定范围浅复制数组中的部分内容,然后将它们插入到指定索引开始的位置。开始索引和结束索引则与 fill()使用同样的计算方法。

7.转换方法

所有对象都有 toLocaleString()、toString()和 valueOf()方法。其中,valueOf()返回的还是数组本身。而 toString()返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串。toLocaleString()方法也可能返回跟 toString()valueOf()相同的结果,但也不一定。在调用数组的 toLocaleString()方法时,会得到一个逗号分隔的数组值的字符串。它与另外两个方法唯一的区别是,为了得到最终的字符串,会调用数组每个值的 toLocaleString()方法,而不是toString()方法。

注意:如果数组中某一项是 null 或 undefined,则在 join()、toLocaleString()、toString()和 valueOf()返回的结果中会以空字符串表示。

8.栈方法

ECMAScript 数组提供了 push()和 pop()方法,以实现类似栈的行为。push()方法接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度。pop()方法则用于删除数组的最后一项,同时减少数组的 length 值,返回被删除的项。

9.队列方法

使用 shift()push(),可以把数组当成队列来使用。因为 shift() 会删除数组的第一项并返回它,然后数组长度减 1。

ECMAScript 也为数组提供了 unshift()方法。顾名思义,unshift()就是执行跟 shift()相反的操作:在数组开头添加任意多个值,然后返回新的数组长度。通过使用 unshift()pop(),可以在相反方向上模拟队列,即在数组开头添加新数据,在数组末尾取得数据。

10.排序方法

数组有两个方法可以用来对元素重新排序:reverse()sort()。顾名思义,reverse()方法就是将数组元素反向排列。

默认情况下,sort()会按照升序重新排列数组元素,即最小的值在前面,最大的值在后面。为此,sort()会在每一项上调用 String()转型函数,然后比较字符串来决定顺序。即使数组的元素都是数值,也会先把数组转换为字符串再比较、排序。

11.操作方法

  1. concat()
    在现有数组全部元素基础上创建一个新数组。它首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组。如果传入一个或多个数组,则 concat()会把这些数组的每一项都添加到结果数组。如果参数不是数组,则直接把它们添加到结果数组末尾。

  2. slice()
    用于创建一个包含原有数组中一个或多个元素的新数组。slice()方法可以接收一个或两个参数:返回元素的开始索引和结束索引。如果只有一个参数,则 slice()会返回该索引到数组末尾的所有元素。如果有两个参数,则 slice()返回从开始索引到结束索引对应的所有元素,其中不包含结束索引对应的元素。记住,这个操作不影响原始数组。

    // 要给 splice()传 2 个参数:要删除的第一个元素的位置和要删除的元素数量
    let colors = ["red", "green", "blue"]; 
    let removed = colors.splice(0,1); // 删除第一项
    alert(colors); // green,blue 
    alert(removed); // red,只有一个元素的数组
    
    // 给 splice()传 3 个参数:开始位置、0(要删除的元素数量)和要插入的元素,可以在数组中指定的位置插入元素
    removed = colors.splice(1, 0, "yellow", "orange"); // 在位置 1 插入两个元素
    alert(colors); // green,yellow,orange,blue 
    alert(removed); // 空数组
    
    // splice()在删除元素的同时可以在指定位置插入新元素,同样要传入 3 个参数:开始位置、要删除元素的数量和要插入的任意多个元素
    removed = colors.splice(1, 1, "red", "purple"); // 插入两个值,删除一个元素
    alert(colors); // green,red,purple,orange,blue 
    alert(removed); // yellow,只有一个元素的数组
    

12.搜索和位置方法

ECMAScript 提供两类搜索数组的方法:按严格相等搜索和按断言函数搜索。

  1. 严格相等
    ECMAScript 提供了 3 个严格相等的搜索方法:indexOf()lastIndexOf()includes()。其中,前两个方法在所有版本中都可用,而第三个方法是 ECMAScript 7 新增的。这些方法都接收两个参数:要查找的元素和一个可选的起始搜索位置。indexOf()和 includes()方法从数组前头(第一项)开始向后搜索,而 lastIndexOf()从数组末尾(最后一项)开始向前搜索。

    indexOf()和 lastIndexOf()都返回要查找的元素在数组中的位置,如果没找到则返回-1。includes()返回布尔值,表示是否至少找到一个与指定元素匹配的项。在比较第一个参数跟数组每一项时,会使用全等(===)比较,也就是说两项必须严格相等。

  2. 断言函数
    ECMAScript 也允许按照定义的断言函数搜索数组,每个索引都会调用这个函数。断言函数的返回值决定了相应索引的元素是否被认为匹配。

    断言函数接收 3 个参数:元素、索引和数组本身。其中元素是数组中当前搜索的元素,索引是当前元素的索引,而数组就是正在搜索的数组。断言函数返回真值,表示是否匹配。

    find()findIndex()方法使用了断言函数。这两个方法都从数组的最小索引开始。find()返回第一个匹配的元素,findIndex()返回第一个匹配元素的索引。这两个方法也都接收第二个可选的参数,用于指定断言函数内部 this 的值。

13.迭代方法

ECMAScript 为数组定义了 5 个迭代方法。每个方法接收两个参数:以每一项为参数运行的函数,以及可选的作为函数运行上下文的作用域对象(影响函数中 this 的值)。传给每个方法的函数接收 3个参数:数组元素、元素索引和数组本身。因具体方法而异,这个函数的执行结果可能会也可能不会影响方法的返回值。数组的 5 个迭代方法如下。

  • every():对数组每一项都运行传入的函数,如果对每一项函数都返回 true,则这个方法返回 true。
  • filter():对数组每一项都运行传入的函数,函数返回 true 的项会组成数组之后返回。
  • forEach():对数组每一项都运行传入的函数,没有返回值。
  • map():对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组。
  • some():对数组每一项都运行传入的函数,如果有一项函数返回 true,则这个方法返回 true。

这些方法都不改变调用它们的数组。

14.归并方法

ECMAScript 为数组提供了两个归并方法:reduce()reduceRight()。这两个方法都会迭代数组的所有项,并在此基础上构建一个最终返回值。reduce()方法从数组第一项开始遍历到最后一项。而 reduceRight()从最后一项开始遍历至第一项。

这两个方法都接收两个参数:对每一项都会运行的归并函数,以及可选的以之为归并起点的初始值。传给 reduce()和 reduceRight()的函数接收 4 个参数:上一个归并值、当前项、当前项的索引和数组本身。这个函数返回的任何值都会作为下一次调用同一个函数的第一个参数。如果没有给这两个方法传入可选的第二个参数(作为归并起点值),则第一次迭代将从数组的第二项开始,因此传给归并函数的第一个参数是数组的第一项,第二个参数是数组的第二项。

三、定型数组

定型数组(typed array)是 ECMAScript 新增的结构,目的是提升向原生库传输数据的效率。实际上,JavaScript 并没有“TypedArray”类型,它所指的其实是一种特殊的包含数值类型的数组。

1.历史

  1. WebGL
  2. 定型数组

2.ArrayBuffer

ArrayBuffer()是一个普通的 JavaScript 构造函数,可用于在内存中分配特定数量的字节空间。

const buf = new ArrayBuffer(16); // 在内存中分配 16 字节
alert(buf.byteLength); // 16 

ArrayBuffer 一经创建就不能再调整大小。不过,可以使用 slice()复制其全部或部分到一个新实例中:

const buf1 = new ArrayBuffer(16); 
const buf2 = buf1.slice(4, 12); 
alert(buf2.byteLength); // 8

ArrayBuffer 某种程度上类似于 C++的 malloc(),但也有几个明显的区别。

  • malloc()在分配失败时会返回一个 null 指针。ArrayBuffer 在分配失败时会抛出错误。
  • malloc()可以利用虚拟内存,因此最大可分配尺寸只受可寻址系统内存限制。ArrayBuffer分配的内存不能超过 Number.MAX_SAFE_INTEGER(2^53 - 1)字节。
  • malloc()调用成功不会初始化实际的地址。声明 ArrayBuffer 则会将所有二进制位初始化为 0。
  • 通过 malloc()分配的堆内存除非调用 free()或程序退出,否则系统不能再使用。而通过声明ArrayBuffer 分配的堆内存可以被当成垃圾回收,不用手动释放。

3.DataView

第一种允许你读写 ArrayBuffer 的视图是 DataView。这个视图专为文件 I/O 和网络 I/O 设计,其API 支持对缓冲数据的高度控制,但相比于其他类型的视图性能也差一些。DataView 对缓冲内容没有
任何预设,也不能迭代。

必须在对已有的 ArrayBuffer 读取或写入时才能创建 DataView 实例。这个实例可以使用全部或部分 ArrayBuffer,且维护着对该缓冲实例的引用,以及视图在缓冲中开始的位置。

  1. ElementType
  2. 字节序
  3. 边界情形

4.定型数组

定型数组是另一种形式的 ArrayBuffer 视图。虽然概念上与 DataView 接近,但定型数组的区别在于,它特定于一种 ElementType 且遵循系统原生的字节序。相应地,定型数组提供了适用面更广的API 和更高的性能。设计定型数组的目的就是提高与 WebGL 等原生库交换二进制数据的效率。由于定型数组的二进制表示对操作系统而言是一种容易使用的格式,JavaScript 引擎可以重度优化算术运算、按位运算和其他对定型数组的常见操作,因此使用它们速度极快。

创建定型数组的方式包括读取已有的缓冲、使用自有缓冲、填充可迭代结构,以及填充基于任意类型的定型数组。另外,通过<ElementType>.from()<ElementType>.of()也可以创建定型数组。

  1. 定型数组行为
  2. 合并、复制和修改定型数组
  3. 下溢和上溢

四、Map

作为 ECMAScript 6 的新增特性,Map 是一种新的集合类型,为这门语言带来了真正的键/值存储机制。Map 的大多数特性都可以通过 Object 类型实现,但二者之间还是存在一些细微的差异。

1.基本 API

使用 new 关键字和 Map 构造函数可以创建一个空映射:

const m = new Map(); 

如果想在创建的同时初始化实例,可以给 Map 构造函数传入一个可迭代对象,需要包含键/值对数组。可迭代对象中的每个键/值对都会按照迭代顺序插入到新映射实例中:

// 使用嵌套数组初始化映射
const m1 = new Map([ 
 ["key1", "val1"], 
 ["key2", "val2"], 
 ["key3", "val3"] 
]); 
alert(m1.size); // 3 

// 使用自定义迭代器初始化映射
const m2 = new Map({ 
 [Symbol.iterator]: function*() { 
 yield ["key1", "val1"]; 
 yield ["key2", "val2"]; 
 yield ["key3", "val3"]; 
 } 
}); 
alert(m2.size); // 3 

// 映射期待的键/值对,无论是否提供
const m3 = new Map([[]]); 
alert(m3.has(undefined)); // true 
alert(m3.get(undefined)); // undefined

初始化之后,可以使用 set()方法再添加键/值对。另外,可以使用 get()has()进行查询,可以通过 size 属性获取映射中的键/值对的数量,还可以使用 delete()clear()删除值。

2.顺序与迭代

Object 类型的一个主要差异是,Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。

映射实例可以提供一个迭代器(Iterator),能以插入顺序生成[key, value]形式的数组。可以通过 entries()方法(或者 Symbol.iterator 属性,它引用 entries())取得这个迭代器。

如果不使用迭代器,而是使用回调方式,则可以调用映射的 forEach(callback, opt_thisArg)方法并传入回调,依次迭代每个键/值对。传入的回调接收可选的第二个参数,这个参数用于重写回调内部 this 的值。

3.选择 Object 还是 Map

  1. 内存占用
    给定固定大小的内存,Map 大约可以比 Object 多存储 50%的键/值对。

  2. 插入性能
    Object 和 Map 中插入新键/值对的消耗大致相当,不过插入 Map 在所有浏览器中一般会稍微快一点儿。

  3. 查找速度
    从大型 Object 和 Map 中查找键/值对的性能差异极小,但如果只包含少量键/值对,则 Object 有时候速度更快。

  4. 删除性能
    Map 的 delete()操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择 Map。

五、WeakMap

ECMAScript 6 新增的“弱映射”(WeakMap)是一种新的集合类型,为这门语言带来了增强的键/值对存储机制。WeakMap 是 Map 的“兄弟”类型,其 API 也是 Map 的子集。WeakMap 中的“weak”(弱),描述的是 JavaScript 垃圾回收程序对待“弱映射”中键的方式。

1.基本 API

可以使用 new 关键字实例化一个空的 WeakMap:

const wm = new WeakMap();

初始化之后可以使用 set()再添加键/值对,可以使用 get()has()查询,还可以使用 delete()删除。

2.弱键

弱映射的键不属于正式的引用,不会阻止垃圾回收。但要注意的是,弱映射中值的引用可不是“弱弱地拿着”的。只要键存在,键/值对就会存在于映射中,并被当作对值的引用,因此就不会被当作垃圾回收。

3.不可迭代键

因为 WeakMap 中的键/值对任何时候都可能被销毁,所以没必要提供迭代其键/值对的能力。

4.使用弱映射

  1. 私有变量
    弱映射造就了在 JavaScript 中实现真正私有变量的一种新方式。前提很明确:私有变量会存储在弱映射中,以对象实例为键,以私有成员的字典为值。

  2. DOM 节点元数据
    因为 WeakMap 实例不会妨碍垃圾回收,所以非常适合保存关联元数据。

六、Set

1.基本 API

使用 new 关键字和 Set 构造函数可以创建一个空集合:

const m = new Set(); 

如果想在创建的同时初始化实例,则可以给 Set 构造函数传入一个可迭代对象,其中需要包含插入到新集合实例中的元素:

// 使用数组初始化集合 
const s1 = new Set(["val1", "val2", "val3"]); 

alert(s1.size); // 3 

// 使用自定义迭代器初始化集合
const s2 = new Set({ 
 [Symbol.iterator]: function*() { 
 yield "val1"; 
 yield "val2"; 
 yield "val3"; 
 } 
}); 
alert(s2.size); // 3 

初始化之后,可以使用 add()增加值,使用 has()查询,通过 size 取得元素数量,以及使用 delete()clear()删除元素。

2.顺序与迭代

Set 会维护值插入时的顺序,因此支持按顺序迭代。

集合实例可以提供一个迭代器(Iterator),能以插入顺序生成集合内容。可以通过 values()方法及其别名方法 keys()(或者 Symbol.iterator 属性,它引用 values())取得这个迭代器。

因为 values()是默认迭代器,所以可以直接对集合实例使用扩展操作,把集合转换为数组:

const s = new Set(["val1", "val2", "val3"]); 
console.log([...s]); // ["val1", "val2", "val3"]

集合的 entries()方法返回一个迭代器,可以按照插入顺序产生包含两个元素的数组,这两个元素是集合中每个值的重复出现。如果不使用迭代器,而是使用回调方式,则可以调用集合的 forEach()方法并传入回调,依次迭代每个键/值对。传入的回调接收可选的第二个参数,这个参数用于重写回调内部 this 的值。

3.定义正式集合操作

从各方面来看,Set 跟 Map 都很相似,只是 API 稍有调整。唯一需要强调的就是集合的 API 对自身的简单操作。很多开发者都喜欢使用 Set 操作,但需要手动实现:或者是子类化 Set,或者是定义一个实用函数库。要把两种方式合二为一,可以在子类上实现静态方法,然后在实例方法中使用这些静态方法。在实现这些操作时,需要考虑几个地方。

  • 某些 Set 操作是有关联性的,因此最好让实现的方法能支持处理任意多个集合实例。
  • Set 保留插入顺序,所有方法返回的集合必须保证顺序。
  • 尽可能高效地使用内存。扩展操作符的语法很简洁,但尽可能避免集合和数组间的相互转换能够节省对象初始化成本。
  • 不要修改已有的集合实例。union(a, b)或 a.union(b)应该返回包含结果的新集合实例。

七、WeakSet

1.基本 API

可以使用 new 关键字实例化一个空的 WeakSet:

const ws = new WeakSet(); 

弱集合中的值只能是 Object 或者继承自 Object 的类型,尝试使用非对象设置值会抛出 TypeError。

如果想在初始化时填充弱集合,则构造函数可以接收一个可迭代对象,其中需要包含有效的值。可迭代对象中的每个值都会按照迭代顺序插入到新实例中。

初始化之后可以使用 add()再添加新值,可以使用 has()查询,还可以使用 delete()删除。

2.弱值

3.不可迭代值

4.使用弱集合

八、迭代与扩展操作

ECMAScript 6 新增的迭代器和扩展操作符对集合引用类型特别有用。这些新特性让集合类型之间相互操作、复制和修改变得异常方便。

如本章前面所示,有 4 种原生集合类型定义了默认迭代器:

  • Array
  • 所有定型数组
  • Map
  • Set

这意味着上述所有类型都支持顺序迭代,都可以传入 for-of 循环。

这也意味着所有这些类型都兼容扩展操作符(...)。扩展操作符在对可迭代对象执行浅复制时特别有用,只需简单的语法就可以复制整个对象。


总结

JavaScript 中的对象称为引用值,几种内置的引用类型可用于创建特定类型的对象。

JavaScript 比较独特的一点是,函数实际上是 Function 类型的实例,也就是说函数也是对象。因为函数也是对象,所以函数也有方法,可以用于增强其能力。

由于原始值包装类型的存在,JavaScript 中的原始值可以被当成对象来使用。有 3 种原始值包装类型:Boolean、Number 和 String。

当代码开始执行时,全局上下文中会存在两个内置对象:Global 和 Math。其中,Global 对象在大多数 ECMAScript 实现中无法直接访问。不过,浏览器将其实现为 window 对象。所有全局变量和函数都是 Global 对象的属性。Math 对象包含辅助完成复杂计算的属性和方法。

以上就是本篇文章的全部内容了,下一篇文章我们将学习“第 7 章 迭代器与生成器”,如果想要第一时间获取相关文章,欢迎关注博主,并订阅专栏。您的支持与鼓励将成为我不断前行地动力!

最后,如果本篇文章对正在阅读的您有所帮助或启发,请不要吝啬您的点赞收藏评论及分享,这样就有可能帮助到更多的人了。同时也欢迎留下您遇到的问题,让我们一起探讨学习,共同进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值