原型链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更可靠一点。

就先整理到这里

相关推荐
kyriewen2 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
weedsfly4 小时前
迭代器、生成器与异步迭代——让数据“按需流动”的艺术
前端·javascript
假如让我当三天老蒯5 小时前
前端跨域解决方案(学习用)
前端·javascript·面试
铁皮饭盒6 小时前
Bun 哪比 Node.js 快?
javascript·后端
JieE21214 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
candyTong17 小时前
RTK 技术原理:一次典型会话里,80% 上下文是怎么省下来的
javascript·后端·架构
_柳青杨21 小时前
深入理解 JavaScript 事件循环
前端·javascript
大家的林语冰1 天前
ES5 凉凉,Babel 8 正式发布,默认不再编译为 ES5 和 CJS......
前端·javascript·前端工程化
weedsfly1 天前
异步编程全景与事件循环——彻底搞懂 JS 执行机制
前端·javascript
用户1733598075371 天前
纯前端 PDF 数字签名实战:Vue 3 + pdf-lib 在浏览器里完成签名嵌入
前端·javascript