JavaScript - 基於原型的面向對象

JavaScript - 基於原型的面向對象

1. 引言

JavaScript 是一種基於原型的面嚮對象語言,而不是基於類的!!!javascript

  • 基於類的面嚮對象語言,好比 Java,是構建在兩個不一樣實體的概念之上的:即類和對象。html

  • 基於原型的語言(如 JavaScript)並不存在這種區別:它只有對象。基於原型的語言具備所謂原型對象(prototypical object)的概念。原型對象能夠做爲一個模板,新對象能夠從中得到原始的屬性。任何對象均可以指定其自身的屬性,既能夠是建立時也能夠在運行時建立。並且,任何對象均可以做爲另外一個對象的原型(prototype),從而容許後者共享前者的屬性。java

對象的產生程序員

  • 基於類的面嚮對象語言: 依靠類產生
  • 基於原型的面嚮對象語言: 依靠 構造器利用原型構造出來的。

例如工廠造一輛車,一方面,工人必須參照一張工程圖紙,設計規定這輛車應該如何製造。這裏的工程圖紙就比如是語言中的 類 (class),而車就是按照這個 類(class)製造出來的;另外一方面,工人和機器 ( 至關於 constructor) 利用各類零部件如發動機,輪胎,方向盤 ( 至關於 prototype 的各個屬性 ) 將汽車構造出來。web

2.構造對象

  • 字面式對象聲明

例如:閉包

var test = {
    name : 'Test',
    email : '123@qq.com'
    website : 'http://www.test.com'
}

而後能夠訪問架構

//以成員的方式
test.name;
test.email;
//以hash_map的方式
test["name"];
test["website"];
  • 使用函數構造器構造對象

每一個構造器其實是一個 函數(function) 對象, 該函數對象含有一個「prototype」屬性用於實現 基於原型的繼承(prototype-based inheritance)和 共享屬性(shared properties)。ide

對象能夠由「new 關鍵字 + 構造器調用」的方式來建立函數

// 構造器 Person 自己是一個函數對象 
function Person() { // 此處可作一些初始化工做 }
// 它有一個名叫 prototype 的屬性
Person.prototype = { 
    name: "張三", 
    age: 26, 
    gender: "男",
    eat: function(stuff){ 
        alert("我在吃" + stuff); 
    } 
} // 使用 new 關鍵字構造對象 var p = new Person();

3.理解原型鏈

每一個由構造器建立的對象擁有一個指向構造器 prototype 屬性值的 隱式引用(implicit reference),這個引用稱之爲 原型(prototype)。進一步,每一個原型能夠擁有指向本身原型的 隱式引用(即該原型的原型),如此下去,這就是所謂的 原型鏈(prototype chain) 。this

在具體的語言實現中,每一個對象都有一個 proto 屬性來實現對原型的 隱式引用。

function Person(name){
    this.name = name; 
} 
var p = new Person(); 
console.log(p.__proto__ === Person.prototype ); // 對象的隱式引用指向了構造器的 prototype 屬性,因此此處打印 true 
console.log(Person.prototype.__proto__ === Object.prototype ); //原型自己是一個 Object 對象,因此他的隱式引用指向了Object 構造器的 prototype 屬性 , 故而打印 true 
console.log(Person.__proto__ === Function.prototype );// 構造器 Person 自己是一個函數對象,因此此處打印 true

有了 原型鏈,即可以定義一種所謂的 屬性隱藏機制,並經過這種機制實現繼承。當要給某個對象的屬性賦值時,解釋器會查找該對象原型鏈中第一個含有該屬性的對象(注:原型自己就是一個對象,那麼原型鏈即爲一組對象的鏈。對象的原型鏈中的第一個對象是該對象自己)進行賦值。反之,若是要獲取某個對象屬性的值,解釋器天然是返回該對象原型鏈中首先具備該屬性的對象屬性值。下圖說名了這中隱藏機制:

object1->prototype1->prototype2 構成了 對象 object1 的原型鏈,根據上述屬性隱藏機制,能夠清楚地看到 prototype1 對象中的 property4 屬性和 prototype2 對象中的 property3 屬性皆被隱藏。(由於解釋器會查找該對象原型鏈中第一個含有該屬性的對象

4.繼承

  • 利用原型鏈 Horse->Mammal->Animal 實現繼承

    // 聲明 Animal 對象構造器 
      function Animal(){}  // 將Animal 的 prototype 屬性指向一個對象,亦可直接理解爲指定 Animal 對象的原型 
      Animal.prototype = { 
          name: "animal",
          weight: 0, 
          eat: function(){ 
              alert( "Animal is eating!" ); 
          } 
      } 
    
      // 聲明 Mammal 對象構造器 function
      Mammal() { this.name = "mammal"; } // 指定 Mammal 對象的原型爲一個 Animal 對象。 
      Mammal.prototype = new Animal(); // 實際上此處即是在建立 Mammal 對象和 Animal 對象之間的原型鏈 
    
      // 聲明 Horse 對象構造器 
      function Horse(height,weight){ 
          this.name = "horse"; 
          this.height = height; 
          this.weight = weight;
      } 
      // 將 Horse對象的原型指定爲一個 Mamal 對象,繼續構建 Horse 與 Mammal 之間的原型鏈 
      Horse.prototype = new Mammal(); // 從新指定 eat方法 , 此方法將覆蓋從 Animal 原型繼承過來的 eat 方法 
      Horse.prototype.eat = function() { 
          alert( "Horse is eating grass!"); 
      } 
    
      // 驗證並理解原型鏈 
      var horse = new Horse( 100, 300 ); 
      console.log(horse.__proto__ === Horse.prototype ); 
      console.log( Horse.prototype.__proto__ === Mammal.prototype ); 
      console.log( Mammal.prototype.__proto__ === Animal.prototype );
  • 類式繼承

基於原型的繼承方式,雖然實現了代碼複用,但其行文鬆散且不夠流暢,可閱讀性差,不利於實現擴展和對源代碼進行有效地組織管理。

因此,類式繼承方式在語言實現上更具健壯性,且在構建可複用代碼和組織架構程序方面具備明顯的優點。這使得程序員們但願尋找到一種可以在 JavaScript 中以類式繼承風格進行編碼的方法途徑。

jQuery 之父 John Resig 在搏衆家之長以後,用不到 30 行代碼便實現了本身的 Simple Inheritance。使用其提供的 extend 方法聲明類很是簡單。

4.JavaScript 私有成員實現

JavaScript 的信息隱藏就是靠閉包實現的。

// 聲明 User 構造器 
 function User( pwd ) { 
    var password = pwd; // 定義私有屬性 
        // 定義私有方法 
    function getPassword() { // 返回了閉包中的 password    
        return password; 
    } // 特權函數聲明,用於該對象其餘公有方法能經過該特權方法訪問到私有成員 
    this.passwordService = function() { 
        return getPassword();
    } 
} 
// 公有成員聲明 
User.prototype.checkPassword = function( pwd ) { 
    return this.passwordService() === pwd; 
}; 
// 驗證隱藏性 
var u = new User( "123456" ); 
console.log( u.checkPassword("123456" )); // 打印 true 
console.log( u.password ); // 打印 undefined 
console.log( typeof u.getPassword === "undefined" );// 打印 true

JavaScript的prototype 具體含義,或者繼承機制的設計思想,良心推薦,講的很是清楚。

http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html

相關文章
相關標籤/搜索