我叫小雨,最近看到一段代码挺有意思
题目如下
// 求以下输出
function Foo () {}
let fo = new Foo();
console.log(fo.__proto__.__proto__.constructor.prototype.constructor.constructor.constructor);
小雨第一次看到这道题时,既兴奋又一脸茫然。明明三个关键字都认识:__proto__,prototype,constructor。可是组合成:fo.__proto__.__proto__.constructor.prototype.constructor.constructor.constructor 却不知道是什么
思考🤔
题目的求解可以分成三部分:
1、求 fo.__proto__
2、求 ???.constructor
3、求 ???.prototype
解决了这三个子问题,无论题型如何组合都可以搞定
关系图
prototype
prototype是 函数 所独有的,它是从一个函数指向一个对象。表示函数的 原型对象。
__proto__
__proto__是 对象 才拥有的,读作“dunder proto”,“double underscore proto”的缩写,该属性在ES标准定义中的名字应该是 [[Prototype]],具体实现是由浏览器代理自己实现,浏览器的实现将 [[Prototype]] 命名为 __proto__
原型链
定义函数时默认有一个prototype指向函数的原型对象,当函数被new调用时,函数就是构造函数,返回一个新的实例对象。这个实例对象上会有一个__proto__属性指向构造函数的原型对象。
当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(父对象)里找,一直找,直到__proto__属性的终点null,通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链。
constructor
constructor是 对象 才拥有的,它是从一个对象指向一个函数,指向该对象的 构造函数,每个对象都有构造函数(本身拥有 或 委托 访问,通过__proto__属性找到原型对象的constructor),
从上图中可以看出Function这个对象比较特殊,它的构造函数就是它自己
Function的constructor不是本身拥有,而是通过委托的方式访问。
首先通过Function.__proto__找到原型对象(Function.prototype),在原型对象中存在constructor属性。最后通过Function.prototype的constructor再找到Function的constructor。(对应图例的虚线部分)
所有函数和对象最终都是由Function的构造函数得来,所以constructor属性的终点就是Function这个函数。
题解
结果输出:ƒ Function() { [native code] }
总结
1、和属性是对象所独有的。属性是函数所独有的。
2、对象的__proto__(隐式原型)指向创建该对象的原型prototype(显式原型),原型中有constructor属性指向构造函数。
3、Function、Object既是函数也是对象,所以它们也拥有__proto__和constructor属性。