JavaScript原型模式-理解對象

一:簡述html

  

  當初學編程一看到什麼什麼模式就比較頭暈,不過本文咱們經過簡單的示例代碼來講一下js 對象這個話題 ,來看下如何理解這個原型模式。java

二:理解對象chrome

    

  1.簡單對象編程

 

  js對象中沒有java、C#等類的概念。可是在js中 一切皆對象嘛 咱們能夠這麼寫一個實例數組

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 5     <title></title>
 6 </head>
 7 <body>
 8 
 9     <script>
10         //建立一個對象
11         var person = new Object();
12         //聲明屬性
13         person.name = 'hello';
14         person.age = 29;
15         person.job = 'Software Engineer';
16         //聲明方法
17         person.sayName = function () {
18             alert(this.name);
19         }
20     </script>
21 </body>
22 </html>

是否是很像一個class。但這是早期js建立對象的寫法,後來出現了對象字面量的寫法 簡化了上面的寫法瀏覽器

 

  2.對象字面量ide

 

  咱們來改進上面的寫法  函數

 1 var person = {
 2             //屬性
 3             name: 'hello',
 4             age: 29,
 5             job: 'Software Engineer',
 6             //聲明方法
 7             sayName: function () {
 8                 alert(this.name);
 9             }
10         }

是否是簡化了不少,可是上面兩種建立的對象若是建立多了會產生大量重複代碼 ,因此也就出現瞭如下第三種模式(又是模式....)ui

  

  3.工廠模式this

  

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 5     <title></title>
 6 </head>
 7 <body>
 8 
 9     <script>
10         //用函數來包裝
11         function createPerson() {
12             var person = new Object();
13             //聲明屬性
14             person.name = 'hello';
15             person.age = 29;
16             person.job = 'Software Engineer';
17             //聲明方法
18             person.sayName = function () {
19                 alert(this.name);
20             }
21             return person;
22         }
23         //調
24         var person1 = createPerson('tom', 21, 'baidu');
25         var person2 = createPerson('tony', 31, 'tencent');
26     </script>
27 </body>
28 </html>

工廠就是把東西加工、包裝成一個對象。 其實咱們大多數的寫法也就是這麼個模式 。可是這樣咱們怎麼知道這個對象的類型呢 ?隨着js發展又出來一個新模式

  

  4.構造函數模式

  

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 5     <title></title>
 6 </head>
 7 <body>
 8 
 9     <script>
10        
11 
12         function Person(name,age,job) {
13             this.name = name;
14             this.age = age;
15             this.job = job;
16             this.sayName = function () {
17                 alert(this.name);
18             }
19         }
20 
21         var pserson1 = new Person('tom', 21, 'baidu');
22         var pserson2= new Person('tony', 31, 'tencent');
23     </script>
24 </body>
25 </html>

  看着是否是跟對象字面量很像。這個模式跟工廠模式對比來看 

    a.沒有顯示的建立對象

    b.直接將屬性和方法賦值給了this對象

    c.沒有return

    d.執行構造函數中的代碼(在Person新對象中添加屬性和方法)

         

  console.info(person1.constructor == Person);//true
  console.info(person1.constructor == Person);//true

 

  對象的constructor屬性 是用來標識對象類型的 ,能夠將他的實例標識爲一種特定的類型

 

  說說這個特殊的函數--構造函數 ,它跟函數的惟一區別就是調用的方式不一樣(有啥不一樣啊。。)

  只要是能經過new操做符來調用的函數就能夠做爲構造函數。(沒new的就是普通函數唄O(∩_∩)O)

   

 //我是構造函數
  var pserson1 = new Person('tom', 21, 'baidu');
  //我是普通函數
  person('tony', 31, 'tencent');

構造函數模式也有本身的問題。每一個方法都要在每一個實例上從新建立一遍。

構造函數的另外一種定義:  

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body> 
    <script> 
        function Person(name,age,job) {
            this.name = name;
            this.age = age;
            this.job = job;
            //第一種寫法
            this.sayName = function () {
                alert(this.name);
            }
            //第二種寫法
            this.sayName = new Function("alert(this.name)")
        }
         
    </script>
</body>
</html>

這樣就能夠看出person1.sayName 不等於person2.sayName了  由於不一樣實例的同名函數是不相等的

可是咱們能夠這麼寫:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body> 
    <script> 
        function Person(name,age,job) {
            this.name = name;
            this.age = age;
            this.job = job; 
            this.sayName = sayName
        }
        function sayName() {
            alert(this.name);
        }
    </script>
</body>
</html>

可是這樣雖然是函數指向相同了  可是方法多了 就沒有封裝性可言了 。

  

  5.原型模式

 

  咱們每一個函數都有一個prototype(原型)屬性。它是構造函數中(就是new的函數)自動建立的對象實例的原型對象 (就是一new就有了)

好處:可讓全部對象實例共享它包含的屬性和方法(能夠直接添)以下

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body> 
    <script> 
        //聲明一個空函數(首字母大寫)
        function Person() {

        }
     //添加屬性和方法 Person.prototype.name
= "tony"; Person.prototype.age=29; Person.prototype.job = 'baidu'; Person.prototype.sayName = function () { alert(this.name); } var person1 = new Person(); person1.sayName();//baidu var person2 = new Person(); person2.sayName();//baidu alert(person1.sayName == person2.sayName);//true </script> </body> </html>

由於新對象的屬性和方法都是共享的,因此person1和person2都是訪問的同一個sayName函數 

  a.理解原型對象:

  上面說到只要建立一個函數就會自動建立一個prototype屬性,這個屬性指向的就是函數的原型對象

  Person.prototype.constructor就是Person 

  

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body> 
    <script> 
        //聲明一個函數(首字母大寫)
        function Person() {

        }
        Person.prototype.name = "tony";
        Person.prototype.age=29;
        Person.prototype.job = 'baidu';
        Person.prototype.sayName = function () {
            alert(this.name);
        } 
        var person1 = new Person();
        console.info(person1);
    </script>
</body>
</html>
View Code

 chrome中打印輸出結構:

  

雖然person1不包含任何屬性和方法 ,可是咱們可使用person1.sayName() 這就是經過查找對象屬性來實現的

person1就是實例 Person就是原型 當實例中的屬性修改後

person1.name='1234' 不影響實例的屬性 person2沒修改 name仍是tony

delete person1.name;

這個能夠刪除person1的實例屬性 從而訪問到原型中的值

 

  (1)咱們能夠經過hasOwnProperty方法來判斷自己是否有這個屬性(就是判斷本身有沒有該屬性 返回true、false)  

 1   <script> 
 2         //聲明一個函數(首字母大寫)
 3         function Person() {
 4 
 5         }
 6         Person.prototype.name = "tony";
 7         Person.prototype.age=29;
 8         Person.prototype.job = 'baidu';
 9         Person.prototype.sayName = function () {
10             alert(this.name);
11         } 
12         var person1 = new Person();
13         alert(person1.hasOwnProperty('name'));//false
14         person1.name = '123';//我本身從新賦值  有了該屬性
15         alert(person1.hasOwnProperty('name'));//true
16         console.info(person1);
17     </script>

 

  (2)經過 in操做符來判斷(單獨使用和在for循環中)

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 5     <title></title>
 6 </head>
 7 <body> 
 8     <script> 
 9         //聲明一個函數(首字母大寫)
10         function Person() {
11 
12         }
13         Person.prototype.name = "tony";
14         Person.prototype.age=29;
15         Person.prototype.job = 'baidu';
16         Person.prototype.sayName = function () {
17             alert(this.name);
18         } 
19         var person1 = new Person();
20         alert(person1.hasOwnProperty('name'));//false
21         alert('name' in person1) //true
22         person1.name = '123';//我本身從新賦值  有了該屬性
23         alert(person1.hasOwnProperty('name'));//true
24         alert('name' in person1) //true
25        
26     </script>
27 </body>
28 </html>

能夠看到in能夠訪問到原型中去查找也就返回了都是true  而hasOwnProperty只在自己查找

  (3)我只想看是否在原型中的屬性 使用hasPrototypeProperty (在原型中不在實例中的屬性)

  (4)像in的用法在ie等瀏覽器中是有bug的 因此es5提供了 Object.keys() 方法來獲取全部枚舉屬性

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body> 
    <script> 
        //聲明一個函數(首字母大寫)
        function Person() {

        }
        Person.prototype.name = "tony";
        Person.prototype.age=29;
        Person.prototype.job = 'baidu';
        Person.prototype.sayName = function () {
            alert(this.name);
        }

        var keys = Object.keys(Person.prototype);
        alert(keys);//name,age,job,sayName
        var person1 = new Person(); 
        person1.name = '123';//我本身從新賦值  有了該屬性
        var keys2 = Object.keys(person1.prototype);
        alert(keys2);//name
        
       
    </script>
</body>
</html>

上面原型寫法徹底能夠用對象字面量的形勢簡寫(注意字面量寫法中的紅字)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body> 
    <script> 
        //聲明一個函數(首字母大寫)
        function Person() {

        }
        Person.prototype = {
       constructor:Person,//修正構造函數從新指向本身 name:
"tony", age: 29, job: 'baidu', sayName: function () { alert(this.name); } } //Person.prototype.name = "tony"; //Person.prototype.age=29; //Person.prototype.job = 'baidu'; //Person.prototype.sayName = function () { // alert(this.name); //} </script> </body> </html>

   

原型模式最大的問題是共享的本性致使的 。裏面包含引用類型好比數組 也會跟着共享

因此原型模式通常不會單獨出現

 

  6.組合使用構造函數模式和原型模式

  構造函數模式用來定義實例屬性  

  原型模式用來定義方法和共享的屬性 

   這種混合模式是目前es中使用最普遍和認同度最高的一種自定義類型的方法  這也是引用類型的一種默認方式

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body>
    <script>
        //聲明一個函數(首字母大寫)
        function Person(name, age, job) {
            this.name = name;
            this.age = age;
            this.job = job;
            this.friends = ["lili","tonk"];
        }
        Person.prototype = {
            constructor: Person,
            sayName: function () {
                alert(this.name);
            }
        }

        var person1 = createPerson('tom', 21, 'baidu');
        var person2 = createPerson('tony', 31, 'tencent');

        person1.friends.push('van');
        console.info(person1.friends);//lili、tonk、van
        console.info(person2.friends);//lili、tonk
        console.info(person1.friends == person2.friends);//false
        console.info(person1.sayName == person2.sayName);//true
    </script>
</body>
</html>
相關文章
相關標籤/搜索