原文地址:http://dailyjs.com/2012/05/20/js101-prototype/javascript
在花費了不少年研究面向對象編程以後,想在javascript使用是使人失望的。主要是從根源上缺乏一個class
這樣的關鍵詞。然而,javascript的設計不會成爲阻礙 -- 精通它基於原型的繼承,將會加深你對該語言的理解。java
首先咱們須要弄清楚面向對象與面向類編程的區別。Javascript提供了咱們須要的工具來完成大多數語言的類能夠作的事情 -- 咱們只須要學習如何正確使用它。編程
咱們簡單的看一下prototype
屬性,看它如何深化咱們對javascript的瞭解。瀏覽器
prototype
屬性(The prototype Property)prototype
屬性是一個內部屬性,它被用於實現繼承。咱們這裏的「繼承」是一種特定的繼承形式。由於狀態和方法都由對象承載,因此咱們能夠說結構、行爲和狀態都是繼承的。這與基於類的語言造成對比,其狀態由實例承載,而方法由類承載。安全
構造函數就是一個具備屬性的方法,該屬性被稱做prototype
:函數
function Animal() { } console.log(Animal.prototype);
{}
標識Animal
具備一個prototype
屬性,可是沒有用戶定義它。咱們能夠隨意添加值和方法:工具
function Animal() { } Animal.prototype.type = 'Unknown'; Animal.prototype.weight = 0; Animal.prototype.weightUnits = 'kg'; Animal.prototype.toString = function() { return this.type + ', ' + this.weight + this.weightUnits; }; var molly = new Animal(); molly.type = 'Dog'; molly.weight = 28; console.log(molly.toString()); // Dog, 28kg
這將會輸出"Dog, 28kg"。咱們可使用對象字面量將這些賦值分組:學習
function Animal() { } Animal.prototype = { type: 'Unknown', weight: 0, weightUnits: 'kg', toString: function() { return this.type + ', ' + this.weight + this.weightUnits; } };
這樣就和你熟悉的類的方式差別不是很大。this
經過指定值能夠給對象動態的添加屬性。prototype
var molly = new Animal() , harley = new Animal(); molly.type = 'Dog'; molly.weight = 28; harley.type = 'Dog'; harley.weight = 38; harley.name = 'Harley'; console.log(molly); console.log(harley); // { type: 'Dog', weight: 28 } // { type: 'Dog', weight: 38, name: 'Harley' }
在這裏添加name
屬性隻影響了實例。然而,構造函數的屬性能夠被改變,而且將影響用這個原型建立的對象。
Animal.prototype.weightUnits = 'oz'; console.log(molly.toString()) // Now displays 'Dog, 28oz'
這就是爲何人們只會擴展本身的庫而不去改變內置原型,或者說只有這麼作纔是安全的。咱們徹底有可能改變對象,例如使用String
的內置方法作一些不安全的事情:
String.prototype.match = function() { return true; }; console.log('alex'.match(/1234/));
輸出爲true
,因此如今我成功的破壞了不少程序都在依賴的基礎方法。
改變內置原型也不必定所有是壞的;咱們使用它有用的東西,如修補支持更舊版本的ECMAScript
在舊版的瀏覽器。
若是咱們替換prototype
屬性會發生什麼?
var molly = new Animal() , harley; molly.type = 'Dog'; molly.weight = 28; Animal.prototype = { toString: function() { return '...'; } }; harley = new Animal; harley.type = 'Dog'; harley.weight = 38; console.log(molly.toString()); console.log(harley.toString()); // Dog, 28kg // ...
儘管事實上改變原型會影響全部實例,可是徹底替換構造函數的原型不會影響舊實例。爲何?實例具備對原型的引用,而不是離散拷貝。想象它就是這樣:使用new
關鍵字建立的每一個實例都連接到原始原型。