探究JavaScript: Object
零、Object 是数据类型中的一种
众所周知,JS 中七大数据类型
- Undefined
- Null
- Boolean
- Number
- String
- Symbol (ES6)
- Object (引用类型)
前六种为基本类型,第七种,也就是今天的主角 Object 是「引用类型」,何为引用类型?
在 ECMAScript 中,引用类型是一种数据结构,用于将数据和功能组织在一起(常被称为类,不准确,无类和接口的基本结构)。而对象是某个特定引用类型的实例。
与基本类型对比来看,更容易理解:
基本类型在内在中具有固定的大小,而引用类型则不同。例如,对象可以具有任意的长度,无固定大小。
基本类型变量存的是数据的具体值,而引用类型变量保存的是值的引用。(名副其实 —— 引用)
一、Object 是函数?
1 | console.log(typeof Object) // 结果:function |
没错,Object 是系统提供的构造函数。何为构造函数?只是出于创建新对象的目的,以首字母大写(潜规则)的一个普通函数而已。这么用:
1 | // 实例化一个对象 |
再来看,与实例息息相关相关的两个对象(构造函数也是对象)
1 | // 查看其原型 |
当然,在知道其构造函数或原型时,也可以通过如下方式判断:
1 | // 判断原型与实例对应关系 |
诶?Object 的原型为空!不,此空非空。让我们解开他神秘的面纱
1 | let personPrototype = Object.getPrototypeOf(person) |
具体每个属性都有何用处,暂时就不展开了。
那么有个问题,为什么我们使用 console.log()
时,看不到这些?
换句话说,这些属性如何做到隐藏?其实非常简单,拎出一个属性来看
1 | // 获取 personPrototype 的 constructor 属性的描述符 |
注意,enumerable
属性,此时为 false
,不可枚举。说明 console.log()
打印对象时,只会展示可枚举的属性。让我们来实验一下:
1 | Object.defineProperty(personPrototype, 'constructor', { |
终于,一切真相大白。那么,趁机我们来验证下,「引用」类型的内涵
1 | console.log(Object.prototype) // 结果:console.log(Object.prototype) |
证明,我们变量 personPrototype
只是一个指向 Object.prototype
的指针,我们刚刚修改的是同一个对象。
总结:Object 只是一个普通的函数,但其原型上定义了各种隐藏的 Object 的属性。我们每次实例化一个对象时,只是继承了 Object 原型中的方法而已。
二、探究Object 与其他引用类型的关系
如果说函数、数组都是对象,Object 与 Function、Array……这些构造函数又有什么联系呢?
直入虎穴,Object 与 Function
1 | // 定义一个函数 |
竟然,函数也有 toString
方法。不得不怀疑与 Object 千丝万缕的关系,让我们扒一扒,先看其原型与构造函数。
1 | // 查看其原型 |
现在,我们知道,我们定义一个函数时,其实就是通过 Function
构造函数,实例化一个对象而已,其原型是名为 [Function]
的一个对象。
如今,想起其他定义函数的方法,就很自然了
1 | // 实例化 |
那么 [Function]
原型究竟是个什么东西?有什么属性。
1 | let functionPrototype = Object.getPrototypeOf(sayName) |
所以说,这个 [Function]
是直接由 Object 函数构造的,这不废话吗!不,请注意「直接」,说明 Function 与 Object 存在直接继承关系。那么,大胆试一下:
1 | console.log(sayName instanceof Function) // 结果:true |
炸裂了,不但 Function 是Object的实例,连 Object 也是 Object 的实例!他们到底是如何继承的?
1 | console.log(Object.getOwnPropertyNames(sayName)) |
似乎只是原型继承 Object,上边这些方法应该是 Function 构造函数实现的。
三、真相
似乎悟到了什么……
- 如果把函数看做「对象」,那么所有函数的原型都是
[Function]
,构造函数都是[Function: Function]
,包括 Object、Function
1 | console.log(Object.getPrototypeOf(Object)) // 结果:[Function] |
- 如果把函数看做「构造函数」,那么他们的原型各不相同
1 | console.log(Object.prototype) // 结果:{ constructor: [Function: Object] } |
进一步验证
1 | console.log(Object.getPrototypeOf(Object) === Function.prototype) |
终于,水落石出,上图
代码所在地址:boboidream/JavaScriptGo
参考资料
- 《JavaScript 高级程序设计》
- 本文链接:https://www.wenboz.com/p/3a52.html
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!