1.prototype(原型):创建每一个函数都有拥有一个prototype属性,这个属性是一个 指针 ,指向一个 对象 ,而这个 对象 的用途是包含可以 由特定类型的所有实例共享的属性和方法 。换句话说: prototype就是通过调用构造函数而创建的那个对象实例的原型对象。 使用原型的好处在于可以让 所有实例共享 它所包含的 属性和方法 (共享原型对象所有属性和方法)。
例子:
function Person(){}//创建空的构造函数
var per1=new Person();//创建一个Person实例
var per2=new Person();//创建一个Person实例
2.ECMAScript原型对象
只要创建一个函数,就会根据一组特定的规则为该函数创建一个protoype属性,这个属性指向函数的原型对象。 在默认情况下,所有原型对象都会自动获得一个constuctor(构造函数)函数 ,这个属性包含一个指 向prototype属性所在函数的指针 。以上例来讲,Person.prototpye.contructor指向Person。通过此构造函数,我们还可以继续添为原型对象添加属性。
在创建自定义构造函数之后,其原型对象默认只会取得constructor属性;至于其他方法则从Object继承而来。当调用构造函数创建一个新的实例后,该实例内部将包含一个指针(内部属性),指向构造函数的原型对象。在很多内部实现中,这个内部属性的名字是_proto_,而且可以访问到(Firefox,Safari、Chrome、Actionscript),而其他的实现这个对象则完全不可见。需要明确一点是:这个连接存在于实例与构造函数的原型对象之间,而不是实例与构造函数之间。
原型对象最初只包含constructor属性,二该属性也是共享属性,一次可以通过对象访问实例。(如下图:最初情况)
图中展示了Person构造函数、Person 的原型对象以及Person现有两个实例之间的关系。此时,Person.prototype指向了原型对象,而Person.prototype.constructor又指回了Person。per1和per2都包含一个内部属性该属性仅仅指向了Person.prototype,换句话说它们与构造函数没有直接关系。
function Person(){}//创建空的构造函数 //通过prototype添加属性,可以实现为所有实例共享属性和方法 Person.prototype.name="张三";//Person函数拥有一个prototype属性 Person.prototype.age=29; Person.prototype.job="软件工程师"; Person.prototype.sayName=fucntion(){ alert(this.name); }; var per1=new Person();//创建一个Person实例 per1.sayName();//"张三" var per2=new Person();//创建一个Person实例 per2.sayName();//"张三" alert(per1.sayName==per2.sayName)//true,说明调用的是同一个函数
下图是添加了额外属性之后关系图:
2.可以通过对象实例访问保存在原型中的值,但是不能通过对象实例重写原型中的值。
如果在实例对象中添加一个与原型对象中相同名称的属性,那么实例对象取到值将是对实例对象的属性值。
function Person(){}//创建空的构造函数 //通过prototype添加属性,可以实现为所有实例共享属性和方法 Person.prototype.name="张三";//Person函数拥有一个prototype属性 Person.prototype.age=29; Person.prototype.job="软件工程师"; Person.prototype.sayName=fucntion(){ alert(this.name); }; var per1=new Person();//创建一个Person实例 per1.name="李四";//实例对象创建一个与原型相同名称的属性 per1.sayName();//"李四" var per2=new Person();//创建一个Person实例 per2.sayName();//"张三" alert(per1.sayName==per2.sayName)//true,说明调用的是同一个函数
说明实例对象的name属性屏蔽了原型对象的name的值。可以使用delete操作符删除实例对象的属性 。
function Person(){}//创建空的构造函数 //通过prototype添加属性,可以实现为所有实例共享属性和方法 Person.prototype.name="张三";//Person函数拥有一个prototype属性 Person.prototype.age=29; Person.prototype.job="软件工程师"; Person.prototype.sayName=fucntion(){ alert(this.name); }; var per1=new Person();//创建一个Person实例 per1.name="李四";//实例对象创建一个与原型相同名称的属性 per1.sayName();//"李四" delete pre1.name;//删除实例对象的name属性 per1.sayName();//"张三" var per2=new Person();//创建一个Person实例 per2.sayName();//"张三" alert(per1.sayName==per2.sayName)//true,说明调用的是同一个函数
3.从上述代码观察,可以得出以下结论:
每当代码读取某个实例对象的属性时,都会执行一次搜索,目标是具有给定名字的属性(或者方法)。搜索首先从实例对象本身开始,如果发现属性(或者方法)存在,则返回对应的值;如果不存在则会搜索原型对象的属性(或者方法),如果存在则返回值。这也是多个对象实例共享原型对象所保存的属性和方法的基本原理 。
4.使用hasOwnProperty()方法可以检测一个属性是存在于实例对象中,还是存在于原型对象中。此方法继承自Object,只在给定属性存在于对象实例中时,才返回true。
function Person(){}//创建空的构造函数
//通过prototype添加属性,可以实现为所有实例共享属性和方法
Person.prototype.name="张三";//Person函数拥有一个prototype属性
Person.prototype.age=29;
Person.prototype.job="软件工程师";
Person.prototype.sayName=fucntion(){
alert(this.name);
};
var per1=new Person();//创建一个Person实例
per1.name="李四";//实例对象创建一个与原型相同名称的属性
per1.sayName();//"李四"
alert(per1.hasOwnProperty("name"));//true
var per2=new Person();//创建一个Person实例
per2.sayName();//"张三"
alert(per2.hasOwnProperty("name"));//false
alert(per1.sayName==per2.sayName)//true,说明调用的是同一个函数