原型模式(5.2)
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处是可以让所有对象实例共享原型对象所包含的属性和方法。换句话说,不必再构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中,这样所有对象实例都能共享这些信息。
1.理解原型对象
无论什么时候,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个Prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在的函数的指针(在ECMAScript中函数就是对象)。
创建了自定义的构造函数之后,其原型对象默认只会取得constructors属性;至于其他方法,则都是从Object继承而来的。当调用构造函数创建一个新实例后,该实例的内部包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第5版中管这个指针叫[[Prototype]]。虽然在脚本中没有标准的方式访问[[Prototype]],但在Firefox, Safari和Chrome在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本则是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例与狗仔函数的原型对象之间,而不是存在于实例与狗仔函数之间。
以下面的代码为例
<script type="text/javascript" > function Person(){ } Person.prototype.name = '高伟刚'; Person.prototype.age = 22; Person.prototype.job = 'Software Engineer'; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.sayName();//高伟刚 person2.sayName();//高伟刚 </script>
各对象之间的关系如下:
说明:1. 每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。如果在原型对象中找到了这个属性,则返回该属性的值。这正是多个对象实例共享原型所保存的属性和方法的基本原理
2 .虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性,而该属性与原型中的一个属性同名,那我们就在实例中创建了该属性,该属性将会屏蔽原型中的那个属性。来看下面一个例子:
<script type="text/javascript" > function Person(){ } Person.prototype.name = '高伟刚'; var person1 = new Person(); var person2 = new Person(); alert(person1.name);//高伟刚 alert(person2.name);//高伟刚 person1.name = '高红程';//注意:这是在person1中添加一个name属性 alert(person1.name);//高红程,来至实例,屏蔽了原型中的同名属性 alert(person2.name);//高伟刚,来至原型 </script>
hasOwnProperty()方法
使用hasOwnProperty()方法可以检测一个属性是存在于实例中,还是存在于原型中。这个方法(不要忘了它是从Object继承而来的)只在给定属性存在于对象实例中时,才会返回true