在这个例子中,我们首先创建了一个内容为空的构造函数,因为刚刚讲了我们可以通过访问构造函数的prototype属性来为原型对象中添加属性和方法。于是在下面几行代码中,我们便通过访问构造函数的prototype属性向原型对象中添加了属性和方法。接着,创建了两个对象实例person1和person2,并调用了原型对象中sayName()方法,得到了原型对象中的name值。这说明:构造函数创建的每一个对象和实例都拥有或者说是继承了原型对象的属性和方法。(因为无论是创建的对象实例还是创造函数的prototype属性都是指向原型对象的) 换句话说,原型对象中的属性和方法会被构造函数所创建的对象实例所共享,这也是原型对象的一个好处。
下面我会画一张图来继续阐述这个问题:
从这张图中我们可以看出以下几点:
构造函数和由构造函数创建的对象的prototype指针都指向原型对象。即原型对象既是构造函数的原型对象,又是构造函数创建的对象的原型对象。
原型对象有一个constructor指针指向构造函数,却不会指向构造函数创建的实例。
构造函数的实例的[[prototype]]属性被实例访问来添加或修改原型对象的属性和方法的,而构造函数的prototype属性可以被用来访问以修改原型对象的属性和方法。
person1和person2与他们的构造函数之间没有直接的关系,只是他们的prototype属性同时指向了同一个原型对象而已。
Person.prototype指向了原型对象,而Person.prototype.constructor又指回了Person。
虽然这两个实例都不包含属性和方法,但我们却可以调用person1.name,这是通过查找对象属性的过程来实现的。
B.有关于原型对象中的方法以及实例中的属性和原型对象中的属性为了加深对原型的理解,我在这里先介绍两种方法确定构造函数创建的实例对象与原型对象之间的关系。
第一种方法:isPrototypeOf()方法,通过原型对象调用,确定原型对象是否是某个实例的原型对象。在之前的代码后面追加下面两句代码:
1 2
console.log(Person.prototype.isPrototypeOf(person1));//true console.log(Person.prototype.isPrototypeOf(person2));//true
结果不出意外地均为true,也就是说person1实例和person2实例的原型对象都是Person.prototype。
第二种方法:Object.getPrototypeOf()方法,通过此方法得到某个对象实例的原型。在之前的代码后面追加下面三句代码:
1 2
console.log(Object.getPrototypeOf(person1)); console.log(Object.getPrototypeOf(person1)==Person.prototype);<br> console.log(Object.getPrototypeOf(person1).name);//zzw
其中第一句代码在控制台中可以直接获得person1的原型对象,如下图所示:
其中第二句代码得到布尔值:true。第三句代码得到了原型对象中的name属性值。
但是,当实例自己本身有和原型中相同的属性名,而属性值不同,在代码获取某个对象的属性时,该从哪里获取呢?
规则是:在代码读取某个对象而某个属性是,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从实例本身��始,如果在实例中找到了给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象。观察下面的例子。
1 2 3 4 5 6 7 8 9 10 11 12 13
function Person(){} Person.prototype.name="zzw"; Person.prototype.age=21; Person.prototype.school="xjtu"; Person.prototype.sayName=function(){ console.log(this.name); }; var person1=new Person(); var person2=new Person(); console.log(person1.name);//zzw <strong>person1.name="htt";</strong> <strong>console.log(person1.name);//htt</strong>