在上篇文章中,我们说过,原型对象也有缺点:
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? 好吧,如果这就是你想要的结果,就当书上什么也没说-_-
直接点的处理方式是组合使用构造函数模式和原型模式:
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; this.friends=["gay1","gay2"]; } Person.prototype={ constructor:Person, sayName:function(){ alert(this.name); } } var person1=new Person("nUll",25,"software"); var person2=new Person("mywei",25,"software"); person1.friends.push("gay3"); alert(person1.friends); // gay1,gay2,gay3 alert(person2.friends); //gay1,gay2 alert(person1.friends===person2.friends); //false alert(person1.sayName===person2.sayName); //true
这与开头的例子的区别在于,属性在构造函数中定义,而方法在原型中定义,因而每个实例有独立的friends属性.这种方式创建实例对象可以说是最广泛,认同度最高的一种创建自定义类型的方法.
在初步了解原型方法后,就应该能理解下面代码的思想,不过要注意,下面不能使用"字面量"的方式重写原型,因为那样会切断现有实例与新原型之间的联系:
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; if(typeof this.sayName!="function"){ Person.prototype.sayName=function(){ alert(this.name); }; } } var person1=new Person("nUll",25,"software"); person1.sayName();
寄生构造函数模式,不知道你们是否还记得上篇文章中的这段代码:
String.prototype.startsWith=function(text){ return this.indexOf(text)==0; } var msg="Hello world"; alert(msg.startsWith("Hello")); //true 说的好!但这毫无意义(这里仅是提供扩展的示例,并不是说扩展的startsWith方法多么的精辟!)
如果我们不想扩充原生对象例如Array,则可以使用寄生构造函数模式:
function SpeciaArray(){ var values=new Array(); values.push.apply(values,arguments); values.toPipedString=function(){ return this.join("|"); }; return values; } var friends=new SpeciaArray("gay1","gay2","gay3"); alert(friends.toPipedString()); //gay1|gay2|gay3 alert(friends instanceof Object); //true alert(friends instanceof SpeciaArray); //false alert(friends instanceof Array); //true
下篇将讨论javascript中的继承.欢迎拍砖.