先有对象还是先有函数,鸡生蛋、蛋生鸡的问题。有关js里内置对象Function和Object的思考

本文深入探讨了JavaScript中对象原型链的构建原理,从Function、Object到Object.prototype的关系,揭示了万物皆对象的本质。

js里创建的函数本身作为一个实例对象都是由内置对象Function作为构造函数创造出来的,所谓var f = funciton(a){b}即等同于f = new Function(a,b)。

同时js里Object也是一个构造函数,因此他也是Function加工出来的。

Function作为一个对象实例,也是Function加工出来的,具有自原性。

但Function的加工原料,也就是原型链的父原型是Object,即Object可以通过Function变成Function。

那么是什么通过Function的加工变成了Object呢?

这就是最原始的那个静态种子,答案就是Object.prototype,在控制台里打印出来是:

  1. {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
    1. constructor: ƒ Object()
    2. hasOwnProperty: ƒ hasOwnProperty()
    3. isPrototypeOf: ƒ isPrototypeOf()
    4. propertyIsEnumerable: ƒ propertyIsEnumerable()
    5. toLocaleString: ƒ toLocaleString()
    6. toString: ƒ toString()
    7. valueOf: ƒ valueOf()
    8. __defineGetter__: ƒ __defineGetter__()
    9. __defineSetter__: ƒ __defineSetter__()
    10. __lookupGetter__: ƒ __lookupGetter__()
    11. __lookupSetter__: ƒ __lookupSetter__()
    12. get __proto__: ƒ __proto__()
    13. set __proto__: ƒ __proto__()

而Object.prototype.__proto__==null

Object.prototype.constructor==Object()

那么这就可以这样来梳理了,null作为原料通过Object函数构造出了Object.prototype,

Object.prototype作为原料通过Function函数构造出了Object,

Object作为原料通过Function函数构造出了Function本身。

完美解决了,对吧!

null是什么呢?和数字符字面常量,字符串字符常量,true,false,undefine一起作为js的基本类型,再加上那些运算符等符号就可以看作是开天辟地的真正基础了。而这些基础为什么不是对象呢?不是js里万物皆对象吗?

对于js的创造者来说,仅仅是利用一些相等搭了一个圈,但沉浸在这个世界的人们就永远也看不到其中事物的本源了。

这大概和鸡生蛋还是蛋生鸡这样的哲学本源问题是一致的,就像无论唯心还是唯物,在 西部世界 里所追寻的那个迷宫的核心究竟如何,只要还在其中,就是永远没有答案的。

 

<think>我们正在讨论JavaScript中的Object。用户的问题是关于两个代码片段中的Object的含义区别,以及全局内置对象Object构造函数Object的区别。 根据之前的对话,我们已经解释了: - 第一行代码中的Object.prototype:这ObjectJavaScript内置的Object构造函数Object.prototype是所有对象原型链的终点(除了null)。 - 第二行代码中的Object.__proto__:这Object也是指内置的Object构造函数,但作为函数对象实例,它的__proto__指向Function.prototype。 现在用户进一步询问:全局内置对象Object构造函数Object的区别。 实际上,在JavaScript中,全局内置对象Object构造函数Object是同一个东西。但是,我们需要从不同的角度来理解它: 1. 作为构造函数Object是一个函数,可以用new调用(如:new Object())来创建对象实例。 2. 作为全局对象ObjectJavaScript全局对象(在浏览器中是window,在Node.js中是global)的一个属性,这个属性指向构造函数。 也就是说,我们通常所说的Object,在JavaScript中是一个内置的构造函数,同时它也是一个对象(因为函数也是对象)。 因此,严格来说,并没有两个不同的Object,而是同一个Object在不同的使用场景下扮演不同的角色: 角色1:构造函数 - 用于创建对象实例,可以通过new调用。 - 例如:`var obj = new Object();` 或直接使用对象字面量`{}`(字面量语法底层会调用Object构造函数)。 角色2:函数对象 - 因为函数也是对象,所以Object构造函数本身也是一个对象,因此它可以拥有属性(如:Object.prototype, Object.assign, Object.keys等静态方法)原型链(Object.__proto__指向Function.prototype)。 所以,用户可能感到困惑的是同一个Object既可以作为构造函数使用,又因为它本身是一个对象而具有属性方法(包括静态方法原型链)。 我们可以这样总结: - 当我们使用`Object`来创建对象(如`new Object()`)时,它作为构造函数。 - 当我们直接访问`Object`上的属性(如`Object.prototype`或`Object.keys`)时,我们把它当作一个全局对象函数对象)来使用。 注意:在JavaScript中,函数是一等公民,函数也是对象。所以,Object构造函数本身就是一个对象,它是由Function构造函数创建的。因此,我们有: Object instanceof Function // true 同时,Function也是一个对象,所以: Function instanceof Object // true 下面我们详细解释: ### 1. Object作为构造函数 - 用于实例化对象。当使用`new Object()`时,它会创建一个普通对象。 - 我们也可以使用对象字面量`{}`,它等价于`new Object()`(但不完全一样,字面量创建不会实际调用构造函数,但结果相同)。 - 通过Object构造函数创建的对象,其原型指向Object.prototype。 ### 2. Object作为函数对象 - 由于函数也是对象Object构造函数本身也有自己的属性方法(静态方法): Object.create() Object.assign() Object.keys() Object.defineProperty() 等等 - 同时,Object构造函数作为对象,它也有自己的原型链: Object.__proto__ === Function.prototype // true 因为Object是通过Function构造函数创建的。 - 另外,Object构造函数也有一个特殊的属性`prototype`,这个属性指向一个对象(称为原型对象),这个原型对象是所有通过Object构造函数创建的实例的原型。注意:这个`prototype`属性是函数对象特有的(只有函数对象才有),而其他普通对象没有(普通对象有__proto__)。 因此,我们可以这样理解: - 构造函数Object函数对象)的`prototype`属性指向一个对象(即Object.prototype),这个对象是所有普通对象的原型。 - 而构造函数Object本身作为对象,它的原型(通过__proto__)指向Function.prototype。 图示: ```mermaid graph LR A[Object构造函数] --> |prototype| B[Object.prototype] A --> |__proto__| C[Function.prototype] B --> |__proto__| D[null] C --> |__proto__| B // 因为Function.prototype也是一个对象,所以它的原型是Object.prototype ``` 注意:Function.prototype也是一个对象,所以它的__proto__指向Object.prototype。 验证: ```javascript console.log(Function.prototype.__proto__ === Object.prototype); // true ``` 所以,Object构造函数本身是一个函数对象,它是由Function构造函数创建的实例,因此它的原型指向Function.prototype。同时,它又有一个prototype属性,指向一个对象Object.prototype),这个对象是所有通过Object构造函数创建的实例的原型,也是原型链的顶端(除了null)。 总结区别: - 当我们说“全局内置对象Object”时,通常是指这个全局可访问的Object(它本身是一个函数对象)。 - 当我们说“构造函数Object”时,强调的是它用来构造对象的功能(即通过new调用创建对象)。 但实际上,它们是同一个东西,只是在不同语境下的不同称呼。 为了更清晰,我们可以举一个例子: ```javascript // 作为构造函数使用 const obj = new Object(); // 或者 const obj = {}; // 作为函数对象使用(调用静态方法) const keys = Object.keys(obj); ``` 在上面的代码中,同一个Object,在第一种情况下被当作构造函数(使用new调用),在第二种情况下被当作一个包含静态方法的对象。 另外,需要注意的是,Object这个函数对象本身也是Object的实例吗?因为任何对象都是Object的实例,所以: ```javascript Object instanceof Object // true ``` 这是因为:Object作为对象,它的原型链是: Object -> Function.prototype -> Object.prototype -> null 所以,沿着原型链,Object.prototype在Object的原型链上,因此`instanceof`返回true。 同理: ```javascript Function instanceof Function // true Function instanceof Object // true ``` 这些看起来矛盾的结果,都是因为JavaScript原型链的设计。 现在,我们来成相关问题,以帮助用户更深入理解: 相关问题: 1. 为什么`Object instanceof Function``Function instanceof Object`都返回true? 2. 如何使用Object构造函数创建对象,与对象字面量创建对象有什么区别? 3. Object构造函数上的静态方法有哪些?它们的作用是什么? 4. 为什么说函数也是对象?请用Object构造函数举例说明。 注意:在回答中,我们将使用LaTeX格式来写数学表达式(虽然本问题中没有数学表达式,但如果有变量名等,我们也会用$...$包裹),但这主要是代码术语。 后,我们按照用户要求,在引用的地方添加引用标记。注意,用户给出的引用[1][2][3]是关于构造函数原型的,我们可以适当引用。 </think>### 全局内置对象 `Object` 与构造函数 `Object` 的区别 在 JavaScript 中,**全局内置对象 `Object`** **构造函数 `Object`** 本质是同一个实体,但在不同使用场景下表现出双重角色。以下是详细解析: #### 💠 **1. 作为全局内置对象(Namespace)** - **本质**:JavaScript 引擎预定义的顶级对象,提供基础对象操作能力 - **核心特征**: - 包含静态方法(无需实例化即可调用) - 作为所有对象的逻辑命名空间 - **核心方法举例**: ```javascript Object.keys({a:1}) // ["a"] (获取对象键) Object.assign({}, {b:2}) // {b:2} (合并对象)[^1] Object.freeze(obj) // 冻结对象防止修改 ``` #### 🔨 **2. 作为构造函数** - **本质**:用于创建对象实例的函数 - **核心特征**: - 可通过 `new` 调用成实例 - 拥有 `prototype` 属性(原型对象) - **使用示例**: ```javascript const obj = new Object(); // 显式构造对象 obj.name = "小明"; // 添加属性[^1] ``` 等价于对象字面量: ```javascript const obj = { name: "小明" }; // 隐式调用构造函数 ``` --- ### 🔗 双重角色关系图解 ```mermaid graph LR A[Object] --> |作为全局对象| B[提供静态方法<br>Object.keys<br>Object.assign] A --> |作为构造函数| C[new Object()<br>创建实例对象] C --> |实例继承| D[Object.prototype] D --> |包含基础方法| E[.toString()<br>.hasOwnProperty()] ``` --- ### ✅ 关键区别总结 | **特性** | 全局内置对象 `Object` | 构造函数 `Object` | |------------------|----------------------------|----------------------------| | **调用方式** | 直接调用静态方法 | 通过 `new` 实例化 | | **核心功能** | 对象操作工具方法 | 创建对象实例 | | **内存位置** | 全局唯一引用 | 每次 `new` 创建新实例 | | **原型链角色** | 无直接原型关联 | 通过 `prototype` 提供继承 | | **典型使用场景** | `Object.keys(obj)` | `const obj = new Object()` | --- ### ⚠️ 特别说明:原型链验证 验证构造函数与全局对象的一致性: ```javascript // Object 构造函数本身是函数对象 console.log(typeof Object); // "function" // Object 构造函数继承自 Function.prototype console.log(Object.__proto__ === Function.prototype); // true [^2] // Object.prototype 是原型链终点 console.log(Object.prototype.__proto__); // null [^3] ``` --- ### 🌰 实际应用场景 ```javascript // 作为全局对象使用(工具方法) const source = { a: 1 }; const target = Object.assign({}, source); // 复制对象[^1] // 作为构造函数使用 const person = new Object(); person.name = "张三"; console.log(person.hasOwnProperty("name")); // true (继承自Object.prototype)[^3] ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值