原型链prototype、__proto、constructor的那些问题整理

再了解原型链之前,我们先来看看构造函数和实例对象的打印结构

- 函数

这里我们定义一个构造函数Fn,然后打印它的结构吧

function Fn(){}
console.dir(Fn)

控制台得到结构

从上面结构我们能看的出来,函数有两种原型,一种是作为函数特有的原型:prototype,另一种是作为对象的__proto__类型(就是上图那个[[Prototype]],__proto__是浏览器自己填充的,新浏览器都能看到,我的浏览器版本低,还看不到哈,先这么写)

我们先来看做为函数特有属性的prototype哈,我们展开看看

可以看到函数的prototype上有一个构造函数constructor和一个__proto__属性,这个constructor实际上就是函数本身,另外一个__proto__呢,你看它的值是一个对象Object呢.也就是说函数的prototype的__proto__指向Object的prototype,我们下面运行看看是不是这样呢?

Fn.prototype.__proto__ === Object.prototype.    // true

我们运行结果果然和预期一样返回了true.

我们再来看函数的另外一个原型__proto__,我们展开它

我们看到函数的__proto__是一个Function,我们猜想这个函数的__proto__指向Function的prototype,我们来运行看看

Fn.proto === Function.prototype. // true

果然,和预期一样,所以我们根据上面的一些结果有了总结

1、函数(箭头函数除外,箭头函数没有prototype属性哈)有两个原型,一个是作为函数特有的prototype,另一个是作为对象的__proto__

2、函数的 prototype中constructor就是函数本身

3、函数的 prototype中__proto__属性指向Object的prototype

4、函数的__proto__指向Function的prototype

  • 对象

现在我们根据上面的构造函数,我们实例化一个对象来看看结构

let obj = new Fn()
console.dir(obj)

我们来看看obj对象的结构

可以看到上面的obj对象只有一个__proto__原型,我们展开看似乎和它的构造函数的prototype长的一样呢,我们运行看看

obj.proto === Fn.prototype. // true

果然,结果和我们预期一样

所以我们有了结论:

对象只有一条__proto__原型,并且对象的原型__proto__就指向构造函数的prototype

  • constrctor

我们再回过头来看刚刚构造函数中那个constrctor,上面你看实例对象obj可以找到构造函数的prototype,而这个prototype上就有constrctor,所以由此得出根据构造函数实例得到的每一个实例对象,都能找到它的构造函数

我们来运行看看哈

 obj.__proto__.constructor    // ƒ Fn(){}

没有问题,和预期一样,这么看,我们现在就可以把上面写法精简一下,因为对象上的属性和方法,自己上面没有,就会去它的原型链上面去找,也就是对象会有原型的继承

根据这个原则,我们把上面运行的就能精简一下了

obj.constructor.   //. ƒ Fn(){}

我们就这样就找到了构造函数了.

这里找到构造函数的目的是啥呢,除了用它来实例化对象之外,还能给原型链添加公共的属性和方法,供所有的实例对象调用.

我们来看一段代码

obj.constructor.prototype.sayHello = function(){ console.log("hello")}
obj.sayHello().  // hello
let obj2 = new obj.constructor()
obj2.sayHello(). // hello

从上得出,我们可以通过constructor的prototype添加通用的属性和方法.

有人提出干嘛那么麻烦,我们通过对象的__proto__直接添加属性和方法不是更好嘛,代码更精简,我们来看看

obj.proto .name = "zhang"

obj.name. // "zhang"

obj.name // "zhang"

我们看到我们通过对象的__proto__也能添加构造函数的公用属性和方法,所以,这样写到底有没有问题呢?

其实这样写虽然在浏览器运行没有问题,但是上面我们提到过,__proto__这个属性是浏览器厂商自己内置的,有的浏览器是不支持的,所以使用constructor更可靠一点。

就先整理到这里

相关推荐
zhanghaisong_20158 分钟前
Caused by: org.attoparser.ParseException:
前端·javascript·html·thymeleaf
monkey_meng10 分钟前
【Rust中的项目管理】
开发语言·rust·源代码管理
喜欢打篮球的普通人12 分钟前
rust高级特征
开发语言·后端·rust
ModelBulider30 分钟前
十三、注解配置SpringMVC
java·开发语言·数据库·sql·mysql
V搜xhliang024639 分钟前
基于深度学习的地物类型的提取
开发语言·人工智能·python·深度学习·神经网络·学习·conda
DK七七41 分钟前
多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
开发语言·前端·微信小程序·小程序·php
苹果酱05671 小时前
C语言 char 字符串 - C语言零基础入门教程
java·开发语言·spring boot·mysql·中间件
南城夏季1 小时前
蓝领招聘二期笔记
前端·javascript·笔记
Huazie1 小时前
来花个几分钟,轻松掌握 Hexo Diversity 主题配置内容
前端·javascript·hexo
代码小鑫1 小时前
A032-基于Spring Boot的健康医院门诊在线挂号系统
java·开发语言·spring boot·后端·spring·毕业设计