将一个对象设置为一个类型的原型,相当于通过实例化这个类型,为对象建立只读副本,在任何时候对副本进行改变,都不会影响到原来对象,而对原来对象进行改变,会影响到每一个副本,除非被改变的属性已经被副本自己的同名属性覆盖。用delete操作将对象自己的同名属性删除,则可以恢复原型属性的可见性。
原型属性修改的正确方法.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
</head>
<body>
<script>
function ClassA(){
this.onlyReady = true;
}
function ClassB(){}
ClassB.prototype = new ClassA();
var classB = new ClassB();
alert("1.1没有进行任何修改之前的onlyReady:" + classB.onlyReady);
//下面的做法不是修改原型属性的正确做法
classB.onlyReady = false; //这个是给classB对象添加一个同原型属性onlyReady一样的属性
alert("2.1给classB对象添加同原型属性onlyReady一样的属性:" + classB.onlyReady);
delete classB.onlyReady;
alert("2.2删除classB对象同原型属性同名的onlyReady属性之后:" + classB.onlyReady);
//正确修改原型属性
ClassB.prototype.onlyReady = false;
alert("3.1通过ClassB.prototype.属性名修改原型属性的值:" + classB.onlyReady);
//classB.prototype.onlyReady = 5;//语法错误
</script>
</body>
prototype的行为类似于C++中的静态域,将一个属性添加为prototype的属性,这个属性将被该类型创建的所有实例所共享,但是这种共享是只读的。在任何一个实例中只能够用自己的同名属性覆盖这个属性,而不能改变它。
采用prototype定义的属性和方法称为静态属性和静态方法,或者原型属性和原型方法,把用this定义的属性和方法称为共有属性和共有方法。
尽管采用prototype和采用this定义的属性和方法在对象调用的形式上是一致的,以致于在一段代码中甚至很难严格区分,但是用“静态”两个字还是很好的诠释了prototype的数据存储上的特质,即所有的实例共享唯一的副本。这一点和C++中的static成员非常相似,但是和C#不同,C#中的static方法的调用形式是通过类型的“.”运算符,这相当于JavaScript中的类属性和类方法。
通过prototype能够以一个对象为原型,安全地创建大量的实例,这就是prototype的真正含义,也是它的价值所在。由于prototype仅仅是以对象为原型给类型创建副本,因此它也具有很大的局限性。首先,它在类型的prototype域上并不是表现为一种值拷贝,而是一种引用拷贝,这带来了“副作用”。改变某个原型上引用类型的属性的属性值,将会彻底影响到这个类型创建的每一个实例。