没错,我就是标题党!你已经成功被我骗进来了。来都来了,那就聊聊再走呗!接下来就听我一本正经地跟你说道说道。
Javascript的原型是这门语言的一个重点和难点。看过很多大佬写的解释Javascript原型的文章,但是很多对于初学者其实不是很友好,看完之后还是云里雾里。我虽然不敢说能把这个东西解释的很清楚,但是作为一个前端菜鸟,我可能更知道大家在读文章的时候会卡在哪一步,所以希望本文能够帮助到大家。
在文章开始,我先明确几个概念,这里如果你觉得不好理解,就先牢牢地记住它,然后继续往下阅读,读完你就会豁然开朗,相信我!另外,一定要每行每字去读,勿跳着读,博主就犯过这样的错误,导致越读越糊涂,我这里也尽量压缩字数,保证你读的每个字都是有用的。答:“你都忽悠半天了赶紧开始吧!”
- prototype :每个函数都会有这个属性,这里强调,是函数,普通对象是没有这个属性的(这里为什么说普通对象呢,因为JS里面,一切皆为对象,所以这里的普通对象不包括函数对象)。它是构造函数的原型对象;
- __proto__ :每个对象都有这个属性,,这里强调,是对象,同样,因为函数也是对象,所以函数也有这个属性。它指向构造函数的原型对象;
- constructor :这是原型对象上的一个指向构造函数的属性。
先看代码
// Pig的构造函数function Pig(name, age) { this.name = name; this.age = age;}// 创建一个Pig的实例,小猪佩奇var Peppa = new Pig('Peppa', 5);复制代码
敲黑板,划重点,理解这一句整个问题的关键,请多重复几遍。:在实例化的时候,prototype上的属性会作为原型对象赋值给实例。 也就是说小猪佩奇的原型,就是从Pig.prototype
继承来的写成代码就是这个样子Peppa.__proto__ === Pig.prototype
。
Pig.__proto__ === Function.prototype
一定为true。 我们在上面提到了constructor这个属性,它位于原型对象上并且指向构造函数,所以 Pig.prototype.constructor === Pig
至此,我大致捋了一遍这三个属性的关系,我们再顺着这条链继续往深挖一挖。 Function.prototype
,也就是Function的原型对象。这个原型对象的__proto__指向了 Object.prototype
。打破砂锅问到底, Object.prototype.__proto__
又指向谁,JS世界里万物皆对象,Object似乎已经到了原型链的顶端,果然不出我所料,它确实是null。: 你可能要吐槽了,说好的讲明白呢,这一坨都被你绕糊涂了,一张图胜过千言万语: 解释一下上面的图。先看蓝色那条线,Pig,Function和Object的构造函数是Function的实例,所以它们的__proto__均指向Function.prototype。这就印证了敲黑板说的那句话,prototype属性会作为原型对象赋值给实例,每个对象的__proto__都指向原型对象(处于最顶层的Object.prototype除外)。
再看绿色那条,Pig和Function的原型对象是Object的实例,所以它们的__proto__均指向了Object.prototype,也就是Object的原型对象。
浅蓝色的线表明了原型的constructor指向了构造函数。
Emmmm,其实也没那么复杂对不对?接着说一下原型链。正如你在上面图中所看到的,JS在创建对象的时候,会在新对象上产生一个__proto__的属性,这个属性指向了它构造函数的原型的prototype。由此一级一级向上直到到达Object.prototype.proto === null的这个链条我们称之为原型链。
关于继承的概念,本来想写在一起的,后来想想,内容过多只会让文章成为收藏不看系列,所以这块的内容放在以后的文章里详解。各位看官,我想我大致讲明白了原型和原型链的概念,有什么错误还恳请批评指正。