JS中常見(jiàn)的8種繼承方法總結(jié)
1. 原型鏈繼承:
原型鏈繼承是JavaScript中最基本的繼承方式。每個(gè)對(duì)象都有一個(gè)原型對(duì)象,通過(guò)原型鏈將屬性和方法沿著對(duì)象鏈傳遞下來(lái)。在原型鏈繼承中,通過(guò)將子構(gòu)造函數(shù)的原型對(duì)象指向父構(gòu)造函數(shù)的實(shí)例,實(shí)現(xiàn)了繼承。這意味著子對(duì)象可以訪問(wèn)父對(duì)象原型鏈上的屬性和方法。
function Parent() {
this.name = 'Parent';
}
Parent.prototype.sayHello = function() {
console.log('Hello');
};
function Child() {
this.name = 'Child';
}
Child.prototype = new Parent();
var child = new Child();
child.sayHello(); // Hello
function Parent() {
this.name = 'Parent';
}
Parent.prototype.sayHello = function() {
console.log('Hello');
};
function Child() {
this.name = 'Child';
}
Child.prototype = new Parent();
var child = new Child();
child.sayHello(); // Hello
在這個(gè)例子中,Child對(duì)象的原型對(duì)象被設(shè)置為Parent的一個(gè)實(shí)例。這樣,當(dāng)我們調(diào)用child.sayHello()時(shí),它會(huì)首先在子對(duì)象上查找sayHello方法,然后在父對(duì)象原型鏈上找到并執(zhí)行該方法。注意:原型鏈繼承的缺點(diǎn)是,所有子對(duì)象共享同一個(gè)原型對(duì)象,對(duì)原型對(duì)象的修改會(huì)影響到所有子對(duì)象。
2. 構(gòu)造函數(shù)繼承(經(jīng)典繼承):
構(gòu)造函數(shù)繼承是通過(guò)在子構(gòu)造函數(shù)中調(diào)用父構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)繼承。在構(gòu)造函數(shù)繼承中,通過(guò)在子構(gòu)造函數(shù)中使用**call()或apply()**方法,將父構(gòu)造函數(shù)的上下文設(shè)置為子對(duì)象的上下文,從而實(shí)現(xiàn)繼承。
function Parent(name) {
this.name = name;
}
function Child(name) {
Parent.call(this, name);
}
var child = new Child('Child');
console.log(child.name); // Child
function Parent(name) {
this.name = name;
}
function Child(name) {
Parent.call(this, name);
}
var child = new Child('Child');
console.log(child.name); // Child
在這個(gè)例子中,我們通過(guò)在Child構(gòu)造函數(shù)內(nèi)部調(diào)用Parent構(gòu)造函數(shù),并傳遞子對(duì)象特定的參數(shù),實(shí)現(xiàn)了繼承。注意:構(gòu)造函數(shù)繼承只能繼承父構(gòu)造函數(shù)的實(shí)例屬性,無(wú)法繼承父構(gòu)造函數(shù)的原型對(duì)象上的方法。
3. 組合繼承:
組合繼承結(jié)合了原型鏈繼承和構(gòu)造函數(shù)繼承,既繼承了父構(gòu)造函數(shù)的屬性,又繼承了父構(gòu)造函數(shù)原型對(duì)象上的方法。在組合繼承中,通過(guò)調(diào)用父構(gòu)造函數(shù)的方式實(shí)現(xiàn)屬性的繼承,通過(guò)將子構(gòu)造函數(shù)的原型對(duì)象指向父構(gòu)造函數(shù)的實(shí)例實(shí)現(xiàn)方法的繼承。
function Parent(name) {
this.name = name;
}
Parent.prototype.sayHello = function() {
console.log('Hello');
};
function Child(name) {
Parent.call(this, name);
}
Child.prototype = new Parent();
var child = new Child('Child');
child.sayHello(); // Hello
function Parent(name) {
this.name = name;
}
Parent.prototype.sayHello = function() {
console.log('Hello');
};
function Child(name) {
Parent.call(this, name);
}
Child.prototype = new Parent();
var child = new Child('Child');
child.sayHello(); // Hello
在這個(gè)例子中,我們通過(guò)調(diào)用**Parent.call(this, name)來(lái)繼承父構(gòu)造函數(shù)的屬性,并通過(guò)Child.prototype = new Parent()**將子構(gòu)造函數(shù)的原型對(duì)象指向父構(gòu)造函數(shù)的實(shí)例,從而實(shí)現(xiàn)方法的繼承。組合繼承的優(yōu)點(diǎn)是既能夠繼承父構(gòu)造函數(shù)的屬性,又能夠繼承父構(gòu)造函數(shù)原型對(duì)象上的方法。然而,缺點(diǎn)是在創(chuàng)建子對(duì)象時(shí)會(huì)調(diào)用兩次父構(gòu)造函數(shù),一次是在設(shè)置原型時(shí),一次是在創(chuàng)建子對(duì)象時(shí)。這樣會(huì)產(chǎn)生一些不必要的開(kāi)銷。
4. 原型式繼承:
原型式繼承是通過(guò)使用一個(gè)臨時(shí)構(gòu)造函數(shù)和**Object.create()**方法來(lái)實(shí)現(xiàn)繼承。
var parent = {
name: 'Parent',
sayHello: function() {
console.log('Hello');
}
};
var child = Object.create(parent);
console.log(child.name); // Parent
child.sayHello(); // Hello
var parent = {
name: 'Parent',
sayHello: function() {
console.log('Hello');
}
};
var child = Object.create(parent);
console.log(child.name); // Parent
child.sayHello(); // Hello
在這個(gè)例子中,我們創(chuàng)建了一個(gè)parent對(duì)象,然后使用**Object.create()**方法創(chuàng)建了一個(gè)新對(duì)象child,并將其原型對(duì)象指向parent對(duì)象,實(shí)現(xiàn)了繼承。原型式繼承的本質(zhì)是創(chuàng)建一個(gè)新對(duì)象,將其原型對(duì)象指向另一個(gè)已有的對(duì)象。這種方式可以實(shí)現(xiàn)屬性和方法的繼承,但是不能傳遞構(gòu)造函數(shù)的參數(shù)。
5. Object.create()
Object.create() 是把現(xiàn)有對(duì)象的屬性,掛到新建對(duì)象的原型上,新建對(duì)象為空對(duì)象
ECMAScript 5通過(guò)增加Object.create()方法將原型式繼承的概念規(guī)范化了。這個(gè)方法接收兩個(gè)參數(shù):作為新對(duì)象原型的對(duì)象,以及給新對(duì)象定義額外屬性的對(duì)象(第二個(gè)可選)。在只有一個(gè)參數(shù)時(shí),Object.create()與這里的函數(shù)A方法效果相同。
let person = {
name: 'mjy',
age: 19,
hoby: ['唱', '跳'],
showName() {
console.log('my name is: ', this.name)
}
}
let child1 = Object.create(person)
child1.name = 'xxt'
child1.hoby.push('rap')
let child2 = Object.create(person)
console.log(child1)
console.log(child2)
console.log(person.hoby) // ['唱', '跳', 'rap']let person = {
name: 'mjy',
age: 19,
hoby: ['唱', '跳'],
showName() {
console.log('my name is: ', this.name)
}
}
let child1 = Object.create(person)
child1.name = 'xxt'
child1.hoby.push('rap')
let child2 = Object.create(person)
console.log(child1)
console.log(child2)
console.log(person.hoby) // ['唱', '跳', 'rap']
優(yōu)點(diǎn): 不需要單獨(dú)創(chuàng)建構(gòu)造函數(shù)。
缺點(diǎn): 屬性中包含的引用值始終會(huì)在相關(guān)對(duì)象間共享,子類實(shí)例不能向父類傳參
6. 寄生式繼承
寄生式繼承的思路與(寄生) 原型式繼承 和 工廠模式 似, 即創(chuàng)建一個(gè)僅用于封裝繼承過(guò)程的函數(shù),該函數(shù)在內(nèi)部以某種方式來(lái)增強(qiáng)對(duì)象,最后再像真的是它做了所有工作一樣返回對(duì)象。
function objectCopy(obj) {
function Fun() { };
Fun.prototype = obj;
return new Fun();
}
function createAnother(obj) {
let clone = objectCopy(obj);
clone.showName = function () {
console.log('my name is:', this.name);
};
return clone;
}
let person = {
name: "mjy",
age: 18,
hoby: ['唱', '跳']
}
let child1 = createAnother(person);
child1.hoby.push("rap");
console.log(child1.hoby); // ['唱', '跳', 'rap']
child1.showName(); // my name is: mjy
let child2 = createAnother(person);
console.log(child2.hoby); // ['唱', '跳', 'rap']function objectCopy(obj) {
function Fun() { };
Fun.prototype = obj;
return new Fun();
}
function createAnother(obj) {
let clone = objectCopy(obj);
clone.showName = function () {
console.log('my name is:', this.name);
};
return clone;
}
let person = {
name: "mjy",
age: 18,
hoby: ['唱', '跳']
}
let child1 = createAnother(person);
child1.hoby.push("rap");
console.log(child1.hoby); // ['唱', '跳', 'rap']
child1.showName(); // my name is: mjy
let child2 = createAnother(person);
console.log(child2.hoby); // ['唱', '跳', 'rap']
優(yōu)點(diǎn): 寫(xiě)法簡(jiǎn)單,不需要單獨(dú)創(chuàng)建構(gòu)造函數(shù)。
缺點(diǎn): 通過(guò)寄生式繼承給對(duì)象添加函數(shù)會(huì)導(dǎo)致函數(shù)難以重用。使用寄生式繼承來(lái)為對(duì)象添加函數(shù), 會(huì)由于不能做到函數(shù)復(fù)用而降低效率;這一點(diǎn)與構(gòu)造函數(shù)模式類似.
7. 寄生組合式繼承
前面講過(guò),組合繼承是常用的經(jīng)典繼承模式,不過(guò),組合繼承最大的問(wèn)題就是無(wú)論什么情況下,都會(huì)調(diào)用兩次父類構(gòu)造函數(shù);一次是在創(chuàng)建子類型的時(shí)候,一次是在子類型的構(gòu)造函數(shù)內(nèi)部。寄生組合繼承就是為了降低父類構(gòu)造函數(shù)的開(kāi)銷而實(shí)現(xiàn)的。
通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性,通過(guò)原型鏈的混成形式來(lái)繼承方法。本質(zhì)上,就是使用寄生式繼承來(lái)繼承超類型的原型,然后再將結(jié)果指定給子類型的原型。
function objectCopy(obj) {
function Fun() { };
Fun.prototype = obj;
return new Fun();
}
function inheritPrototype(child, parent) {
let prototype = objectCopy(parent.prototype);
prototype.constructor = child;
Child.prototype = prototype;
}
function Parent(name) {
this.name = name;
this.hoby = ['唱', '跳']
}
Parent.prototype.showName = function () {
console.log('my name is:', this.name);
}
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
inheritPrototype(Child, Parent);
Child.prototype.showAge = function () {
console.log('my age is:', this.age);
}
let child1 = new Child("mjy", 18);
child1.showAge(); // 18
child1.showName(); // mjy
child1.hoby.push("rap");
console.log(child1.hoby); // ['唱', '跳', 'rap']
let child2 = new Child("yl", 18);
child2.showAge(); // 18
child2.showName(); // yl
console.log(child2.hoby); // ['唱', '跳']function objectCopy(obj) {
function Fun() { };
Fun.prototype = obj;
return new Fun();
}
function inheritPrototype(child, parent) {
let prototype = objectCopy(parent.prototype);
prototype.constructor = child;
Child.prototype = prototype;
}
function Parent(name) {
this.name = name;
this.hoby = ['唱', '跳']
}
Parent.prototype.showName = function () {
console.log('my name is:', this.name);
}
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
inheritPrototype(Child, Parent);
Child.prototype.showAge = function () {
console.log('my age is:', this.age);
}
let child1 = new Child("mjy", 18);
child1.showAge(); // 18
child1.showName(); // mjy
child1.hoby.push("rap");
console.log(child1.hoby); // ['唱', '跳', 'rap']
let child2 = new Child("yl", 18);
child2.showAge(); // 18
child2.showName(); // yl
console.log(child2.hoby); // ['唱', '跳']
優(yōu)點(diǎn): 高效率只調(diào)用一次父構(gòu)造函數(shù),并且因此避免了在子原型上面創(chuàng)建不必要,多余的屬性。與此同時(shí),原型鏈還能保持不變;
缺點(diǎn): 代碼復(fù)雜
8. ES6類繼承:
在ES6中引入了類的概念,通過(guò)class關(guān)鍵字和extends關(guān)鍵字可以實(shí)現(xiàn)類的繼承。
class Parent {
constructor(name) {
this.name = name;
}
sayHello() {
console.log('Hello');
}
}
class Child extends Parent {
constructor(name) {
super(name);
}
}
const child = new Child('Child');
console.log(child.name); // Child
child.sayHello(); // Hello
class Parent {
constructor(name) {
this.name = name;
}
sayHello() {
console.log('Hello');
}
}
class Child extends Parent {
constructor(name) {
super(name);
}
}
const child = new Child('Child');
console.log(child.name); // Child
child.sayHello(); // Hello
在這個(gè)例子中,我們定義了一個(gè)Parent類,通過(guò)extends關(guān)鍵字實(shí)現(xiàn)子類Child對(duì)父類Parent的繼承。子類使用super關(guān)鍵字調(diào)用父類的構(gòu)造函數(shù),并可以訪問(wèn)父類的屬性和方法。ES6類繼承提供了更加語(yǔ)法簡(jiǎn)潔和面向?qū)ο蟮睦^承方式。
以上是JavaScript中常見(jiàn)的八種繼承方式,每種方式都有其特點(diǎn)和適用場(chǎng)景。根據(jù)具體需求,你可以選擇適合的繼承方式來(lái)構(gòu)建對(duì)象之間的關(guān)系。
總結(jié)
到此這篇關(guān)于JS中常見(jiàn)的8種繼承方法的文章就介紹到這了,更多相關(guān)JS繼承方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于three.js實(shí)現(xiàn)簡(jiǎn)易照片墻效果
這篇文章主要為大家詳細(xì)介紹了基于three.js實(shí)現(xiàn)簡(jiǎn)易照片墻效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
深入解析Javascript閉包的功能及實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)解析Javascript閉包的功能及實(shí)現(xiàn)方法,感興趣的小伙伴們可以參考一下2016-07-07
IE與Firefox在JavaScript上的7個(gè)不同寫(xiě)法小結(jié)
盡管那需要用長(zhǎng)串的、沉悶的不同分支代碼來(lái)應(yīng)付不同瀏覽器的日子已經(jīng)過(guò)去,偶爾還是有必要做一些簡(jiǎn)單的區(qū)分和目標(biāo)檢測(cè)來(lái)確保某塊代碼能在用戶的機(jī)器上正常運(yùn)行。2009-09-09
關(guān)于layui toolbar和template的結(jié)合使用方法
今天小編就為大家分享一篇關(guān)于layui toolbar和template的結(jié)合使用方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
JS實(shí)現(xiàn)網(wǎng)頁(yè)上隨機(jī)產(chǎn)生超鏈接地址的方法
這篇文章主要介紹了JS實(shí)現(xiàn)網(wǎng)頁(yè)上隨機(jī)產(chǎn)生超鏈接地址的方法,涉及JavaScript隨機(jī)數(shù)的相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
JS實(shí)現(xiàn)計(jì)算小于非負(fù)數(shù)n的素?cái)?shù)的數(shù)量算法示例
這篇文章主要介紹了JS實(shí)現(xiàn)計(jì)算小于非負(fù)數(shù)n的素?cái)?shù)的數(shù)量算法,可實(shí)現(xiàn)針對(duì)一定范圍內(nèi)素?cái)?shù)個(gè)數(shù)的統(tǒng)計(jì)功能,涉及javascript數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2019-02-02
JS利用時(shí)間戳倒計(jì)時(shí)的實(shí)現(xiàn)示例
這篇文章主要介紹了JS利用時(shí)間戳倒計(jì)時(shí)的實(shí)現(xiàn)示例,本文將提供代碼示例和詳細(xì)的步驟,幫助你實(shí)現(xiàn)一個(gè)簡(jiǎn)單而實(shí)用的時(shí)間戳倒計(jì)時(shí),感興趣的可以了解一下2023-12-12

