JavaScript 是一種基於原型的面嚮對象語言,而不是基於類的!!!javascript
基於類的面嚮對象語言,好比 Java,是構建在兩個不一樣實體的概念之上的:即類和對象。html
基於原型的語言(如 JavaScript)並不存在這種區別:它只有對象。基於原型的語言具備所謂原型對象(prototypical object)的概念。原型對象能夠做爲一個模板,新對象能夠從中得到原始的屬性。任何對象均可以指定其自身的屬性,既能夠是建立時也能夠在運行時建立。並且,任何對象均可以做爲另外一個對象的原型(prototype),從而容許後者共享前者的屬性。java
對象的產生程序員
例如工廠造一輛車,一方面,工人必須參照一張工程圖紙,設計規定這輛車應該如何製造。這裏的工程圖紙就比如是語言中的 類 (class),而車就是按照這個 類(class)製造出來的;另外一方面,工人和機器 ( 至關於 constructor) 利用各類零部件如發動機,輪胎,方向盤 ( 至關於 prototype 的各個屬性 ) 將汽車構造出來。web
例如:閉包
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();
每一個由構造器建立的對象擁有一個指向構造器 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 屬性皆被隱藏。(由於解釋器會查找該對象原型鏈中第一個含有該屬性的對象)
利用原型鏈 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 方法聲明類很是簡單。
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