对于普通对象,我们理解了它的 key-value 数据结构 和 原型链相关的知识 基本就可以了,但是如果想用好JS的对象还远远不够。
因为我们日常工作中,接触到的主要 API,几乎都是由这些对象提供的。
根据对象的来源来分类
- 宿主对象
- 内置对象
- 固有对象:
- 原生对象
- 普通对象
宿主对象
JavaScript 宿主环境提供的对象。
例如浏览器的window、document,Node的global
window 和 global 里面有一些就是宿主对象,有一些就是内置对象
内置对象
由 JavaScript 语言提供的对象
固有对象
随着 JavaScript 运行时(Runtime)创建而自动创建的对象实例 (程序运行生命周期:编译时、链接时、加载时、运行时)
ECMA 标准为我们提供了一份固有对象表,里面含有 150+ 个固有对象,但是自己遍历了一下有 900+ 个固有对象
例如: Math、JSON、Symbol、Promise、Boolean、Array....
原生对象
可以由用户通过 Array、RegExp 等内置构造器或者特殊语法创建的对象
普通对象
由{}语法、Object 构造器或者 class 关键字定义类创建的对象
函数对象和构造器对象
在Javascript中,除了原始类型,其他都是对象。其中很特殊的对象是函数和构造器。
JavaScript 用对象模拟函数的设计代替了一般编程语言中的函数。
函数对象:具有 [[call]] 私有字段的对象
构造器对象:具有私有字段 [[construct]] 的对象。
用 function 关键字来创建的函数,它是必定是同时是函数和构造器。
同一个函数而言,作为函数和构造器使用时,它们的表现会不太一致。
[[construct]]的步骤大概可以分成3步:
1. 以 fn.prototype 为原型创建新对象
2. 以新对象为this,调用[[call]]
3. 如果[[call]]返回的是对象,那么,返回这个对象,否则返回第一步创建的新对象
有趣的现象:
function Person() {
return {}
}
new Person instanceof Person // false
按照上面的说法,如果是构造器对象的话,那它也必定是函数对象。
作为函数和构造器使用时不一致的例子:
1. new String() 和 String()
2. Symbol 只能作为一个函数来使用(Symbol 应该是一个箭头函数,箭头函数只能作为函数使用,不能作为构造器)
3. Image 只能作为构造器使用,作为函数使用时会报错
对象是由 function 创建的,而 function 本身也是一个对象
我们知道,在一般情况下(没有人为修改)如果一个对象的__proto__是一个函数的prototype,就说明这个对象是由这个函数构建的。
追踪到最源头的时候,我们又发现了一个有趣的现象(Function:我构造我自己):
Function.prototype === Function.__proto__
特殊行为的对象
Array:length 属性根据最大的下标
Object.prototype:不允许设置 __proto__
Arguments: 对应的下标属性和对应的变量联动联动
function aaa(name) {
arguments[0] = '666';
console.log(name);
}
aaa(233); // 最终打印出来666
这是不那么有规律、不那么优雅的知识,但是正是这些特殊的对象,给我们提供了很多基础能力。