--本文采自本人公众号《猴哥别瞎说》

在这篇文章中,我们来聊聊JavaScript中的对象分类。对于我而言,之所以这样做,不仅仅是为了知识的完备性,更想要对其中的每一类别都有明确的认知,为更进一步的学习踏实步子。

JavaScript中的对象分类

首先肯定是做一个枚举,从最肤浅的划分角度来看待的话,对象可以分为两类:宿主对象和内置对象,一里一外。 在内置对象中呢,又可以有更详细的划分:固有对象、原生对象和普通对象。它们的定义分别如下:

  • 宿主对象:由JavaScript宿主环境提供的对象,它们的行为完全由宿主决定。
  • 内置对象:由JavaScript语言提供的对象。
    • 固有对象:由标准规定,随着 JavaScript 运行时创建而自动创建的对象实例。
    • 原生对象:可以由用户通过 Array、RegExp 等内置构造器或者特殊语法创建的对象。
    • 普通对象:由{}语法、Object 构造器或者 class 关键字定义类创建的对象,它能够被原型继承。

下面就来一一了解除了普通对象之外的其他对象类型。

宿主对象

提起宿主对象,首先想到的肯定是浏览器(其实JavaScript的宿主很多的,除了浏览器,还有可以V8的node环境等)。

在浏览器环境中,我们都知道全局对象是 window,window 上又有很多属性,如 document,还有我们总是使用的console。

实际上,这个全局对象 window 上的属性,一部分来自 JavaScript 语言,一部分来自浏览器环境。(虽然说宿主的行为完全由宿主决定,但是语言规范相关的属性,是所有宿主一致都有的。)

JavaScript 标准中规定了全局对象属性,W3C 的各种标准中规定了 Window 对象的其它属性。宿主对象也分为固有的和用户可创建的两种,比如 document.createElement 就可以创建一些 DOM 对象。

这个部分不打算详细讲浏览器的知识点(有专门的文章来写它),我们来看下面的内置对象分类。

内置对象·固有对象

我们在前面说过,固有对象是由标准规定,随着 JavaScript 运行时创建而自动创建的对象实例。固有对象在任何 JavaScript 代码执行前就已经被创建出来了,它们通常扮演者类似基础库的角色。

这些对象非常多。其中的很多对象是我们根本没有见过的。ECMA 标准有固有对象的文档,有兴趣的可以查看。在这里不做更多讲解。

内置对象·原生对象

我们把 JavaScript 中,能够通过语言本身的构造器创建的对象称作原生对象。在 JavaScript 标准中,提供了 34个构造器。有如下的分类:

1

通过这些构造器,我们可以用 new 运算创建新的对象,所以我们把这些对象称作原生对象。几乎所有这些构造器的能力都是无法用纯 JavaScript 代码实现的。

这些构造器创建的对象多数使用了私有字段, 例如:

  • Error: [[ErrorData]]
  • Boolean: [[BooleanData]]
  • Number: [[NumberData]]
  • Date: [[DateValue]]
  • RegExp: [[RegExpMatcher]]
  • Symbol: [[SymbolData]]
  • Map: [[MapData]]

这些私有字段,即使我们使用原型链拷贝的方式,都没有权限访问到。我们可以认为,所有这些原生对象都是为了特定能力或者性能,而设计出来的“特权对象”。

特殊之处

在固有对象和原生对象中,有一些对象的行为跟正常对象有很大区别。它们常见的下标运算(就是使用中括号或者点来做属性访问)或者设置原型跟普通对象不同。

  • Array:Array 的 length 属性根据最大的下标自动发生变化。
  • Object.prototype:作为所有正常对象的默认原型,不能再给它设置原型了。
  • String:为了支持下标运算,String 的正整数属性访问会去字符串里查找。
  • Arguments:arguments 的非负整数型下标属性跟对应的变量联动。
  • 模块的 namespace 对象:特殊的地方非常多,跟一般对象完全不一样,尽量只用于 import 吧。
  • 类型数组和数组缓冲区:跟内存块相关联,下标运算比较特殊。