原型链的树形结构
总所周知,js有七种数据类型,其中一种引用类型Object,其他六种基本类型:Number、String、null、undefined、symbol、Boolean。
在讨论原型的时候,我们讨论的还是这个引用类型Object。
我们先看一下这段代码
var a = 20;
var b = 'abc';
var c = true;
var d = { m: 20 }
通过这段代码我们可以看一看JS的栈内存和堆内存
JS栈内存与堆内存
对于引用类型的变量d,我们可以在栈中记录的是其堆中的引用地址。我们可以看到 d 的属性以及值存储在堆中,我们可以通过 d.m 获取20这个值,但我们调用 d.toSting() 时我们可以发现,这个方法是存在的。
var d = { m: 20 } console.log(d.toString()) // '[object Object]'
为什么有toString 属性
根据执行结果可以知道toSting是一个函数,也就是属于对象,属于引用类型。
可以确定,toString 属于引用类型,而对于我们生成的引用变量d来说,它有一种特殊的方式,通过这一方式可以访问toString。同样的这一方式还可以访问 valueOf、isPrototypeOf等方法。
而每个生成的一个新的对象,我们知道,它们都具有这么一个方式,可以以这个方式访问我们未曾定义的方法集合。
在我们先将这个方式称之为 ‘共’ ,如图所示。
我们定义一个对象obj,在chrome浏览器里
var obj = {
name:'he',
}
console.dir(obj)
我们可以看到打印出来的结果
- obj 本身有一个属性 name(这是我们给它加的)
- obj 还有一个属性叫做 __proto__(它是一个对象)
- obj.__proto__ 有很多属性,包括 valueOf、toString、constructor、hasOwnProperty 等
也就是说这个共的属性名的真正名字就是 __proto__ 也就是我们平时说的原型。
而obj.__proto__ 指向的集合,也就称之为 Object.prototype
现在回到我们的问题:obj 为什么会拥有 valueOf / toString / constructor等属性?
答案:这跟 __proto__ 有关。
对于 obj 来说,本身不具有toString / valueOf 方法,通过 __prototype__ 以后可以 以 obj.toString 进行访问
当我们读取obj.toString 时,JS引擎是这样的
- 查询 obj 本身是否有toString属性,没有就到下一步
- 查询obj.__proto__ 上是否有toString属性,没有就到下一步
- 查询obj.__proto__.__proto__ (此时为null)上是否有toString属性,没有就继续查找
对于obj来说,在obj.__proto__ 找到toSting,所以调用 obj.__proto.toString 方法
而在这一过程中,也就是 [读取属性] 的过程中,就像摸着链子一步一步寻找目的地一样。
这条链子,我们就称之为原型链
当然,这只是对 new Object() 生成的对象,当我们把整个原型链可以放置到所有的数据结构时, 每个不同类型的对象也同样会拥有他们不同的集合。
所以,数组有一个 Array.prototype、函数有一个Function.prototype、Number类型对象有一个Number.prototype 。。。
JS一切皆对象,其实Array.prototype 、Function.prototype ... 都属于 Object类型。
var arr = [1,2,3] console.log(arr.toString()) // 1,2,3
我们可以画图
注:原型链的部分树形结构
- [p] 表示的是 __proto__
- console.log方法,Array.prototype 打印出来为数组,Function.prototype无法打印结果
- 建议使用console.dir()打印,以便查看结果
- 。。。 表示包括String、Symbol、Date、Number、Boolean、Error....
总结:
- JS中为了方便区分,生成了许多如Array、Function、String...不同的数据类型
- 每个数据类型的通用属性集合被放置在一个对象中,用户定义的变量根据其数据类型可以获取不同的方法,同时其顶端都属于Object.prototype
延伸:obj 的由 Object所构造,但Array,Function又是由谁构造出来的呢。也就是说构造函数是什么情况呢?
参考资料:JavaScript万物诞生记
这篇文章通过比较诙谐的方式,以现有的证据来说明了JS不同数据类型是怎么出现的