這部分是我長久以來習慣於直接忽略的部分,可是後面在面試和實習的過程當中發現這部分知識是很是有用的!因此我花了很久時間看書、參考博客、敲代碼,結合本身的理解將這些內容總結以下~javascript
最開始想要直觀的理解請直接參考阮一峯老師博客關於繼承的講解:http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.htmlhtml
javascript語言是一種面向對象的語言,它沒有"子類"和"父類"的概念,裏面全部的數據類型都是對象,如何將這些對象聯繫起來呢?java
Brendan Eich在考慮設計繼承機制的時候,參考了C++和JAVA使用new命令,經過調用類的構造函數生成實例的方式,將new命令引入javascript。面試
C++的寫法是:閉包
ClassName *object = new ClassName(param);ide
Java的寫法是:函數
Person person = new Person();this
可是,javascript裏面沒有「類」這個概念,那麼,Brendan Eich決定直接在new後面跟一個構造函數,來生成實例。idea
構造函數是什麼?構造函數與其餘函數惟一的區別在於調用方式不一樣。任何函數只要經過new來調用就能夠做爲構造函數,它是用來建立特定類型的對象。spa
下面定義一個構造函數Female:
1 function Female(name){ 2 this.name = name; 3 this.sex = 'female'; 4 }
經過new命令來生成一個person實例:
var person1 = new Female("Summer")
這裏,構造函數Female就是實例對象person1的原型!!!Female裏的this關鍵字就指的是person1這個對象!
new出來的person1對象此時已經和Female再無聯繫了!也就是說每個new出來的實例都有本身的屬性和方法的副本,是獨立的的!修改其中一個不會影響另外一個!
var person1 = new Female("Summer"); var person2 = new Female("Lily"); person2.sex = 'male'; console.log(person1.sex) // female console.log(person2.sex) // male
可是,咱們但願構造函數中的sex屬性是一個共有屬性,那麼此時用這樣的方法,每一個實例中都有一個相同的sex屬性,會形成資源極大的浪費!
那麼原型對象就即將登場了!Brendan Eich決定給每個構造函數都設置一個prototype屬性,這個屬性就指向原型對象。其實原型對象就只是個普通對象,裏面存放着全部實例對象須要共享的屬性和方法!因此,咱們把須要共享的放到原型對象裏,把那些不須要共享的屬性和方法存在在構造函數裏!
那麼上面的代碼可改寫以下:
function Person(name,age){ this.name = name; } Person.prototype.sex = 'female'; var person1 = new Person("Summer"); var person2 = new Person("Lily"); console.log(person1.sex) // female console.log(person2.sex) // female Person.prototype.sex = 'male'; console.log(person1.sex) // male console.log(person2.sex) // male
能夠看出,修改prototype屬性會影響它的全部實例的sex的值!!
實例一旦建立出來就會自動引用prototype對象的屬性和方法!因此實例對象的屬性和方法通常分爲兩種:一種是自身的,一種是引用自prototype的。
具體實現是這樣的:
每當代碼讀取某個對象的某個屬性的時候,都會執行一次搜索。首先從對象實例自己開始,若是在實例中找到了該屬性,則返回該屬性的值,若是沒有找到,則順着原型鏈指針向上,到原型對象中去找,若是若是找到就返回該屬性值。
這裏要提一點,若是爲對象實例添加了一個屬性與原型中同名,則該屬性會屏蔽掉原型中的同名屬性,不會去修改它!使用delete能夠刪除實例中的屬性~(提到delete那要插一句~delete只能刪除對象下的屬性,不能刪除變量和參數!)
事實上,js裏徹底依靠"原型鏈"(prototype chain)模式來實現繼承。
上面說完原型對象。下面要扒一扒__proto__、prototype、constructor
__proto__:事實上就是原型鏈指針!!
prototype:上面說到這個是指向原型對象的
constructor:每個原型對象都包含一個指向構造函數的指針,就是constructor
爲了實現繼承,__proto__會指向上一層的原型對象,而上一層的結構依然相似,那麼就利用__proto__一直指向Object的原型對象上!Object.prototype.__proto__ = null;表示到達最頂端。如此造成了原型鏈繼承。
下面有個圖解很是經典,我本身也手畫了一遍去理解,真的很是有效~
大體總結一下就是:
Object是做爲衆多new出來的實例的基類 function Object(){ [ native code ] }
Function是做爲衆多function出來的函數的基類 function Function(){ [ native code ] }
構造函數的__proto__(包括Function.prototype和Object.prototype)都指向Function.prototype
原型對象的__proto__都指向Object.prototype
Object.prototype.__proto__指向null
今兒老爹生日~下午給老爹作cake~晚上繼續總結js相關的面試題和閉包~