原型链的树形结构

  总所周知,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)

  我们可以看到打印出来的结果

  1. obj 本身有一个属性 name(这是我们给它加的)
  2. obj 还有一个属性叫做 __proto__(它是一个对象)
  3. 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引擎是这样的

  1. 查询 obj 本身是否有toString属性,没有就到下一步
  2. 查询obj.__proto__ 上是否有toString属性,没有就到下一步
  3. 查询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....

  总结:

  1. JS中为了方便区分,生成了许多如Array、Function、String...不同的数据类型
  2. 每个数据类型的通用属性集合被放置在一个对象中,用户定义的变量根据其数据类型可以获取不同的方法,同时其顶端都属于Object.prototype

  

  延伸:obj 的由 Object所构造,但Array,Function又是由谁构造出来的呢。也就是说构造函数是什么情况呢?

  参考资料:JavaScript万物诞生记

  这篇文章通过比较诙谐的方式,以现有的证据来说明了JS不同数据类型是怎么出现的

原文地址:https://www.cnblogs.com/h246802/p/9794264.html