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?  好吧,如果这就是你想要的结果,就当书上什么也没说-_- 

 

posted on 2014-04-09 09:46  nU||  阅读(880)  评论(1编辑  收藏  举报

导航