起初在学习原型的时候,我也是一脸懵逼,这到底是个啥玩意,在网上搜各种博客,讲解的也是很绕,今天就将自己对原型链的理解分享出来,若有理解错误还望大佬多多指教。

当我们创建一个对象的时候:let obj = {age:24},我们能发现在对象的属性下面有一个__proto__的属性,顿时疑惑就来了,咦,我明明没有定义这玩意,它是从哪里冒出来的?

其实每个JS对象都有一个__proto__属性,这是属性指向了该对象构造函数的原型对象,在上图中var obj = {age:24}其实是一个语法糖,真正创建obj的是Object构造函数

let obj = new Object();
obj.age = 24;

正如我们所说的__proto__属性指向的是该对象的构造函数的原型对象,这里的构造函数是Object,所以__proto__指向的就是object的prototype。

我们还可以发现一个叫做constructor的属性,这又是个什么玩意呢?其实这是一个构造函数,是该prototype所在的函数,打开constructor,我们又能看到一个prototype属性,并且这个属性对应的值和先前我们在__proto__中看到的一模一样。所以我们又可以得出一个结论:原型的constructor属性指向构造函数,构造函数又通过prototype属性指回原型,但是并不是所有函数都具有这个属性,Function.prototype.bind()就没有这个属性。

接下来我们看一张图,相信这张图能让你完完全全的明白原型链:

我们先看这部分的内容:

这里f1 = new Foo(),所以f1的构造函数是Foo,而__proto__指向的是该对象构造函数的原型对象,所以f1的__proto__指向的是Foo的prototype对象,而prototype对象有一个constructor属性指向构造函数,展开constructor属性后又有一个prototype属性指回Foo的prototype对象,这也印证了上面那个结论。

我们再来看下一部分的内容:

这里Foo.prototype也有一个__proto__属性,因为原型对象prototype也是对象,所以它的构造函数为Object,因此__proto__指向的是Object的prototype,我们再看o1,它的构造函数也是Object,因此o1的__proto__就指向了o1的构造函数的原型对象,也就是Object.prototype,Object.prototype有一个constructor属性,指向了Object构造函数,展开constructor属性里面又有一个prototype属性,该属性又指回Object.prototype对象,这里又印证了我们上述的那个结论。再看Object.prototype对象,它也有一个__proto__属性,但是Object的原型对象的__proto__属性很特别,它始终指向的是null,因为Object已经是整个原型链的最顶层了。

看完对象的原型链,我们再来看看函数在原型链上的关系:

我们看到构造函数Foo的__proto__指向的Function.prototype,这是为什么呢?正如我们上面所述,__proto__指向该对象的构造函数的原型对象,而函数也是一种对象,也有构造函数,而Foo的构造函数是Function,那么Foo的__proto__自然而然的也指向了Function的prototype对象。我们再看为什么Object构造函数的__proto__也指向了Function.prototype呢?你傻呀!函数Object是一个函数,任何函数都是由Function构造函数创建出来的呀!所以Object的__proto__指向了它的构造函数的原型对象——Function.prototype!

最后我们再来看一个细节,Function构造函数还有一个__proto__指向Function.prototype,这不就构成了循环引用了吗?对,就是一个环形结构。其实稍微想一下就明白了。Function也是一个函数,函数是一种对象,也有__proto__属性。既然是函数,那么它一定是被Function创建。所以——Function是被自身创建的。所以它的__proto__指向了自身的Prototype。

到这里,整个原型链的结构图已经解释完了。以上就是我对javascript原型链的理解,若有错误或者大佬们有疑义,请及时提出来,反正提了我也不会听,听了也学不会,哈哈!

推荐阅读:

相关文章