javascript一切皆对象-浅析

本文详细探讨了JavaScript中的new操作符的工作原理,包括如何实例化对象、继承、改变this上下文以及构造函数的返回值影响。同时,文章深入剖析了原型链的构建,通过实例展示了instanceof运算符的用法,以及Function和Object在原型链中的特殊地位。文章最后揭示了原型链的终点是null,并通过一系列实验验证了这一结论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

出一篇19年写的文章吧,如有不对之处,请大佬指正

Date:2019-09-23 14:06:56

javascript 一切皆对象浅析

最新的 ECMAScript 标准定义了 8 种数据类型:

Boolean Null Undefined Number BigInt String SymbolObject,注意:这里没有 Function 类型;
对于Function类型,ECMAScript 标准:“函数是一个附带可被调用功能的常规对象。”

还有一些:Math RegExp Events对象;

一、从new说起

先看一个示例:

function Car(make, model, year) {
   this.make = make;
   this.model = model;
   this.year = year;
}
var myCar = new Car("Eagle", "shaoanan", "1994")

// 输出:Car {make: "Eagle", model: "shaoanan", year: "1994"}

new做了哪些事情?

1、实例化一个对象:myCar

2、继承自 Car :即将 myCar.__proto__ 指向 Car.prototype

3、更改 this 的上下文,将this绑定到新创建的对象上:即将 this 指向 myCar

4、返回新对象,即:由构造函数返回的对象就是 new 表达式的结果,如果该函数没有返回对象,则返回 this;

注意第四步:构造函数 return 的是引用类型(如:[ ], { }, function(){}, new Date)时,才会对构造函数有影响,值类型(’’, false, null, undefined, 3)则没有影响;

做个测试:

function Car1(make, model, year) {
   this.make = make;
   this.model = model;
   this.year = year;
   return {};               // 返回了一个引用类型
}
function Car2(make, model, year) {
   this.make = make;
   this.model = model;
   this.year = year;
   return "car-2";          // 返回了一个值
}
var myCar1 = new Car1("Eagle", "shaoanan", "1994")
var myCar2 = new Car2("Eagle", "shaoanan", "1994")

// 输出:{}
// 输出:Car2 {make: "Eagle", model: "shaoanan", year: "1994"}

另外,明确区分引用类型与基本类型,如:false 是基本类型, 而 new Boolean('false') 是引用类型!

var b = new Boolean(false);
if( b ){ console.log("此时有输出!") }
if( false ){ console.log("此时无输出!") }

// 再具体一点
var a = false, b = new Boolean(false), c = b;
Object.defineProperty(c, 'value', {value: true});
console.log(b, c)
Object.defineProperty(a, 'value', {value: true});     // 报错

typeof b;                   // "object"
typeof false;               // "boolean"
b == false;                 // true
b === false;                // false
b instanceof Boolean;       // true
b instanceof Object;        // true
Boolean instanceof Object   // true,证明了Boolean类型是Object对象的实例
二、原型链的形成

写在前面:instanceof运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

object instanceof constructor

即:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链(object.__proto__)上

Array instanceof Function                          // true
Array.__proto__ === Function.prototype             // true

Object instanceof Function                         // 请注意
Boolean instanceof Function
Number instanceof Function
String instanceof Function
Date instanceof Function
Promise instanceof Function
Symbol instanceof Function
Error instanceof Function
RegExp instanceof Function
Set instanceof Function
Proxy instanceof Function
......

Math instanceof Object
JSON instanceof Object
Function instanceof Object                         // 请注意

// 以上全都输出 true

基本上,每个对象都有prototype__proto__constructor三个属性,通俗一点解释:prototype是该对象的原型,__proto__是实现原型链的核心(目前只有部分浏览器可在控制台输出),constructor指向该对象的构造函数

var a = [];
a.constructor === Array

Boolean.constructor === Function
......其他同 instanceof 部分

故可以断言:BooleanNumberString...等对象是由Function对象new出来的,MathJSON...等对象都是由Object对象new出来的!故可以推断,js 的内置对象(或者叫原型)的就在FunctionObject!

Object.constructor === Function        // true
Function.constructor === Function      // true

// 上面证明了 Object 和 Function 互为对方的实例,But:
Object.__proto__ === Function.prototype      // true
Function.__proto__ === Object.prototype      // false, ??????????

Function instanceof Function                 // true
Array instanceof Array                       // false
Boolean instanceof Boolean                   // false
...
这说明:Function 是自己 new 的自己,其他内置对象不是,那么(so):
Function.__proto__ === Function.prototype    // true

看一下Function.__proto__Function.prototype都输出:f () { [native code] },说明到这里已经超出 js 的“可控范围”了,也就说Function到头了!

那为什么说一切皆对象呢?为什么说原型链的尽头是null呢?Function到头了,Object还到头呢!继续控制台输出:

Object.__proto__              // native code ---- 到头
Object.prototype              // 震惊!输出了一个对象!

// 展开看一下
{
   constructor: ƒ Object()
   hasOwnProperty: ƒ hasOwnProperty()
   isPrototypeOf: ƒ isPrototypeOf()
   propertyIsEnumerable: ƒ propertyIsEnumerable()
   toLocaleString: ƒ toLocaleString()
   toString: ƒ toString()
   valueOf: ƒ valueOf()
   __defineGetter__: ƒ __defineGetter__()
   __defineSetter__: ƒ __defineSetter__()
   __lookupGetter__: ƒ __lookupGetter__()
   __lookupSetter__: ƒ __lookupSetter__()
   get __proto__: ƒ __proto__()
   set __proto__: ƒ __proto__()
}

好的,按照之前的思路,继续找Object.prototypeprototype__proto__constructor这三个属性,依次在控制台输出:

Object.prototype.prototype                // undefined
Object.prototype.__proto__                // null !!!!!!!!!!!----终于找到了!
Object.prototype.constructor              // ƒ Object() { [native code] }

至此,我们又回到了Object对象!同时也证明Object instanceof Object,但是

Object.__proto__ === Object.prototype     // false

这只能说明一个问题:Object.prototype 存在于(仅有一部分) Object.__proto__上,并不全等!

Object.__proto__ === Function.prototype      // true

这个能说明Function.prototype 完全存在于(所有) Object.__proto__上,是全等!

推断一下形成这个结果的原因,假设:有一部分native code既被Function.prototype使用,也被Object.prototype使用,而 Object.__proto__这个部分代码继承了以上两者中的一部分或者全部,会不会形成这样的结果呢?

// 先验证两者有公共的 native code
Function.prototype.valueOf                                  // ƒ valueOf() { [native code] }
Object.prototype.valueOf                                    // ƒ valueOf() { [native code] }
Function.prototype.valueOf === Object.prototype.valueOf     // true!验证成功!

刚才已经验证Object.prototype.__proto__ === null,那Function.prototype.__proto__(虽然Function.prototype已经是native code 了)呢?控制台输出:

Function.prototype.__proto__                    // 简直无情,竟然是个对象

// 展开看一下
{
   constructor: ƒ Object()
   hasOwnProperty: ƒ hasOwnProperty()
   isPrototypeOf: ƒ isPrototypeOf()
   propertyIsEnumerable: ƒ propertyIsEnumerable()
   toLocaleString: ƒ toLocaleString()
   toString: ƒ toString()
   valueOf: ƒ valueOf()
   __defineGetter__: ƒ __defineGetter__()
   __defineSetter__: ƒ __defineSetter__()
   __lookupGetter__: ƒ __lookupGetter__()
   __lookupSetter__: ƒ __lookupSetter__()
   get __proto__: ƒ __proto__()
   set __proto__: ƒ __proto__()
}

有没有什么发现?是不是跟上面Object.prototype的输出一模一样?!保险起见,再验证一下,控制台输出:

Function.prototype.__proto__ === Object.prototype           // true 哦了!

Function.prototype instanceof Object                        // true

到此,可以证明上面的推断是正确的!

同理,也可以推断Function.__proto__.__proto__ === Object.prototype

所有的__proto__、prototype最终都指向了Object.prototype,而Object.prototype.__proto__ === null,所以我们说:一切皆对象!

另外,在Object.prototype.constructor的介绍中,MDN是这样描述的:返回创建实例对象的 Object 构造函数的引用。此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。对原始类型来说,如1,true和"test",该值只可读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值