构造函数创建对象我们首先使用构造函数创建对象:functionPerson(){}varperson=newPerson();person.name='name';console.log(person.name)//name在这个例子中,Person是一个构造函数,我们使用new来创建一个实例对象person。很简单,进入正题:prototype的每个函数都有一个prototype属性,也就是我们经常在各种例子中看到的prototype,比如:functionPerson(){}//虽然注释里写了,但是你注意://prototype是函数的一个属性Person.prototype.name='name';varperson1=newPerson();varperson2=newPerson();console.log(person1.name)//nameconsole.log(person2.name)//name那么这个函数的prototype属性指向什么呢?是这个函数的原型吗?其实这个函数的prototype属性指向一个对象,就是调用构造函数Prototype创建的实例,也就是本例中person1和person2的原型。那么什么是原型呢?你可以这样理解:每个JavaScript对象(null除外)在创建时都会与另一个对象相关联。这个对象就是我们所说的原型,每个对象都会“继承”原型的属性。让我们用一张图来表示构造函数和实例原型的关系:在这个图中我们使用Object.prototype来表示实例原型,那么我们如何表示实例和实例原型,也就是人与人之间的关系和Person.prototype?,这时候我们就要说到第二个属性:__proto__这是每个JavaScript对象(除了null)都有的一个属性,叫做__proto__,这个属性会指向对象的原型。为了证明这一点,我们可以在Firefox或Google中输入:functionPerson(){}varperson=newPerson();console.log(person.__proto__===Person.prototype);//true所以我们更新关系图:因为两者实例对象和构造函数可以指向原型,原型是否有属性指向构造函数或实例?没有构造函数指向实例,因为一个构造函数可以生成多个实例,但是有原型指向构造函数,这就是说到第三个属性:constructor,每个原型都有一个constructor属性指向关联的构造函数。为了验证这一点,我们可以尝试:functionPerson(){}console.log(Person===Person.prototype.constructor);//true所以更新关系图:综上,我们得出结论:functionPerson(){}varperson=newPerson();console.log(person.__proto__==Person.prototype)//trueconsole.log(Person.prototype.constructor==Person)//true//顺便学习一个ES5方法,可以得到prototypeoftheobjectconsole.log(Object.getPrototypeOf(person)===Person.prototype)//真正理解构造函数,Instance原型,以及实例之间的关系。接下来说说实例和原型的关系:实例和原型。在读取一个实例的属性时,如果找不到,它会在与该对象关联的原型中寻找属性。如果还是找不到的话,就去prototype的prototype,直到找到最顶层。例如:functionPerson(){}Person.prototype.name='name';varperson=newPerson();person.name='nameofthisperson';console.log(person.name)//nameofthispersondeleteperson.name;console.log(person.name)//name在这个例子中,我们设置了person的name属性,所以我们可以把它读作'这个人的名字',当我们删除person的name属性时,读person.name,如果可以的话'如果不是从person找,就要从person的原型找,即person.__proto__==Person.prototype。幸运的是,我们找到了它作为“名称”,但是如果您还没有找到怎么办?原型的原型是什么?前面我们已经说过原型也是一个对象。既然是对象,那么我们可以用最原始的方式来创建,即varobj=newObject();obj.name='name'console.log(obj.name)//name所以原型对象是通过对象构造函数。结合前面说的,实例的__proto__指向的是构造函数的原型,所以我们更新一下关系图:原型链中Object.prototype的原型?null,嗯,就是null,这样就可以了找到Object.prototype时停止搜索。那就是蓝线。补充***,补充纠正本文中一些不严谨的地方:一、constructor,functionPerson(){}varperson=newPerson();console.log(person.constructor===Person);//获取person时为true中.constructor的情况下,实际上没有constructor属性。当constructor属性无法读取时,会从person的原型中读取,即Person.prototype。prototype中正好有这个属性,所以person.constructor===Person.prototype.constructor后面跟着__proto__。大多数浏览器都支持这种非标准的方法来访问原型。但是,它不存在于Person.prototype中。其实它来自于Object.prototype,与其说是一个Property,不如说是一个getter/setter,在使用obj.__proto__的时候,可以理解为返回Object.getPrototypeOf(obj)***是关于继承的。前面我们说过“每个对象都会继承原型的属性”,其实继承是一个很容易混淆的说法。引用《你不知道的JavaScript》的话,就是:继承就是复制操作,但是JavaScript不会复制对象的属性默认情况下,在它们之间创建一个关联,使一个对象可以通过委托访问另一个对象的属性和函数,所以与其说是继承,不如说是委托更准确。更多JavaScript深入系列文章可以查看在https://github.com/mqyqingfeng/Blog
