Why系列: A.__proto__.__proto__.__proto__ === null

简介: __proto__ 是什么__proto__一般情况指向的是该对象的构造函数的prototype

1.JPG


前言



很久以前,还比较白的时候呀, 某某同事,show me的下面的code


function A(){}
A.__proto__.__proto__.__proto__
复制代码


然后问我,下面这个玩意A.__proto__.__proto__.__proto__是啥,然后我一脸懵逼,prototype还知道一点,这个__proto__,还来三个,是个什么鬼。于是我一直不能放下这个问题,虽然我很懒,很不喜欢费脑子,但是这个坎还是过不去,最近两天研究了大半天,就有了这篇文章。


至于答案, 看本文标题就知道值为 null。


我还很负责的告诉你,下面的值也是null:

这个和前面代码是有区别的,这里用new进行了实例化。


function A(){}
var a = new A();
a.__proto__.__proto__.__proto__
复制代码


经典之图


先来一张非常经典的图,真的是非常经典,你看懂他,你就懂了整个世界,然后整个世界就等着你去拯救整个世界。


2.JPG


__proto__和prototype


都谁有的问题


typeof === object(null除外)的有__proto__

typeof === function的有__proto__prototype

null和undefined都没有


__proto__ 是什么


__proto__一般情况指向的是该对象的构造函数的prototype,一般情况,因为还有很二般的情况。


先来看个简单的例子, 下面的输出是true


function A(){}
var a = new A()
console.log(a.__proto__ === A.prototype)
复制代码


a.__proto__.__proto__怎么推导呢,

依据上面a.__proto__ === A.prototype,

那么a.__proto__.__proto__就等同A.prototype.__proto__

继续推导得到 a.prototype.constructor.prototype,然后你去一比,结果是false。 所以原型链这玩意, 是基于一些规则下玩的。


a.__proto__.__proto__  === A.prototype.constructor.prototype  
// false
复制代码


几条规则


这个先不纠结, 我们先看看上图,我们先得知道或者记住这几个规则


  1. Object.prototype.__proto__ === null
    不要纠结,铁律
  2. Object.__proto__ === Function.prototype


这么理解,Object,Number, Error等等这些函数都是Function创建的,下面就说明 这些的constructor就是Function。


这里比较有意思的就是 Function.constructor也是Function。

那就有Object.__proto__ === Function.prototype === Function.__proto__


Object.constructor.prototype  === Function.prototype  
// true
Function.constructor === Function
// true
复制代码


  1. Function.prototype.__proto__ === Object.prototype

有没有点一切皆对象的设计。


Function.prototype.constructor === Object 
// false
复制代码


自定义函数,默认情况下,比如 function Person(){}有下面的规律:

Person.prototype.__proto__ === Object.prototype

Person.constructor === Function


正题


有这几个基本东西,我们就可以来推导了。


先看下面的代码,


js 我们来推到 A.__proto__.__proto__.__proto__

function A(){} 
var a = new A()
复制代码
  1. A.__proto__

A构造函数是Function

A.constructor === Function

A.__proto__ === Function.prototype


  1. A.__proto__.__proto__

A.__proto__.__proto__ === Function.prototype.__proto__

依据 Function.prototype.__proto__ === Object.prototype

A.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype


  1. A.__proto__.__proto__.__proto__

A.__proto__.__proto__.__proto__ === Object.prototype.__proto__

依据 Object.prototype.__proto__ === null

A.__proto__.__proto__.__proto__ === null


到此为止,标题部分我们已经推导完毕。

这才哪到哪,继续推导下面的代码


function A(){}
var a = new A();
a.__proto__.__proto__.__proto_
复制代码


还是上面代码,我们接着推导a.__proto__.__proto__.__proto__


  1. a.__proto__

a的构造函数是 A

a.constructor === A

a.__proto__ === a.constructor.prototype

a.__proto__ === A.prototype


  1. a.__proto__.__proto__

a.__proto__.__proto__ === A.prototype.__proto__

根据规则三,再参考图,Foo.prototype.__proto__ === Object.prototype

a.__proto__.__proto__ === A.prototype.__proto__ === Object.protype


  1. a.__proto__.__proto__.__proto__

a.__proto__.__proto__.__proto__ === Object.protype.__proto__

根据规则一 Object.prototype.__proto__ === null

a.__proto__.__proto__.__proto__ === null


正题延伸, 加上继承关系


我们再来看看,带继承关系的


function Parent(){}
function Child(){}
Child.prototype = new Parent()
var child = new Child();
复制代码


Parent.__proto__.__proto__.__proto__ === null这个没啥好说的。


Child.prototype.__proto__.__proto__.__proto__

先来看看 Child.prototype.__proto__.__proto__.__proto__


  1. Child.prototype.__proto__

Child.prototype.__proto__ === Child.prototype.constructor.prototype

Child.prototype的原型是 Parent的实例, Child原型的构造函数就是Parent,所以

Child.prototype.__proto__ === Parent.prototype


  1. Child.prototype.__proto__.__proto__

Child.prototype.__proto__.__proto__ === Parent.prototype.__proto__

参考图,Foo.prototype.__proto__ === Object.prototype

Child.prototype.__proto__.__proto__ === Object.prototype


  1. Child.prototype.__proto__.__proto__

Child.prototype.__proto__.__proto__ .__proto__=== Object.prototype.__proto__ === null

child.__proto__.__proto__.__proto__ .__proto__


再来看看child.__proto__.__proto__.__proto__ .__proto__


  1. child.__proto__

child.__proto__ === Child.prototype


  1. child.__proto__.__proto__

child.__proto__.__proto__ === Child.prototype._proto__ === Child.prototype.constructor.prototype === Parent.prototype


  1. child.__proto__.__proto__.__proto__

child.__proto__.__proto__.__proto__ === Parent.prototype.__proto__

参考图Foo.prototype.__proto__ === Object.prototype

child.__proto__.__proto__.__proto__ === Parent.prototype.__proto__ === Object.prototype


  1. child.__proto__.__proto__.__proto__.__proto__

child.__proto__.__proto__.__proto__.__proto__ === Object.prototype.__proto__ === null


正文 再加量


看看如下代码


function Grandpa(){}
function Parent(){}
Parent.prototype = new Grandpa();
function Child(){}
Child.prototype = new Parent()
var child = new Child()
复制代码


我们再来分析child的prototype__proto__ ,你们会说,你有完没完,

那我就不分析了,我来推导公式:


推导公式


  1. 任何自定义的function,默认情况,三次.__proto__必然是null

也就是往上找三代, 包括Function,Object, Error等等


依据 Object.__proto__ === Function.prototype === Function.__proto__

我们来推导Function.__proto__.__proto__ .__proto__


第一步:Function.__proto__ === Function.prototype


第二步:Function.__proto__.__proto__ ===

Function.prototype.__proto__ === Object.protetype


第三步: Function.__proto__.__proto__ .__proto__ ===Object.protetype.__proto__ === null


都是Function构造出来的

我们来测试一下ccc


Child.__proto__.__proto__.__proto__ === null // true
复制代码


  1. 继承关系的 function Fn,假设继承次数为 n, fn = new Fn();

那么 fn.__proto__[3 + n] === null

child应该是3+2就是5次


child.__proto__.__proto__.__proto__.__proto__.__proto__ === null // true
复制代码


  1. 继承关系的function Fn,假设继承次数为n

推导 Fn.prototype.__proto__[3+n-1]

Child应该是 4次__proto__


```js
Child.prototype.__proto__.__proto__.__proto__.__proto__ === null // true
```
复制代码


当然上面关联的关系,就自己慢慢看吧


正文之外, class


下面的代码也是遵守规则,至于为什么,问自己喽。


class Grandpa {}
class Parent extends Grandpa{}
class Child extends Parent{};
var child = new Child()
复制代码


关于Number,Boolen, String,Function, Date, Array, RegExp等的__proto__prototype.__proto__


  1. __proto__

因为这些都是Function创建出来的函数,__proto__在函数上时就是表示构造函数的prototype,所以 .__proto__ === .constrcutor.prototype === Function.prototype


  1. .prototype.__proto__

这些老骨头不遵循 __proto__ = 构造函数的prototype 这条规则

在上面提到过了,Function.prototype.__proto__ === Object.prototype, 类推,这些内置的老骨头的 .prototype.__proto__ === Object.prototype


总结


总结, 特别需要记忆的:


  1. Object.prototype.__proto__ === null
  2. Function.prototype.__proto__ === Object.prototype
    内置Number,Boolen, String,Function, Date, Array, RegExp等一样
  3. Object.__proto__ === Function.prototype === Function.__proto__ 联系2,这些东西都是Function创建出来的
  4. Math, JSON的__ptoto__是 Object.prototype typeof 可以看出来这两个是object,而不是Function
  5. function A(){} 默认的原型关系如下

A.prototype.__proto__ === Object.prototype

  1. 有继承关系的function看上面的推断
  2. 对象字面量和new Object() 比如, var a ={}, b = new Object(), c = [];
    a.__proto__ === a.constructor.prototype === Object.protype
    a.__proto__.__proto__ === Object.protype.__proto__ === null
    两次.__proto__ 为null
  3. 基本数据类型string,number,boolean,比如 var a = '', b=10, c= false,
    b.__proto__ === b.constructor.prototype === Number.prototype
    b.__proto__.__proto__ === Number.prototype.__proto__ === Object.prototype
    b.__proto__.__proto__.__proto__ === Object.prototype.__proto__ === null
    三次.__proto__ 为null
  4. null和undefined没有__proto__


最终


  1. 看图
  2. 浏览器输入 xx.__proto__ 或者xx.prototype自己看去
相关文章
|
人工智能 JSON 数据格式
GEE、PIE和AI Earth平台进行案例评测:NDVI计算,结果差异蛮大
GEE、PIE和AI Earth平台进行案例评测:NDVI计算,结果差异蛮大
396 0
基于宜搭的“企业报销流程”实践案例
报销是一个企业的典型场景,本案例着重讲述一个典型的财务报销流程的搭建,已介绍宜搭流程相关的核心功能。报销由员工发起申请,填写报销项以及对应的详情信息,发起审批流程。审批流程计划设置为:当前提交人主管,审批人所在部门对应的财务接口人,财务总监(如果金额大于10000元,则需要加入该角色)
基于宜搭的“企业报销流程”实践案例
|
11月前
|
前端开发 JavaScript
Async/Await 如何通过同步的方式(形式)实现异步
Async/Await 是一种在 JavaScript 中以同步方式书写异步代码的语法糖。它基于 Promise,使异步操作看起来更像顺序执行,简化了回调地狱,提高了代码可读性和维护性。
|
6月前
|
安全 算法 区块链
当量子计算遇上区块链:未来技术的双刃剑
当量子计算遇上区块链:未来技术的双刃剑
247 16
|
数据采集 机器学习/深度学习 算法
Python基于决策树多分类模型实现水色图像的水质评价
Python基于决策树多分类模型实现水色图像的水质评价
|
缓存 JavaScript
Vue中的keep-alive是什么意思?以及如何使用
Vue中的keep-alive是什么意思?以及如何使用
456 0
|
9月前
|
数据采集 分布式计算 Hadoop
使用Hadoop MapReduce进行大规模数据爬取
使用Hadoop MapReduce进行大规模数据爬取
|
11月前
|
移动开发 JavaScript 前端开发
webpack学习四:使用webpack配置plugin,来使用HtmlWebpackPlugin、uglifyjs-webpack-plugin、webpack-dev-server等插件简化开发
这篇文章主要介绍了如何通过配置Webpack的插件,如HtmlWebpackPlugin、uglifyjs-webpack-plugin和webpack-dev-server,来简化前端开发流程。
474 0
webpack学习四:使用webpack配置plugin,来使用HtmlWebpackPlugin、uglifyjs-webpack-plugin、webpack-dev-server等插件简化开发
|
JavaScript 前端开发 Java
使用这个正则表达式来验证一个字符串是否符合特定的格式要求
使用这个正则表达式来验证一个字符串是否符合特定的格式要求
275 5
|
11月前
|
前端开发 JavaScript Java
导出excel的两个方式:前端vue+XLSX 导出excel,vue+后端POI 导出excel,并进行分析、比较
这篇文章介绍了使用前端Vue框架结合XLSX库和后端结合Apache POI库导出Excel文件的两种方法,并对比分析了它们的优缺点。
2560 0