出一篇19年写的文章吧,如有不对之处,请大佬指正
Date:2019-09-23 14:06:56
javascript 一切皆对象浅析
最新的 ECMAScript 标准定义了 8 种数据类型:
Boolean
Null
Undefined
Number
BigInt
String
Symbol
和 Object
,注意:这里没有 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 部分
故可以断言:Boolean
、Number
、String...
等对象是由Function
对象new
出来的,Math
、JSON...
等对象都是由Object
对象new
出来的!故可以推断,js 的内置对象(或者叫原型)的根就在Function
和Object
!
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.prototype
的prototype
、__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",该值只可读。