javascript中对象的创建-原型模式1
function Person(name,age,job){ } Person.prototype.name="nUll"; Person.prototype.age=25; Person.prototype.job="software"; Person.prototype.sayName=function(){ alert(this.name); }; var person1=new Person(); person1.sayName(); //nUll var person2=new Person(); person2.sayName(); //nUll alert(person1.sayName==person2.sayName); //true
原型中的所有属性与方法是所有实例所共享的.
person1的内部属性prototype 指向 Person.prototype
Person.prototype指向原型对象
而原型对象中的构造函数属性constructor 指向Person
注意,person1与person2与它们的构造函数没有直接关系,虽然这两个实例都不包含属性和方法,但是却可以调用person1.sayName();
这里简述一下查找sayName的查找过程,类似于作用域链的查找过程,由下至上,即实例-原型
person1与person2与它们的构造函数没有直接关系,那如何确定他们之间的间接关系呢?
alert(Person.prototype.isPrototypeOf(person1));//true alert(Person.prototype.isPrototypeOf(person2));//true
person1的内部属性prototype,在脚本中是无法直接访问的.但是可以通过其他方法访问,例如在ECMAScript5 中提供了Object.getPrototypeOf()方法,至于javascript与ECMAScript5 的关系,可以google一下.
alert(Object.getPrototypeOf(person1)==Person.prototype);//true alert(Object.getPrototypeOf(person2).name);//nUll
Object.getPrototypeOf()方法返回的对象,就是这个实例的原型
如果给实例添加一个属性,这个属性与原型中的某个属性名称一样,那么该属性就会屏蔽原型中的属性.
var person1=new Person(); var person2=new Person(); person1.name="mywei"; alert(person1.name); //mywei 来至实例 alert(person2.name); //nUll 来至原型 delete person1.name; //删除实例中的 name属性 alert(person1.name); //nUll 又来至原型了
如何判断实例的属性值来自实例还是来至原型?
var person1=new Person(); var person2=new Person(); alert(person1.hasOwnProperty("name")); //false person1.name="mywei"; alert(person1.name); //mywei 来至实例 alert(person2.name); //nUll 来至原型 alert(person1.hasOwnProperty("name")); //true delete person1.name; //删除实例中的 name属性 alert(person1.name); //nUll 又来至原型了 alert(person1.hasOwnProperty("name")); //false
实用代码:
function hasPrototypeProperty(object,name){ return !object.hasOwnProperty(name)&&(name in object); } var person1=new Person(); alert(hasPrototypeProperty(person,"name")); //false 来自原型 person1.name="mywei"; alert(hasPrototypeProperty(person,"name")); //true 来自实例
以上 name in object中的in操作符是判断 name的值是否存在于原型或实例中.其实,in操作符只能枚举必须是可枚举的([Enumerable]=true),属性有几种特性?google一下吧.
另一种原型模式创建对象的方式:
function Person(){ } Person.prototype.name="nUll"; Person.prototype.age=25; Person.prototype.job="software"; Person.prototype.sayName=function(){ alert(this.name); }; var person1=new Person(); alert(person1 instanceof Object); //true alert(person1 instanceof Person);//true alert(person1.constructor==Person);//true alert(person1.constructor==Object);//true //--------------------------邪恶的分割线------------------------------------------// function Person(){ } Person.prototype={ name:"nUll", age:25, job="software", sayName=function(){ alert(this.name); } } var person2=new Person(); alert(person2 instanceof Object); //true alert(person2 instanceof Person);//true alert(person2.constructor==Person);//false 注意,这里变成了false原因在于这里的"字面量写法",覆盖了原型里的所有属性,包括constructor,而默认的constructor 是 Object alert(person2.constructor==Object);//true //怎么破? 写回去! function Person(){ } Person.prototype={ constructor:"Person", name:"nUll", age:25, job="software", sayName=function(){ alert(this.name); } }; //可惜的是,这样写回去会改变constructor属性的特性[Enumerable],默认情况下,constructor属性是不可枚举的.更好的写法是这样,当然,这是在建立在如何设定特性值的情况下,刚才说让你google的...: function Person(){ } Person.prototype={ constructor:"Person", name:"nUll", age:25, job="software", sayName=function(){ alert(this.name); } }; Object.defineProperty(Person.prototype,"constructor",{ enumerable:false, value:Person });
原型的动态性:
function Person(){} var person1=new Person(); Person.prototype.sayHi=function(){ alert("hi"); }; person1.sayHi(); //hi 没有问题!原型中新增了sayHi方法,先找实例,没找到就找原型. function Person(){} var person1=new Person(); Person.prototype( sayHi:function(){ alert("hi"); } }; person1.sayHi(); //error 刚说过了,尽管上面为原型添加属性和方法可以在所有对象的实例中反映出来,但这种"字面量"写法重写了整个原型,情况就不一样了.这种重写已经改变原有对象与构造函数之间的联系,它是一个新的原型(虽然旧的原型没有显式定义,但它确实存在?)
如何为通过原型模式为原生对象添加方法:
String.prototype.startsWith=function(text){ return this.indexOf(text)==0; } var msg="Hello world"; alert(msg.startsWith("Hello")); //true 说的好!但这毫无意义(这里仅是提供扩展的示例,并不是说扩展的startsWith方法多么的精辟!)
原型对象的缺点:
function Person(){} Person.prototype={ name:"nUll", friends:["gay1","gay2"], sayName:function(){ alert(this.name); } }; var person1=new Person(); var person2=new Person(); person1.friends.push("gay3"); alert(person2.friends); //gay1,gay2,gay3 //WTF? person2 的friends 怎么会有gay3? 好吧,如果这就是你想要的结果,就当书上什么也没说-_-