1:JavaScript的面向對象編程和大多數其餘語言如Java、C#的面向對象編程都不太同樣。若是你熟悉Java或C#,很好,你必定明白麪向對象的兩個基本概念:javascript
類:類是對象的類型模板,例如,定義Student
類來表示學生,類自己是一種類型,Student
表示學生類型,但不表示任何具體的某個學生;java
實例:實例是根據類建立的對象,例如,根據Student
類能夠建立出xiaoming
、xiaohong
、xiaojun
等多個實例,每一個實例表示一個具體的學生,他們全都屬於Student
類型。編程
因此,類和實例是大多數面向對象編程語言的基本概念。ruby
不過,在JavaScript中,這個概念須要改一改。JavaScript不區分類和實例的概念,而是經過原型(prototype)來實現面向對象編程。編程語言
2:函數
原型是指當咱們想要建立xiaoming
這個具體的學生時,咱們並無一個Student
類型可用。那怎麼辦?剛好有這麼一個現成的對象:this
var robot = { name: 'Robot', height: 1.6, run: function () { console.log(this.name + ' is running...'); } };
咱們看這個robot
對象有名字,有身高,還會跑,有點像小明,乾脆就根據它來「建立」小明得了!spa
因而咱們把它更名爲Student
,而後建立出xiaoming
:prototype
var Student = { name: 'Robot', height: 1.2, run: function () { console.log(this.name + ' is running...'); } }; var xiaoming = { name: '小明' }; xiaoming.__proto__ = Student;
注意最後一行代碼把xiaoming
的原型指向了對象Student
,看上去xiaoming
彷彿是從Student
繼承下來的:code
xiaoming.name; // '小明' xiaoming.run(); // 小明 is running...
xiaoming
有本身的name
屬性,但並無定義run()
方法。不過,因爲小明是從Student
繼承而來,只要Student
有run()
方法,xiaoming
也能夠調用:
JavaScript的原型鏈和Java的Class區別就在,它沒有「Class」的概念,全部對象都是實例,所謂繼承關係不過是把一個對象的原型指向另外一個對象而已。
若是你把xiaoming
的原型指向其餘對象:
var Bird = { fly: function () { console.log(this.name + ' is flying...'); } }; xiaoming.__proto__ = Bird;
如今xiaoming
已經沒法run()
了,他已經變成了一隻鳥:
xiaoming.fly(); // 小明 is flying...
在JavaScrip代碼運行時期,你能夠把xiaoming
從Student
變成Bird
,或者變成任何對象。
請注意,上述代碼僅用於演示目的。在編寫JavaScript代碼時,不要直接用obj.__proto__
去改變一個對象的原型,而且,低版本的IE也沒法使用__proto__
。Object.create()
方法能夠傳入一個原型對象,並建立一個基於該原型的新對象,可是新對象什麼屬性都沒有,所以,咱們能夠編寫一個函數來建立xiaoming
:
// 原型對象: var Student = { name: 'Robot', height: 1.2, run: function () { console.log(this.name + ' is running...'); } }; function createStudent(name) { // 基於Student原型建立一個新對象: var s = Object.create(Student); // 初始化新對象: s.name = name; return s; } var xiaoming = createStudent('小明'); xiaoming.run(); // 小明 is running... xiaoming.__proto__ === Student; // true