1. 程式人生 > >實現javaScript物件的"繼承"的兩種方法(prototype與閉包)

實現javaScript物件的"繼承"的兩種方法(prototype與閉包)

javaScript的prototype屬性:

什麼是prototype:

javaScript的方法分為三類:

  • 類方法

  • 物件方法

  • 原型方法

function People(name)
{
  this.name=name;
  //物件方法
  this.Introduce=function(){
    alert("My name is "+this.name);
  }
}
//類方法
People.Run=function(){
  alert("I can run");
}
//原型方法
People.prototype.IntroduceChinese=function
(){
alert("我的名字是"+this.name); } //測試 var p1=new People("Windking"); p1.Introduce(); People.Run(); p1.IntroduceChinese();

javascript中的每個物件都有prototype屬性,Javascript中物件的prototype屬性的解釋是:返回物件型別原型的引用。

定義:原型就是一個函式物件的屬性。
作用:

  • 利用原型為函式物件增加屬性和方法
  • 函式物件的屬性或方法與原型的屬性或方法同名時:
  • 函式物件本身的屬性和方法的優先順序要高於原型上的熟悉感和方法
  • 利用函式物件的屬性和方法重寫原型上的屬性和方法
  • 內建物件(應該都是函式物件):都有prototype屬性
  • 可以擴充套件內建物件的屬性和方法
  • 實現繼承

在簡單瞭解了prototype的作用後,我們來使用prototype來實現繼承。

利用prototype來實現繼承

定義一個Person類

function  Person(){
   this.sayHello = function(){
      alert("helloworld");
     }
}
Person.prototype.setName=function(name){
  this
.name = name; } Person.prototype.getName=function(){ return this.name; } var p = new Person(); p.sayHello(); p.setName("wang"); alert(p.getName());

現在我們定義一個Student類來繼續Person類:

function Student(){

}
Student.prototype = new Person();
var s = new Student();
s.sayHello();
s.setName("xi");
alert(s.getName());

這樣Student類即繼承了Person類。

使用javaScript的閉包來完成繼承:

1.什麼是js的閉包

js閉包Demo:

    function A(){ 

    function B(){
     alert("Hello Closure!"); 
} 
 return B; 
} 
  var b = A(); 
   b();//Hello Closure! 

這是史上最簡單的閉包,不能再簡單了,再簡單就不是閉包了!B為在函式內部定義的函式,用A函式返回,並用b來接收,也就是說在函式內部定義的函式,在外部使用,這種現象為閉包,所以繼承的封裝是閉包的一種應用。

2.閉包的作用

avascript中的GC機制:在javascript中,如果一個物件不再被引用,那麼這個物件就會被GC回收,否則這個物件一直會儲存在記憶體中。

在上述例子中,B定義在A中,因此B依賴於A,而外部變數b又引用了B, 所以A間接的被b引用,也就是說,A不會被GC回收,會一直儲存在記憶體中。
這就是閉包的作用,有時候我們需要一個模組中定義這樣一個變數:希望這個變數一直儲存在記憶體中但又不會“汙染”全域性的變數,這個時候,我們就可以用閉包來定義這個模組。

閉包無處不在,比如:jQuery、zepto的主要程式碼都包含在一個大的閉包中,上面的寫法其實是最簡單最原始的寫法,而在實際應用中,沒人這麼玩,特別是在一些大型JS框架中更不會這麼寫。現在我們來寫一個閉包的高階用法:

    (function(document){ 

        var viewport; 

        var obj = { 
           init:function(id)
           {         
           viewport = document.querySelector("#"+id);   
           },          
           addChild:function(child){ 
           viewport.appendChild(child); 
           }, 
           removeChild:function(child){
            viewport.removeChild(child); 
           } } 
        window.jView = obj; 

    })(document); 

這個元件的作用是:初始化一個容器,然後可以給這個容器新增子容器,也可以移除一個容器。功能很簡單,但這裡涉及到了另外一個概念:立即執行函式。 簡單瞭解一下就行。主要是要理解這種寫法是怎麼實現閉包功能的。

(function(){})() 紅色部分是一個表示式,而這個表示式本身是一個匿名函式,所以在這個表示式後面加()就表示執行這個匿名函式。

因此這段程式碼執行執行過程可以分解如下:

    var f = function(document){

        var viewport; 

        var obj = { 

         init:function(id){ 
            viewport = document.querySelector("#"+id);
         },
        addChild:function(child){        
             viewport.appendChild(child); 
         }, 
         removeChild:function(child){               
            viewport.removeChild(child);
          } }

 window.jView = obj; 

    }; 

    f(document); 

在這段程式碼中似乎看到了閉包的影子,但 f 中沒有任何返回值,似乎不具備閉包的條件,注意這句程式碼:

    window.jView = obj;

obj 是在 f 中定義的一個物件,這個物件中定義了一系列方法, 執行window.jView = obj 就是在 window 全域性物件定義了一個變數 jView,並將這個變數指向 obj 物件,即全域性變數 jView 引用了 obj . 而 obj 物件中的函式又引用了 f 中的變數 viewport ,因此 f 中的 viewport 不會被GC回收,會一直儲存到記憶體中,所以這種寫法滿足閉包的條件。

瞭解了js的閉包之後使用閉包來實現繼承

function extend(obj1){
    function F(){ }
   //判斷傳遞進行的是一個new出來的物件
   if(typeof obj1 == "object"){
        for(var i in obj1){
        //直接呼叫物件的屬性來獲取,呼叫方法的prototype來接受
          F.prototype[i] = obj1[i];
         }
    }
    //返回函式
    return  F;
}
var person_son = extend(new Person());
var p = new person_son();
p.sayHello();
p.setName("abc");
alert(p.getName());

如上使用閉包也可以完成繼承。