开局一道题,内容全靠编

190 阅读2分钟

我叫小雨,最近看到一段代码挺有意思

题目如下

// 求以下输出
function Foo () {}
let fo = new Foo();
console.log(fo.__proto__.__proto__.constructor.prototype.constructor.constructor.constructor);

小雨第一次看到这道题时,既兴奋又一脸茫然。明明三个关键字都认识:__proto__prototypeconstructor。可是组合成: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、__proto__\color{#42b983}{\_\_proto\_\_}constructor\color{#42b983}{constructor}属性是对象所独有的。prototype\color{#42b983}{prototype}属性是函数所独有的。
2、对象的__proto__(隐式原型)指向创建该对象的原型prototype(显式原型),原型中有constructor属性指向构造函数。
3、Function、Object既是函数也是对象,所以它们也拥有__proto__和constructor属性。