目录

Table of Contents generated with DocToc

一、参考书籍和数据

翻看了几本JS书籍,其中主要有以下几本:《JavaScript高级程序设计第三版》、《你不知道的JavaScript卷一》、《JavaScript权威指南》以及查看了MDN文档。文章主要说了JavaScript中原型的一些概念知识,花了一点时间去总结,如任何问题的话可以提出来一起交流解决。文章中的图大多是从网络和书中截取下来,并非本人原创。

二、原型,[[prototype]]和.prototype以及constructor

结合书中的概念,原型是什么这个问题,可以这样去解释:原型就是一个引用(也就是指针),指向原型对象。这并不是废话,很多人说原型,实际上没意识到它只是一个引用,指向原型对象。原型在实例对象和构造函数中有不同的名称属性,但总是指向原型对象。如图所示:

[[prototype]]和.prototype以及constructor

 

  • 其中的constructor是原型对象的属性,引用的是对象关联的函数,不可枚举,但这个属性是可以修改的,因此不可靠。
  • 在实例对象中,原型就是对象的[[prototype]]内置属性(双方括号代表这是JavaScript引擎内部使用的属性/方法,正常JS代码无法访问,但可以通过__proto__访问到,后面会说到),在对象被创建时就包含了该属性,指向它的构造函数的原型对象。
  • 在函数中,原型就是函数的.prototype属性,在函数被创建时就包含该属性,指向构造函数的原型对象 。

三、原型链

要理解原型链,首先需要明白原型对象的作用就是让所有实例对象共享它的属性和方法。根据上图,不难发现,person1和person2中的内部属性[[prototype]]都指向Person原型对象。当进行对象属性查找的时候,比如person1.name,首先会检查对象本身是否有这个属性,如果没有就继续去查找该对象[[prototype]]指向的原型对象中是否有该属性,如果还是没有就继续去找这个原型对象的[[prototype]]指向的原型对象(注意,原型对象也是有他自己的[[prototype]]属性的)!这个过程会持续找到匹配的属性名或查找完整的原型链。不难理解了,原型链就是:每个实例对象( object )都有一个私有属性(称之为[[prototype]])指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( [[prototype]] ) ,层层向上直到一个对象的原型对象为Object.prototype(因为所有对象都是源于Object.prototype,其中包含许多通用的功能方法)。显然,如果找完这个原型链都找不到就会返回undefined。这个过程可以用一张图描述:

显然,原型和原型链的作用就是:如果对象上没有知道需要的属性和方法引用,JS引擎就会继续在[[prototype]]关联的对象上进行查找。这也是原型和原型链存在的意义。

for...in和in操作符

两个跟原型链有关的操作

  • for...in遍历对象时,任何可以通过原型链访问到的(并且是enumerable为true)属性都会被枚举。
  • in操作符用于检测属性在对象中是否存在,同样是会查找整条原型链。
function Person(name){   this.name = name; } Person.prototype.sayName = function() {   return this.name; } let myObject = new Person('练习生'); // 输出两个属性:name和sayName,其中sayName是原型对象中的属性 for(let key in myObject) {   console.log(key); } // 输出true,表示不可枚举的constructor存在于myObject中。 // 事实上constructor是在Person.prototype对象中 console.log("constructor" in myObject);

四、属性设置和屏蔽

给对象设置属性并不仅仅是添加一个属性或修改已有属性。这个过程应该是这样的:

// myObject的声明在第一个代码块  // 注意:sayName在Person.prototype中存在,将屏蔽原型链上的sayName方法 myObject.sayName =