JavaScript 類式繼承與原型繼承

交叉着寫Java和Javascript都有2年多了,今天來總結下本身所瞭解的Javascript類與繼承。javascript

Javascript自己沒有相似Java的面向對象的類與繼承術語,但其基於原型對象的思想卻能夠輕鬆實現各類類和繼承。java

下面來描述實現類的第一種方法,請看例子:chrome

function People(name, age){
    this.name = name;
    this.age = age;
    this.say = function(){
        console.log('hello, javascript!');
    };
}
var people = new People('sky',25);
people.say();

從形式上看上去,與面向對象的類幾乎同樣,this爲實例化後的對象自身,name/age爲成員變量,say爲成員方法,但其內部原理卻相差甚遠。函數

接下來分析其中的不一樣之處,先看一下代碼:this

var people_1 = new People('sky1',21);
var people_2 = new People('sky2',22);
people_1.say == people_2.say//false

按照面向對象語言的特徵,表面上看上去people_1/2都有本身的屬性name/age,有公共的(佔用同一分內存區域)方法say,但在JS中並不是如此。spa

首先,People自身是一個對象,new People產生了兩個對象people_1/2,每一個對象都擁有各自的內存空間,即將name/age/say在各自空間都存在一份。prototype

可經過 people_1.say == people_2.say 驗證,結合下圖可清楚得出結論,每一個對象之間是獨立的個體,沒有關聯關係。code

接下來,結合JS原型概念構造類的第二種方法。原型是JS的核心概念,後續篇章詳細描述。對象

function People(name,age){
    this.name=name;
    this.age=age;
}

People.prototype.say = function(){
    console.log('hello, javascript!'); 
};

var people_1 = new People('sky1',21);
var people_2 = new People('sky2',22);

people_1.say == people_2.say//true

經過看到上述代碼結果,可得出people_1/2共享成員say,可經過下圖分析。這裏涉及到了原型鏈的概念,後面和原型一塊兒闡明。blog

關於類的構造就介紹到這。接下來描述實現繼承的幾種方法。

先來看第一種,基於類式繼承的方式。

function People(name,age,sex){
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.say=function(){
        console.log('hello,javascript!');
    };
}

function Man(name,age){
    People.call(this,name,age,'male');
}

function Woman(name,age){
    People.call(this,name,age,'female');
}

var man = new Man('sky-man',21);
var woman = new Woman('sky-woman',22);
man.say();
woman.say();

這種繼承基於第一種類的構造形式,即採用複製的方法實現子類對象對父類成員的繼承。

其中,起復製做用的關鍵在與People.call(this,...)語句上,意思是使用call方法借用People函數來構造Man對象。

這裏不太好理解,首先要理解call方法如何使用,其次要了解this做用域的概念和使用。關於做用域及做用域鏈概念也在之後的篇章中闡述。

總之,這裏的意義是將People對象的屬性複製到Man對象上。

咱們看下這裏的圖形描述:

很顯然man/woman都繼承了People的成員變量,但其採用的是複製的方法,對象之間並無創建真正的繼承。

接下來將基於第二種構造類的方法來介紹第二種構造類的形式,即繼承依賴原型。直接看一下代碼:

function People(name,age,sex){
    this.name=name;
    this.age=age;
    this.sex=sex;
}

People.prototype.say=function(){
    console.log('hello,javascript!');
}

function Man(name,age){
    People.call(this,name,age,'male');
}

Man.prototype = Object.create(People.prototype);

function Woman(name,age){
    People.call(this,name,age,'female');
}

Woman.prototype = Object.create(People.prototype);

上面的代碼可能已經引入一些JS原理層面的東西,仍是先用圖來展現:

上圖中引入幾個比較JS原理的東西,prototype/constructor/__proto__,其中前二者是JS標準中存在的,

而__proto__是標準中未暴露的,該名稱採用chrome暴露的屬性名。

其中prototype是原型函數,每一個函數中都存在;constructor是構造器,每一個對象都存在;__proto__是原型對象,每一個對象都存在。

此處先介紹到這,後期將根據ECMAScript標準詳細介紹幾者之間的關係。

經過上面的線條能夠了解每一個對象之間的關係,以及原型鏈在其中所起的做用。

能夠看出,第二種繼承方法是基於原型的,雖然成員是採用複製的方式,但保證了方法的繼承性。這與傳統面向對象類繼承意義上纔是一致的。

經過上面的類的構造和繼承方式,咱們對Javascript原型繼承有必定了解。那麼若是要實現內部成員,內部方法,該如何實現呢?

疑問將在下個篇章解答。

相關文章
相關標籤/搜索