您的位置:首页 > Web前端 > JavaScript

javascript Prototype Pattern

2017-08-11 16:47 225 查看
Prototype :和java 类中定义static方法一样,表示类方法,所有对象使用同一方法。

                    java中的原型:就像电影里一个真人,然后有许多真人复制品。

                                            就是用new建立一个对象(原xi),然后建立其它对象不用new,直接复制以前建立的属性和方法。

           因此java和javascript的[b]Prototype不一样。 
                                         [/b]

一、构造函数的问题

   1、建立一个实例,相应的建立一个方法.因此不同的实例,同名的方法名,但是方法的实例不一样。

       尽管构造函数模式是有用的,但是有一些缺点。 主要的缺点,建立一个实例,相应的建立一个方法. 记住,函数在in
ECMAScript里是对象, 
 因此,每当一个函数被定义,实际上被实例化了一个对象。逻辑上,
构造器看起来像这样:
function Person(name, age, job){

     this.name = name;

    this.age = age;

    this.job = job;

   this.sayName = new Function(“alert(this.name)”); //logical equivalent

 //this.sayName
= function(){ alert(this.name); }


}

 
       类:Function:

 
    实例:new Function

构造函数:Function(“
”);

 
上面表示定义一个Function的实例,哪么

 
 var person1 = new Person(“Nicholas”, 29, “Software Engineer”);

   var person2 = new Person(“Greg”, 27, “Doctor”);

 
 new Person 一次,sayName
()实例一次,所以同名的函数sayName
()的实例对象不一样。

    alert(person1.sayName
== person2.sayName); //false

 
做同一件事情,有两个Function实例是无意义的,所以大家都希望建立一个类的无数对象,可以只用一个方法。

2、把函数写在构造函数外面,哪么多个实例只用一个方法,但是缺点是外面有可能写很多方法。

例子:

function Person(name, age, job){

this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName(){

   alert(this.name);g;;;

}

var person1 = new Person(“Nicholas”, 29, “Software Engineer”);

var person2 = new Person(“Greg”, 27, “Doctor”);

 
在这个例子中,sayName() 函数时定义在构造函数外面. 在构造函数里面sayName 属性等于全局 sayName()
函数. 因此sayName属性现在包含一个指向函数的指针,
   person1, person2  共享 在全局作用域里的sayName() 函数 .
这个解决了上面做同一件事情重复函数的问题,

 
但是 也不好.如果对象需要多个方法,需要建立多个全局函数, 这些问题由Prototype Pattern 解决  

二、The Prototype Pattern:就是解决多个实例使用同一个方法的问题。
     用一个prototype 属性建立每一个函数,包含属性和方法。一旦构造函数被调用, 对象的原型被建立
     使用prototype 的好处是所有的properties和methods 是被所有实例共享,例子

1、prototype的建立
     例如:Person:大写表示是一个类,用prototype定义其公共属性和方法。

 
  发现这种方法,只建立一个Person prototype原型。

   function Person(){ }
     c.name = “Nicholas”;
     Person.prototype.age = 29;
     Person.prototype.job = “Software Engineer”;

     Person.prototype.sayName = function(){

        alert(this.name);

     };

    var person1 = new Person();

        person1.sayName(); //”Nicholas”

   var person2 = new Person();
       person2.sayName(); //”Nicholas”

    alert(person1.sayName == person2.sayName); //true
   上面,属性和sayName()方法时直接加到Person的prototype属性上,留下空的构造函数.
上面person1,person2 实例调用同一方法,结果一样。
2、Prototypes
工作过程:


 
   每建立一个函数,它的 prototype 属性同时建立,同时建立一个Person Prototype类, 所有的Person
prototypes自动的得到一个constructor属性,值指向类Person的prototype属性.
在上面例子中, 例如,Person.prototype.constructor指向Person.
     当定义一个自己的构造函数Person 时,Person  prototype仅默认的得到constructor属性,所有其它方法来自父类Object.每次构造函数被调用去建立一个新实例,实例有一个有一个内部指针指向属性 constructor. 

       实例(person1,person2)和Person prototype直接相连

但是实例(person1,person2)和构造函数(Person)不相连。

    


 
  alert(Person.prototype.isPrototypeOf(person1)); //true
   alert(Person.prototype.isPrototypeOf(person2)); //true

   alert(Object.getPrototypeOf(person1) == Person.prototype); //true
   alert(Object.getPrototypeOf(person1).name); //”Nicholas”   

    Person.prototype.isPrototypeOf(obj)方法:判断person1的实例是否和Person
prototype对象相连

    Object.getPrototypeOf(person1) :返回person1里面[[Prototype]]值。

2.1、查找对象属性的过程

 
   
调用 person1.sayName()时, 有两步,

 
        第一: the JavaScript engine 问, “实例 person1,你有一个叫sayName属性吗?”
no,因此它继续别找边问,

 
         第二:Person Prototype,你有一个叫sayName属性吗?”,yes,因此存贮在prototype
的函数被访问。

      person2.sayName()被调用, 会得到同样的结果,在多个对象中, 利用prototypes会共享属性和方法。

3、解决实例属性和prototype属性名字一样的问题。



function Person(){
}
Person.prototype.name = “Nicholas”;
Person.prototype.age = 29;
Person.prototype.job = “Software Engineer”;
Person.prototype.sayName = function(){
alert(this.name);
};

var person1 = new Person();

var person2 = new Person();
person1.name = “Greg”;

alert(person1.name); //”Greg” - from instance

alert(person2.name); //”Nicholas” - from prototype

 因为实例person1查找name时,从实例对象开始找,找到,则停止

person2没找到,去Prototype里面去找。

 可以删除person1中属性name,

 delete
person1.name;
alert(person1.name); //”Nicholas” - from the prototype
alert(person1.hasOwnProperty(“name”)); //false,实例1是否建立属性name.

   person1.hasOwnProperty(“name”)
 方法:

 
1、hasOwnProperty:只在实例person1上有用

 
2、“name” in person1:在实例person1上有用,在Prototype 上也有用,所以只要[b]name存在一方,会显示true[/b]

 
3、 一个对象的属性是否存在prototype
上,通过 hasOwnProperty()和in结合来判断。

 
    function hasPrototypeProperty(object, name){
        return !object.hasOwnProperty(name) && (name in object);

 4、Object.keys(p1):得到p1实例的所有属性和方法名

 
    var keys = Object.getOwnPropertyNames(Person.prototype);
      alert(keys); //”constructor,name,age,job,sayName”

function Person(){
}

Person.prototype.name = “Nicholas”;

Person.prototype.age = 29;

Person.prototype.job = “Software Engineer”;

Person.prototype.sayName = function(){

alert(this.name);

};
 
  var p1 = new Person();

     p1.name = “Rob”;

    p1.age = 31;

    var p1keys = Object.keys(p1);

    alert(p1keys); //”name,age”
四、上面prototype重复太多,声明简单写法 ,只有一个prototype,

 
        

function Person(){
}
Person.prototype = {
        name : “Nicholas”,
           age : 29,

        job : “Software Engineer”,

        sayName : function () {

      alert(this.name);

    }

};
上面有一个异常: the constructor 属性不再指向 Person对象。
所以你不能用constructor
来确定对象类型
var friend = new Person();

alert(friend instanceof Object); //true

alert(friend instanceof Person); //true

alert(friend.constructor == Person); //false

alert(friend.constructor == Object); //true

 1、更改方法1,直接加属性,如果你需要constructor来判断对象类型  

function Person(){
}
Person.prototype = {
         constructor: Person,
           name : “Nicholas”,

         age : 29,

          job : “Software Engineer”,

         sayName : function () {

       alert(this.name);

}

};
2、用 ECMAScript 5 新增的规范

function Person(){
}
Person.prototype = {
    name : “Nicholas”,
    age : 29,
    job : “Software Engineer”,
    sayName : function () {
           alert(this.name);
     }
};
//ECMAScript 5 only – restore the constructor

Object.defineProperty(Person.prototype, “constructor”, {

enumerable: false,

value: Person

});


五、Dynamic Nature of Prototypes

   但是Person Prototype 出现两个,一个是Person
P
rototype,一个是新的Person Prototype。

var friend= new Person();

   Person.prototype.sayHi = function(){

      alert(“hi”);

         };

friend.sayHi(); //”hi” - works!
下面例子:  
 类:Person

   实例:friend

  原型:Person.prototype 
 

  流程:当 friend.sayHi()
被调用时,执行new Person();。建立Person,Person
P
rototype,实例friend,

             1、浏览器去实例friend找属性sayHi,没有找到,出现错误。

             2、然后执行重写Person
P
rototype,建立一个新Person Prototype,

  

function Person(){
}
    var friend = new Person();
       Person.prototype = {//这是建立固定值对象的标准方式,会建立新Person
P
rototype原型。
           constructor: Person,
                   name : “Nicholas”,
                      age : 29,

                       job : “Software Engineer”,

                      sayName : function () {

                       alert(this.name);

                  }

       };

friend.sayName(); //error
 
    在这个例子中,当调用 friend.sayName() 时,一个新的Person
实例被建立,然后prototype objec是重写。
这将引起一个错误,因为friend 指向的原型并没有包含name属性,

 
举例如下:

     1、在原型赋值前,建立Person实例friend
,自动建立一个Person Prototype 原型,属性值为空。



 2、在原型赋值后,比上面多一个新的Person Prototype 原型,以前的指向变化的是,Person的prototype属性改指向new Person
Prototype。而new Person Prototype里面的constructor 指向Person构造函数,我喜欢叫Person类。

    


在构造函数上重写属性意味着新的实例将引用新的prototype ,而以前的实例指向不变。

六、Combination Constructor/Prototype Pattern

      这也许是最好的一种方式,和一个java类一样,分类级别(所有对象共享属性和方法)的和实例级别(属性和方法给特定的对象用)。
   

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.friends
= [“Shelby”, “Court”];
}
Person.prototype = {
        constructor: Person,
       sayName : function () {
       alert(this.name);
}
};
var person1 = new Person(“Nicholas”, 29, “Software Engineer”);

var person2 = new Person(“Greg”, 27, “Doctor”);

person1.friends.push(“Van”);

alert(person1.friends); //”Shelby,Court,Van”

alert(person2.friends); //”Shelby,Court”

alert(person1.friends === person2.friends); //false

alert(person1.sayName === person2.sayName); //true

 
  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript Prototyp