搜尋
首頁web前端前端問答javascript繼承有什麼用

javascript繼承有什麼用

Jan 18, 2022 pm 01:48 PM
javascript繼承

javascript繼承的作用:1、可以不呼叫「父類別」的建構方法就創造新的實例;2、修改「父類別」的prototype可以動態修改所有已經創造的實例;3、可以動態修改一個物件的原型。

javascript繼承有什麼用

本教學操作環境:windows7系統、javascript1.8.5版、Dell G3電腦。

JavaScript 是以物件為基礎,以函數為模型,以原型為繼承的物件導向開發模式。

javascript繼承的作用:

1、可以不呼叫「父類別」的建構方法就創造新的實例

2 、修改「父類」的prototype 可以動態修改所有已經創造的實例

3、可以動態修改一個物件的原型,也就是說爸爸媽媽可以換

下面介紹定義 JavaScript 類型的方法,以及實作繼承的常用模式。

建構原型

直接使用 prototype 原型設計類別的繼承有兩個問題。

由於建構子事先聲明,而原型屬性在類別結構宣告之後才被定義,因此無法透過建構函式向原型動態傳遞參數。這樣實例化物件都是一個模樣,沒有個性。若要改變原型屬性值,則所有實例都會受到干擾。

當原型屬性的值為引用型別資料時,如果在一個物件實例中修改該屬性值,將會影響所有的實例。

範例1

簡單定義 Book 類型,然後實例化。

function Book () {};  //声明构造函数
Book.prototype.o = {x : 1, y : 2};  //构造函数的原型属性o是一个对象
var book1 = new Book ();  //实例化对象book1
var book2 = new Book ();  //实例化对象book2
console.log(book1.o.x);  //返回1
console.log(book2.o.x);  //返回1
book2.o.x = 3;  //修改实例化对象book2中的属性x的值
console.log(book1.o.x);  //返回3
console.log(book2.o.x);  //返回3

由於原型屬性 o 為一個引用型的值,所以所有實例的屬性 o 的值都是同一個物件的引用,一旦 o 的值發生變化,就會影響所有實例。

建構原型正是為了解決原型模式而誕生的混合設計模式,它把建構子模式與原型模式混合使用,從而避免了上述問題的發生。

實作方法:對於可能會互相影響的原型屬性,並且希望動態傳遞參數的屬性,可以把它們獨立出來使用建構函式模式來設計。對於不需要個性設計、具有共通性的方法或屬性,則可以使用原型模式來設計。

範例2

遵循上述設計原則,把其中兩個屬性設計為建構函式模式,設計方法為原型模式。

function Book (title, pages) {  //构造函数模式设计
    this.title = title;
    this.pages = pages;
}
Book.prototype.what = function () {  //原型模式设计
    console.log(this.title + this.pages);
};
var book1 = new Book("JavaScript 程序设计", 160);
var book2 = new Book("C语言程序设计", 240);
console.log(book1.title);
console.log(book2.title);

建構原型模式是 ECMAScript 定義類別的建議標準。一般建議使用建構函式模式定義所有屬性,使用原型模式定義所有方法。這樣所有方法都只建立一次,而每個實例都能夠根據需要設定屬性值。這也是使用最廣的一種設計模式。

動態原型

根據物件導向的設計原則,類型的所有成員應該都被封裝在類別結構體內。例如:

function Book (title, pages) {  //构造函数模式设计
    this.title = title;
    this.pages = pages;
    Book.prototype.what = function () {  //原型模式设计,位于类的内部
        console.log(this.title + this.pages);
    };
}

但當每次實例化時,類別 Book 中包含的原型方法就會重複創建,產生大量的原型方法,浪費系統資源。可以使用 if 判斷原型方法是否存在,如果存在就不再建立該方法,否則就建立方法。

function Book (title, pages) {
    this.title = title;
    this.pages = pages;
    if (typeof Book.isLock == "undefined") {  //创建原型方法的锁,如果不存在则创建
        Book.prototype.what = function () {
            console.log(this.title + this.pages);
        };
        Book.isLock = true;  //创建原型方法后,把锁锁上,避免重复创建
    }
}
var book1 = new Book("JavaScript 程序设计", 160);
var book2 = new Book("C语言程序设计", 240);
console.log(book1.title);
console.log(book2.title);

typeof Book.isLock 表達式能夠偵測該屬性值的類型,如果傳回為undefined 字串,則不存在該屬性值,說明沒有建立原型方法,並允許建立原型方法,設定該屬性的值為true,這樣就不用重複建立原型方法。這裡使用類別名稱 Book,而沒有使用 this,這是因為原型是屬於類別本身的,而不是物件實例的。

動態原型模式與建構原型模式在效能上是等價的,使用者可以自由選擇,不過建構原型模式應用比較廣泛。

工廠模式

工廠模式是定義類型的最基本方法,也是 JavaScript 最常用的開發模式。它把物件實例化簡單封裝在一個函數中,然後透過呼叫函數,實現快速、大量生產實例物件。

範例1

下列範例設計一個 Car 類型:包含汽車顏色、驅動輪數、百公里油耗 3 個屬性,同時定義一個方法,用來顯示汽車顏色。

function Car (color, drive, oil) {  //汽车类
    var _car =  new Object();  //临时对象
        _car.color = color;  //初始化颜色
        _car.drive = drive;  //初始化驱动轮数
        _car.oil = oil;  //初始化百公里油耗
        _car.showColor = function () {  //方法,提示汽车颜色
            console.log(this.color);
        };
        return _car;  //返回实例
}
var car1 = Car("red", 4, 8);
var car2 = Car("blue", 2, 6);
car1.showColor();  //输出“red”
car2.showColor();  //输出“blue”

上面程式碼是一個簡單的工廠模式類型,使用Car 類別可以快速建立多個汽車實例,它們的結構相同,但是屬性不同,可以初始化不同的顏色、驅動輪數和百公里油耗。

範例2

在型別中,方法就是一種行為或操作,它能夠根據初始化參數完成特定任務,具有共通性。因此,可以考慮把方法置於 Car() 函數外面,避免每次實例化時都要建立一次函數,讓每個實例共用同一個函數。

function showColor () {  //公共方法,提示汽车颜色
    console.log(this.color);
};
function Car (color, drive, oil) {  //汽车类
    var _car = new Object();  //临时对象
        _car.color = color;  //初始化颜色
        _car.drive = drive;  //初始化驱动轮数
        _car.oil = oil;  //初始化百公里油耗
        _car.showColor = showColor;  //引用外部函数
    return _car;  //返回实例
}

在上面這段重寫的程式碼中,在函數 Car() 之前定義了函數 showColor()。在 Car() 內部,透過引用外部 showColor() 函數,避免了每次實例化時都要建立新的函數。從功能上講,這樣解決了重複創建函數的問題;但是從語義上講,該函數不太像是物件的方法。

類別繼承

類別繼承的設計方法:在子類別中呼叫父類別建構子。

在 JavaScript 中实现类继承,需要注意以下 3 个技术问题。

在子类中,使用 apply 调用父类,把子类构造函数的参数传递给父类父类构造函数。让子类继承父类的私有属性,即 Parent.apply(this, arguments); 代码行。

在父类和子类之间建立原型链,即 Sub.prototype = new Parent(); 代码行。通过这种方式保证父类和子类是原型链上的上下级关系,即子类的 prototype 指向父类的一个实例。

恢复子类的原型对象的构造函数,即 Sub.prototype.constructor=Sub;语句行。当改动 prototype 原型时,就会破坏原来的 constructor 指针,所以必须重置 constructor。

示例1

下面示例演示了一个三重继承的案例,包括基类、父类和子类,它们逐级继承。

//基类Base
function Base (x) {  //构造函数Base
    this.get = function () {  //私有方法,获取参数值
        return x;
    }
}
Base.prototype.has = function () {  //原型方法,判断get()方法返回值是否为0
    return ! (this.get() == 0);
}
//父类Parent
function Parent () {  //构造函数Parent
    var a = [];  //私有数组a
    a = Array.apply(a, arguments);  //把参数转换为数组
    Base.call(this, a.length);  //调用Base类,并把参数数组长度传递给它
    this.add = function () {  //私有方法,把参数数组补加到数组a中并返回
        return a.push.apply(a, arguments)
    }
    this.geta = function () {  //私有方法,返回数组a
        return a;
    }
}
Parent.prototype = new Base();  //设置Parent原型为Base的实例,建立原型链
Parent.prototype.constructor = Parent;  //恢复Parent类原型对象的构造器
Parent.prototype.str = function (){  //原型方法,把数组转换为字符串并返回
    return this.geta().toString();
}
//子类Sub
function Sub () {  //构造函数
    Parent.apply(this, arguments);  //调用Parent类,并把参数数组长度传递给它
    this.sort = function () {  //私有方法,以字符顺序对数组进行排序
        var a = this.geta();  //获取数组的值
        a.sort.apply(a, arguments);  //调用数组排序方法 sort()对数组进行排序
    }
}
Sub.prototype = new Parent();  //设置Sub原型为Parent实例,建立原型链
Sub.prototype.constructor = Sub;  //恢复Sub类原型对象的构造器
//父类Parent的实例继承类Base的成员
var parent = new Parent (1, 2, 3, 4);  //实例化Parent类
console.log(parent.get());  //返回4,调用Base类的方法get()
console.log(parent.has());  //返回true,调用Base类的方法has()
//子类Sub的实例继承类Parent和类Base的成员
var sub = new Sub (30, 10, 20, 40);  //实例化Sub类
sub.add(6, 5);  //调用Parent类方法add(),补加数组
console.log(sub.geta());  //返回数组30,10,20,40,6,5
sub.sort();  //排序数组
console.log(sub.geta());  //返回数组10,20,30,40,5,6
console.log(sub.get());  //返回4,调用Base类的方法get()
console.log(sub.has());  //返回true,调用Base类的方法has()
console.log(sub.str());  //返回10,20,30,40,5,6

【设计思路】

设计子类 Sub 继承父类 Parent,而父类 Parent 又继承基类 Base。Base、Parent、Sub 三个类之间的继承关系是通过在子类中调用的构造函数来维护的。

例如,在 Sub 类中,Parent.apply(this, arguments); 能够在子类中调用父类,并把子类的参数传递给父类,从而使子类拥有父类的所有属性。

同理,在父类中,Base.call(this, a.length); 把父类的参数长度作为值传递给基类,并进行调用,从而实现父类拥有基类的所有成员。

从继承关系上看,父类继承了基类的私有方法 get(),为了确保能够继承基类的原型方法,还需要为它们建立原型链,从而实现原型对象的继承关系,方法是添加语句行 Parent.prototype=new Base();。

同理,在子类中添加语句 Sub.prototype=new Parent();,这样通过原型链就可以把基类、父类和子类串连在一起,从而实现子类能够继承父类属性,还可以继承基类的属性。

示例2

下面尝试把类继承模式封装起来,以便规范代码应用。

function extend (Sub, Sup) {  //类继承封装函数
    var F = function () {};  //定义一个空函数
    F.prototype = Sup.prototype;  //设置空函数的原型为父类的原型
    Sub.prototype = new F ();  //实例化空函数,并把父类原型引用传给给子类
    Sub.prototype.constructor = Sub;  //恢复子类原型的构造器为子类自身
    Sub.sup = Sup.prototype;  //在子类定义一个私有属性存储父类原型
    //检测父类原型构造器是否为自身
    if (Sup.prototype.constructor == Object.prototype.constructor) {
        Sup.prototype.constructor = Sup;  //类继承封装函数
    }
}

【操作步骤】

1) 定义一个封装函数。设计入口为子类和父类对象,函数功能是子类能够继承父类的所有原型成员,不涉及出口。

function extend (Sub, Sup) {  //类继承封装函数
    //其中参数Sub表示子类,Sup表示父类
}

2) 在函数体内,首先定义一个空函数 F,用来实现功能中转。设计它的原型为父类的原型,然后把空函数的实例传递给子类的原型,这样就避免了直接实例化父类可能带来的系统负荷。因为在实际开发中,父类的规模可能会很大,如果实例化,会占用大量内存。

3) 恢复子类原型的构造器为子类自己。同时,检测父类原型构造器是否与 Object 的原型构造器发生耦合。如果是,则恢复它的构造器为父类自身。

下面定义两个类,尝试把它们绑定为继承关系。

function A (x) {  //构造函数A
    this.x = x;  //私有属性x
    this.get = function () {  //私有方法get()
        return this.x;
    }
}
A.prototype.add = function () {  //原型方法add()
    return this.x + this.x;
}
A.prototype.mul = function () {  //原型方法mul()
    return this.x * this.x;
}
function B (x) {  //构造函数B
    A.call (this.x);  //在函数体内调用构造函数A,实现内部数据绑定
}
extend (B, A);  //调用封装函数,把A和B的原型捆绑在一起
var f = new B (5);  //实例化类B
console.log(f.get());  //继承类A的方法get(),返回5
console.log(f.add());  //继承类A的方法add(),返回10
console.log(f.mul());  //继承类A的方法mul(),返回25

在函数类封装函数中,有这么一句 Sub.sup=Sup.prototype;,在上面代码中没有被利用,那么它有什么作用呢?为了解答这个问题,先看下面的代码。

extend (B, A);
B.prototype.add = function () {  //为B类定义一个原型方法
    return this.x + "" + this.x;
}

上面的代码是在调用封装函数之后,再为 B 类定义了一个原型方法,该方法名与基类中原型方法 add() 同名,但是功能不同。如果此时测试程序,会发现子类 B 定义的原型方法 add() 将会覆盖父类 A 的原型方法 add()。

console.log(f.add());  //返回字符串55,而不是数值10

如果在 B 类的原型方法 add() 中调用父类的原型方法 add(),避免代码耦合现象发生。

B.prototype.add = function () {  //定义子类B的原型方法add()
    return B.sup.add.call(this);  //在函数内部调用父类方法add()
}

【相关推荐:javascript学习教程

以上是javascript繼承有什麼用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
CSS:使用ID選擇器不好嗎?CSS:使用ID選擇器不好嗎?May 13, 2025 am 12:14 AM

使用ID選擇器在CSS中並非固有地不好,但應謹慎使用。 1)ID選擇器適用於唯一元素或JavaScript鉤子。 2)對於一般樣式,應使用類選擇器,因為它們更靈活和可維護。通過平衡ID和類的使用,可以實現更robust和efficient的CSS架構。

HTML5:2024年的目標HTML5:2024年的目標May 13, 2025 am 12:13 AM

html5'sgoalsin2024focusonrefinement和optimization,notNewFeatures.1)增強performanceandeffipedroptimizedRendering.2)inviveAccessibilitywithRefinedwithRefinedTributesAndEllements.3)explityconcerns,尤其是withercercern.4.4)

HTML5試圖改進的主要領域是什麼?HTML5試圖改進的主要領域是什麼?May 13, 2025 am 12:12 AM

html5aimedtotoimprovewebdevelopmentInfourKeyAreas:1)多中心供應,2)語義結構,3)formcapabilities.1)offlineandstorageoptions.1)html5intoryements html5introctosements introdements and toctosements and toctosements,簡化了inifyingmediaembedingmediabbeddingingandenhangingusexperience.2)newsements.2)

CSS ID和類:常見錯誤CSS ID和類:常見錯誤May 13, 2025 am 12:11 AM

IDsshouldbeusedforJavaScripthooks,whileclassesarebetterforstyling.1)Useclassesforstylingtoallowforeasierreuseandavoidspecificityissues.2)UseIDsforJavaScripthookstouniquelyidentifyelements.3)Avoiddeepnestingtokeepselectorssimpleandimproveperformance.4

課程和ID選擇器之間的差異是什麼?課程和ID選擇器之間的差異是什麼?May 12, 2025 am 12:13 AM

classSelectorSareVersAtileAndReusable,whileIdSelectorSareEctorAreNiqueAndspecific.1)USECLASSSELECTORS(表示)forStylingmultilemtsswithsharedCharacteristics.2)UseIdSelectors.2)UseIdSelectors(eustotedBy#)

CSS IDS vs類:真正的差異CSS IDS vs類:真正的差異May 12, 2025 am 12:10 AM

IDSareuniqueIdentifiersForsingLelements,而LileclassesstyLemultiplelements.1)useidsforuniquelementsand andjavascripthooks.2)useclassesforporporporblesable,flexiblestylestylestylinglingactossmultiplelements。

CSS:如果我只使用課程怎麼辦?CSS:如果我只使用課程怎麼辦?May 12, 2025 am 12:09 AM

使用僅類選擇器可以提高代碼的重用性和可維護性,但需要管理類名和優先級。 1.提高重用性和靈活性,2.組合多個類創建複雜樣式,3.可能導致冗長類名和優先級問題,4.性能影響微小,5.遵循最佳實踐如簡潔命名和使用約定。

CSS中的ID和類選擇器:初學者指南CSS中的ID和類選擇器:初學者指南May 12, 2025 am 12:06 AM

ID和class選擇器在CSS中分別用於唯一和多元素的樣式設置。 1.ID選擇器(#)適用於單一元素,如特定導航菜單。 2.Class選擇器(.)用於多元素,如統一按鈕樣式。應謹慎使用ID,避免過度特異性,並優先使用class以提高樣式複用性和靈活性。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用