JavaScript 的繼承機制(圖文)
一、JavaScript的一些語言特性
1.當我們聲明一個函數時,實際上是定義了一個函數類型的對象。如下所示,下面三種方式定義函數對象結果是一樣的。
var func = function(){ //....define code goes there. } function func () { // ...define code goes there. } var func = new Function(....);
而當我們使用它時,它會一次執行其內的代碼。
2. this 指針的作用。在函數的內部,函數的this指針的作用域是動態綁定的,即this 代表的作用域是 上面的func 變量的作用域。但是,當我們使用new func()時,此時會為函數 func 獨立出一塊內存區域,this 的作用域便是func自己的區域。
var func = function() { this.name = "louis"; this.age = 22; } func(); //此時函數運行后,在外部window 對象可以訪問name,age var a = new func();// 此時的函數運行后,a.name,b,name.
總結:出現上面的情況是因為函數 是一個function 類型的對象,其中,內部定義的執行語句是不可識別的,都是以字符串的形式存儲在相應的區域,當我們調用它們的時候,即使用() 的時候,這時候的代碼才會被拿出來,在給定的一個作用域內解析并且執行。這就是所謂的動態綁定: 即只有在運行的情況下才知道其執行的上下文。
3.根據上面的函數的特性,我們現在定義了一個Person類 ,和一個Woman 類,由Woman類要繼承Person類,我們可以在Woman內,創建一個對Person 變量的一個引用,然后執行之,這時候函數執行的上下文是Woman內部,即Person函數執行后,Person 內部的變量、屬性自然隸屬于 Woman 創建的對象了.
function Person() { this.name="people"; this.speak = function(){ console.log("hello,Fellow"); } } // Woman要繼承Person類 function Woman() { this.birthe = function(){ console.log("brithing..."); } }
這種繼承的方式,叫做 對象冒充。
function Woman() { //對象冒充方式,將函數Person動態在Woman內部執行 this.newMethod = Person; this.newMethod(); delete this.newMethod; this.birthe = function(){ console.log("birthing...."); } }
二、繼承的方式介紹
1. 對象冒充(如上所述)
對象冒充可以實現多重繼承:
function ClassZ() { this.newMethod = ClassX; this.newMethod(); delete this.newMethod; this.newMethod = ClassY; this.newMethod(); delete this.newMethod; }
上面的模式有個弊端,就是ClassX和ClassY 的屬性定義中,如果有重復的情況,則對于繼承者ClassZ而言,要看其繼承順序,后面的聲明繼承的類會覆蓋先聲明的類,即:ClassY的屬性和 ClassX重合的話,ClassY會覆蓋ClassX內的屬性。
以對象冒充為原理,JavaScript提供了兩個可以完成此繼承的的方法:apply(),call();
假設現在有對象a, 它要繼承 B中的屬性和方法,如下所示:
function B (words) { this.name="hello"; this.say= function(){ console.log(words); }; } var a = new Object(); //a 繼承B內的屬性。 B.call(a,"hello"); B.apply(a,new Array("hello"));
2. 原型模式
在我們現實生活中,經常聽到 某某東西出現了山寨貨,那所謂的山寨貨,則是以某個正品貨為原型造出來的東西,即是仿的。javascript 內的“原型”,和這個意思差不多,都是以某一對象作為參考,進行對象的創建。故而,我們在對象的創建時,如果需要以某一對象作為原型,則如下操作:
// 設定B 以A 為原型創建 function A() { this.attr1; this.attr2; this.method1(); ///.... } function B() { } B.prototype = new A(); var b = new B();// 繼承A內所有的屬性
另外A 也可以以其它對象作為原型進行創建對象,由此,便組成了原型鏈:
使用原型繼承機制的一個弊端,就是B.prototype = new A(); A () 是不可以帶參數的。如果使用參數,則可以使用對象冒充。 function ClassA(sColor) {
this.color = sColor;
}
ClassA.prototype.sayColor = function () {
alert(this.color);
};
function ClassB(sColor, sName) {
ClassA.call(this, sColor);
this.name = sName;
}
ClassB.prototype = new ClassA();
ClassB.prototype.sayName = function () {
alert(this.name);
};