日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

055_继承机制

發布時間:2025/4/17 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 055_继承机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 繼承機制實例

1.1. 說明繼承機制最簡單的方式是, 利用一個經典的例子:?幾何形狀。實際上, 幾何形狀只有兩種, 即橢圓形和多邊形。圓是橢圓的一種, 它只有一個焦點。三角形、矩形和五邊形都是多邊形的一種, 具有不同數量的邊。正方形是矩形的一種, 所有的邊等長。這就構成了一種完美的繼承關系。

1.2. 在這個例子中, 形狀(Shape)是橢圓形(Ellipse)和多邊形(Polygon)的基類(base class所有類都由它繼承而來)。圓形(Circle)繼承了橢圓形, 因此圓形是橢圓形的子類(subclass), 橢圓形是圓形的超類(superclass)。同樣, 三角形(Triangle)、矩形(Rectangle)和五邊形(Pentagon)都是多邊形的子類, 多邊形是它們的超類。最后, 正方形(Square)繼承了矩形。

2. 繼承機制的實現

2.1. 要用JavaScript實現繼承機制, 您可以從要繼承的基類入手。所有開發者定義的類都可作為基類。出于安全原因, 本地類和宿主類不能作為基類, 這樣可以防止公用訪問編譯過的瀏覽器級的代碼, 因為這些代碼可以被用于惡意攻擊。

2.2. 選定基類后, 就可以創建它的子類了。 有時, 你可能想創建一個不能直接使用的基類, 它只是用于給子類提供通用的函數, 在這種情況下, 基類被看作抽象類。

2.3. 創建的子類將繼承超類的所有屬性和方法, 包括構造函數及方法的實現。記住, 所有屬性和方法都是公用的, 因此子類可直接訪問這些方法。子類還可添加超類中沒有的新屬性和方法, 也可以覆蓋超類的屬性和方法。

3. 對象冒充

3.1. 其原理如下: 構造函數使用this關鍵字給所有屬性和方法賦值(即采用類聲明的構造函數方式)。因為構造函數只是一個函數, 所以可使ClassA構造函數成為ClassB的方法, 然后調用它。ClassB就會收到ClassA 的構造函數中定義的屬性和方法。例如, 用下面的方式定義ClassA和ClassB:

function ClassA(color) {this.color = color;this.sayColor = function () {alert(this.color);}; }function ClassB(color) {}

3.2. 這個原理是把ClassA作為常規函數來建立繼承機制, 而不是作為構造函數。如下使用構造函數ClassB可以實現繼承機制:

function ClassB(color) {this.newMethod = ClassA;this.newMethod(color);delete this.newMethod; }

3.3. 在這段代碼中, 為ClassA賦予了方法newMethod。然后調用該方法, 傳遞給它的是ClassB構造函數的參數color。最后一行代碼刪除了對ClassA的引用, 這樣以后就不能再調用它。

3.4. 所有新屬性和新方法都必須在刪除了新方法的代碼行后定義。否則, 可能會被超類的相關屬性和方法覆蓋:

function ClassB(color, name) {this.newMethod = ClassA;this.newMethod(color);delete this.newMethod;this.name = name;this.sayName = function () {alert(this.name);}; }

3.5. 對象冒充可以實現多重繼承

3.5.1. 有趣的是, 對象冒充可以支持多重繼承。也就是說, 一個類可以繼承多個超類。用UML表示的多重繼承機制如下圖所示:

3.5.2. 例如, 如果存在兩個類ClassX和ClassY, ClassZ想繼承這兩個類, 可以使用下面的代碼:

function ClassZ() {this.newMethod = ClassX;this.newMethod();delete this.newMethod;this.newMethod = ClassY;this.newMethod();delete this.newMethod; }

3.5.3. 這里存在一個弊端, 如果存在兩個類ClassX和ClassY具有同名的屬性或方法, ClassY具有高優先級。因為它從后面的類繼承。除這點小問題之外, 用對象冒充實現多重繼承機制輕而易舉。

4. call()方法

4.1. call()方法是與經典的對象冒充方法最相似的方法。它的第一個參數用作this的對象。其他參數都直接傳遞給函數自身。例如:

function sayColor(prefix, suffix) {alert(prefix + this.color + suffix); };var obj = new Object(); obj.color = "blue";sayColor.call(obj, "The color is ", "a very nice color indeed.");

4.2. 在這個例子中, 函數sayColor()在對象外定義, 即使它不屬于任何對象, 也可以引用關鍵字this。對象obj的color屬性等于blue。調用call()方法時, 第一個參數是obj, 說明應該賦予sayColor()函數中的this 關鍵字值是obj。第二個和第三個參數是字符串。它們與sayColor()函數中的參數prefix和suffix匹配, 最后生成的消息"The color is blue, a very nice color indeed."將被顯示出來。

4.3. 要與繼承機制的對象冒充方法一起使用該方法, 只需將前三行的賦值、調用和刪除代碼替換即可:

function ClassA(color) {this.color = color;this.sayColor = function () {alert(this.color);}; }function ClassB(color, name) {//this.newMethod = ClassA;//this.newMethod(color);//delete this.newMethod;ClassA.call(this, color);this.name = name;this.sayName = function () {alert(this.name);}; }

4.4. 這里, 我們需要讓ClassA中的關鍵字this等于新創建的ClassB對象, 因此this是第一個參數。第二個參數color對兩個類來說都是唯一的參數。

5. apply()方法

5.1. apply()方法有兩個參數, 用作this的對象和要傳遞給函數的參數的數組。例如:

function sayColor(prefix, suffix) {alert(prefix + this.color + suffix); };var obj = new Object(); obj.color = "blue";sayColor.apply(obj, new Array("The color is ", "a very nice color indeed."));

5.2. 這個例子與前面的例子相同, 只是現在調用的是apply()方法。調用apply()方法時, 第一個參數仍是obj, 說明應該賦予sayColor()函數中的this關鍵字值是obj。第二個參數是由兩個字符串構成的數組, 與sayColor() 函數中的參數prefix和suffix匹配, 最后生成的消息仍是"The color is blue, a very nice color indeed.", 將被顯示出來。

5.3. 該方法也用于替換前三行的賦值、調用和刪除新方法的代碼:

function ClassB(color, name) {//this.newMethod = ClassA;//this.newMethod(color);//delete this.newMethod;ClassA.apply(this, new Array(color));this.name = name;this.sayName = function () {alert(this.name);}; }

5.4. 同樣的, 第一個參數仍是this, 第二個參數是只有一個值color的數組。可以把ClassB的整個arguments對象作為第二個參數傳遞給apply()方法:

function ClassB(color, name) {//this.newMethod = ClassA;//this.newMethod(color);//delete this.newMethod;ClassA.apply(this, arguments);this.name = name;this.sayName = function () {alert(this.name);}; }

5.5. 當然, 只有超類中的參數順序與子類中的參數順序完全一致時才可以傳遞參數對象。如果不是, 就必須創建一個單獨的數組, 按照正確的順序放置參數。

6. 原型鏈(prototype chaining)

6.1. prototype對象是個模板, 要實例化的對象都以這個模板為基礎。總而言之, prototype對象的任何屬性和方法都被傳遞給那個類的所有實例。原型鏈利用這種功能來實現繼承機制。

6.2. 如果用原型方式重定義前面例子中的類, 它們將變為下列形式:

function ClassA() {}ClassA.prototype.color = "blue"; ClassA.prototype.sayColor = function () {alert(this.color); };function ClassB() {}ClassB.prototype = new ClassA();

6.3. 這里, 把ClassB的prototype屬性設置成ClassA的實例。

6.4. 調用ClassA的構造函數, 沒有給它傳遞參數。這在原型鏈中是標準做法。要確保構造函數沒有任何參數。

6.5. 與對象冒充相似, 子類的所有屬性和方法都必須出現在prototype屬性被賦值后, 因為在它之前賦值的所有方法都會被刪除。為什么?因為prototype屬性被替換成了新對象, 添加了新方法的原始對象將被銷毀。所以, 為 ClassB類添加name屬性和sayName()方法的代碼如下:

function ClassB() {}ClassB.prototype = new ClassA();ClassB.prototype.name = ""; ClassB.prototype.sayName = function () {alert(this.name); };

6.6. 原型鏈的弊端是不支持多重繼承。記住, 原型鏈會用另一類型的對象重寫類的prototype屬性。

7. 對象冒充和原型鏈

7.1. 對象冒充的主要問題是必須使用構造函數方式, 構造函數會重復生成函數。不過如果使用原型鏈, 不能通過給構造函數傳遞參數來初始化屬性的值, 而且對象被多個實例共享。

7.2. 繼承機制, 用對象冒充繼承構造函數的屬性, 用原型鏈繼承prototype對象的方法。用這兩種方式重寫前面的例子, 代碼如下:

function ClassA(color) {this.color = color; }ClassA.prototype.sayColor = function () {alert(this.color); };function ClassB(color, name) {ClassA.call(this, color);this.name = name; }ClassB.prototype = new ClassA();ClassB.prototype.sayName = function () {alert(this.name); };

7.3. 在此例子中, 在ClassB構造函數中, 用對象冒充繼承ClassA類的color屬性。用原型鏈繼承ClassA類的方法。

7.4. 由于這種混合方式使用了原型鏈, 所以instanceof運算符仍能正確運行。

8. 對象冒充例子

8.1. 代碼

<!DOCTYPE html> <html lang="zh-CN"><head><meta charset="utf-8" /><title>對象冒充實現繼承</title></head><body><script type="text/javascript">function Polygon(myName) { // 多邊形this.myName = myName;}function Rectangle(myName, width, height) { // 矩形this.extendPolygon = Polygon;this.extendPolygon(myName);delete this.extendPolygon;this.width = width;this.height = height;this.perimeter = function() {return (this.width + this.height) * 2;}}function Triangle(myName, width, height) { // 三角形Polygon.call(this, myName);this.width = width;this.height = height;this.area = function() {return this.width * this.height / 2;}}function Square(myName, width) { // 正方形Rectangle.apply(this, [myName, width, width]);this.area = function() {return this.width * this.width;}}var rectangle = new Rectangle('矩形', 100, 30);document.write(rectangle.myName + '的周長: ' + rectangle.perimeter() + '<br />');var square = new Square('正方形', 100);document.write(square.myName + '的周長: ' + square.perimeter() + '<br />');document.write(square.myName + '的面積: ' + square.area() + '<br />');var triangle = new Triangle('三角形', 100, 30);document.write(triangle.myName + '的面積: ' + triangle.area() + '<br />');document.write((rectangle instanceof Polygon) + '<br />');document.write((square instanceof Polygon) + '<br />');document.write((triangle instanceof Polygon) + '<br />');</script></body> </html>

8.2. 效果圖

9. 原型鏈例子

9.1. 代碼

<!DOCTYPE html> <html lang="zh-CN"><head><meta charset="utf-8" /><title>原型鏈實現繼承</title></head><body><script type="text/javascript">function ClassA() {}ClassA.prototype.color = "blue";ClassA.prototype.sayColor = function () {document.write(this.color + '<br />');};function ClassB(){}ClassB.prototype = new ClassA();var personZhang = new ClassB();personZhang.sayColor();function ClassC(firstName, lastName){this.firstName = firstName;this.lastName = lastName;}ClassC.prototype.fullName = function() {return this.firstName + this.lastName;};function ClassD(firstName, lastName){ClassC.apply(this, [firstName, lastName]);}ClassD.prototype = new ClassC();ClassD.prototype.drink = function() {document.write(this.fullName() + '喝的多。' + '<br />');};var personLi = new ClassD('李', '四');personLi.drink();document.write((personLi instanceof ClassD) + '<br />');document.write((personLi instanceof ClassC) + '<br />');</script></body> </html>

9.2. 效果圖

總結

以上是生活随笔為你收集整理的055_继承机制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。