学习JavaScript有一段时间了,感觉原型那块儿又有点混乱了,现在写个笔记整理一下思路。
什么是原型
每创建一个函数,这个函数都会自带一个属性prototype指向一个原型对象,最初这个原型对象只包含一个属性constructor,这是指向我们创建的那个函数的指针。也就是说函数和原型对象分别通过prototype和constructor这两个属性(指针)能找到对方。
我们可以通过fn.prototype.propertyName=value来给原型对象继续添加属性和方法。这些属性和方法区别于在函数中书写的实例属性和方法。为什么会有这种区别或者说这种区别是怎么做到的呢?来看看创建一个实例后发生了什么。以下面的代码来说明:
function Person(name,age){
this.name=name,
this.age=age;
}
Person.prototype.hobby = ["running","swimming","tennis"];
Person.prototype.country="China";
Person.prototype.showName=function(){alert(this.name);};
var person1 = new Person("anna",10);
这里创建了一个实例person1,我们知道通过new方法创建的实例,原来Person中的this会被新创建的实例即person1取代,也就是说通过这样的方式,我们为对象person1增加了属性name和age,这些是person1自己所拥有的属性,独立于其他Person的实例,叫做实例属性。
同时,每创建一个实例,这个实例会自带一个内部属性[prototype],它是一个指向构造函数的原型对象的引用。也就是说person1对象其实现在包括了这么三个属性:
person1={
_proto_:Person.prototype,
name:"anna",
age:10
}
这个内部属性_proto_
一般来说是不可以通过脚本来访问到的,那它有什么用呢?在进行属性标识符查找的时候会用到它。
引擎在读到某个对象的属性时,会首先查找实例属性中有没有这个属性,如果有则停止,没有则通过内部属性_proto_
找到其关联的原型对象,看原型对象中有没有相应的属性。
实例属性和原型属性同名
这里需要注意,如果我们又为实例添加了一个和原型对象中同名的属性,或者说我们“重写”原型中的属性会发生什么。这得分属性是原始值类型还是引用类型。
原始类型
同名的实例属性会屏蔽掉原型对象中的同名属性,这里的屏蔽的意思是,这个属性是添加到实例属性上的,跟原型对象中的属性半毛钱关系没有,按照查找标识符的顺序会首先找到该实例属性,就不会再往上找原型中的了。它根本就不会“重写”原型对象中的属性,根本就是两个值,在内存中有两个空间。通过hasOwnProperty()可以看到已经成为自己的实例属性了:
person1.country="USA"; //重写属性
alert(person1.hasOwnProperty("country"));//true
可通过delete person1.country来删除实例属性,这样就又可以访问到原型对象中的属性了。
引用类型
引用类型也是一样的,当实例属性和原型中的属性同名的时候,就会屏蔽原型中的属性,可以通过delete(impletation.property)来删除实例属性以重新获取原型中的属性:
person1.hobby=['table tennis','singing'];
alert(person1.hasOwnProperty('hobby')); //true
问题:原型对象showName方法中的this是实例对象?解释为谁调用this就是谁?
做了实验,的确是原型对象方法中的this是指向实例对象的:
Person.prototype.name = 'lily';
var p = new Person('anna', 10);
p.showName(); // 显示 anna
但如果实例没有自己的属性name,那么会沿着原型链查找这个属性,此时就是显示原型对象上的属性lily了。
由于时间关系先写到这儿,后面还会有补充。。。。