JavaScript六種繼承方式總結(jié)大全
1. 原型鏈繼承
是什么?
這是最基礎(chǔ)的繼承方式。其核心是:讓一個(gè)構(gòu)造函數(shù)的 prototype 對(duì)象指向另一個(gè)構(gòu)造函數(shù)的實(shí)例。這樣,子類(lèi)就能通過(guò)原型鏈訪問(wèn)到父類(lèi)的屬性和方法。
javascript
// 父類(lèi)
function Parent() {
this.name = 'Parent';
this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
// 子類(lèi)
function Child() {
this.type = 'Child';
}
// 關(guān)鍵!將Child的原型指向Parent的實(shí)例,建立原型鏈
Child.prototype = new Parent();
var child1 = new Child();
child1.sayName(); // 'Parent' (來(lái)自原型鏈)
console.log(child1.colors); // ['red', 'blue'] (來(lái)自原型鏈)
var child2 = new Child();
child1.colors.push('green'); // 修改child1的colors
console.log(child2.colors); // ['red', 'blue', 'green'] (問(wèn)題出現(xiàn)了!)有什么作用?
實(shí)現(xiàn)屬性和方法的繼承。
實(shí)際開(kāi)發(fā)運(yùn)用場(chǎng)景?
在現(xiàn)代前端開(kāi)發(fā)中,幾乎不會(huì)單獨(dú)使用原型鏈繼承,因?yàn)樗兄旅毕?。但它是一切其他繼承方式的理論基礎(chǔ)。
優(yōu)點(diǎn):
簡(jiǎn)單易懂,是理解JS繼承的基礎(chǔ)。
能夠繼承父類(lèi)原型上的方法。
缺點(diǎn):
引用類(lèi)型屬性被所有實(shí)例共享(如上例中的
colors數(shù)組)。一個(gè)實(shí)例修改了引用類(lèi)型屬性,所有實(shí)例都會(huì)受到影響。這是最大的問(wèn)題。創(chuàng)建子類(lèi)實(shí)例時(shí),無(wú)法向父類(lèi)構(gòu)造函數(shù)傳參(因?yàn)?nbsp;
new Parent()在初始化原型時(shí)就執(zhí)行了)。
2. 借用構(gòu)造函數(shù)繼承(經(jīng)典繼承)
是什么?
為了解決原型鏈繼承的缺點(diǎn),這種方法的核心是:在子類(lèi)構(gòu)造函數(shù)的內(nèi)部調(diào)用父類(lèi)構(gòu)造函數(shù)。這利用了 call() 或 apply() 方法,使父類(lèi)的 this 指向子類(lèi)的實(shí)例。
javascript
// 父類(lèi)
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
// 注意:父類(lèi)原型上的方法子類(lèi)訪問(wèn)不到
Parent.prototype.sayName = function() {
console.log(this.name);
};
// 子類(lèi)
function Child(name, type) {
// 關(guān)鍵!“借用”父類(lèi)的構(gòu)造函數(shù)來(lái)初始化屬性
Parent.call(this, name); // 相當(dāng)于執(zhí)行了 this.name = name; this.colors = ['red', 'blue'];
this.type = type;
}
var child1 = new Child('小明', 'Child');
var child2 = new Child('小紅', 'Child');
child1.colors.push('green');
console.log(child1.colors); // ['red', 'blue', 'green']
console.log(child2.colors); // ['red', 'blue'] (互不影響了!)
console.log(child1.sayName); // undefined (無(wú)法繼承父類(lèi)原型的方法)有什么作用?
解決原型鏈繼承中“引用屬性共享”和“無(wú)法傳參”的問(wèn)題。
實(shí)際開(kāi)發(fā)運(yùn)用場(chǎng)景?
通常不會(huì)單獨(dú)使用,但它是組合繼承的重要組成部分。
優(yōu)點(diǎn):
避免了引用屬性共享的問(wèn)題。
可以在子類(lèi)中向父類(lèi)傳遞參數(shù)。
缺點(diǎn):
方法都在構(gòu)造函數(shù)中定義,每次創(chuàng)建實(shí)例都會(huì)創(chuàng)建一遍方法,無(wú)法實(shí)現(xiàn)函數(shù)復(fù)用,效率低。
無(wú)法繼承父類(lèi)原型(prototype)上的方法(如上例中的
sayName)。
3. 組合繼承
是什么?
組合繼承結(jié)合了原型鏈繼承和借用構(gòu)造函數(shù)繼承的優(yōu)點(diǎn),是 JavaScript 中最常用的繼承模式。其核心是:
使用借用構(gòu)造函數(shù)來(lái)繼承屬性(解決共享和傳參問(wèn)題)。
使用原型鏈來(lái)繼承方法(實(shí)現(xiàn)方法復(fù)用)。
javascript
// 父類(lèi)
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
// 子類(lèi)
function Child(name, type) {
// 1. 繼承屬性
Parent.call(this, name); // 第二次調(diào)用 Parent()
this.type = type;
}
// 2. 繼承方法
Child.prototype = new Parent(); // 第一次調(diào)用 Parent()
// 修復(fù)構(gòu)造函數(shù)指向,否則Child實(shí)例的constructor會(huì)指向Parent
Child.prototype.constructor = Child;
// 子類(lèi)自己的方法
Child.prototype.sayType = function() {
console.log(this.type);
};
var child1 = new Child('小明', 'Child1');
child1.colors.push('green');
console.log(child1.colors); // ['red', 'blue', 'green']
child1.sayName(); // '小明'
child1.sayType(); // 'Child1'
var child2 = new Child('小紅', 'Child2');
console.log(child2.colors); // ['red', 'blue'] (屬性不共享)
child2.sayName(); // '小紅' (方法可復(fù)用)有什么作用?
綜合了兩種模式的優(yōu)點(diǎn),成為 JavaScript 中一種非常實(shí)用的繼承模式。
實(shí)際開(kāi)發(fā)運(yùn)用場(chǎng)景?
在 ES6 的 class 出現(xiàn)之前,這是最主流、最可靠的繼承方式。常用于構(gòu)建復(fù)雜的對(duì)象系統(tǒng),如UI組件庫(kù)、游戲引擎中的實(shí)體繼承等。
優(yōu)點(diǎn):
實(shí)例擁有獨(dú)立的屬性,不會(huì)共享。
實(shí)例可以復(fù)用父類(lèi)原型上的方法。
可以向父類(lèi)構(gòu)造函數(shù)傳參。
缺點(diǎn):
最大的缺點(diǎn):會(huì)兩次調(diào)用父類(lèi)構(gòu)造函數(shù)。
一次在
Parent.call(this)。一次在
new Parent()。
這導(dǎo)致子類(lèi)實(shí)例和原型上存在兩份相同的屬性(一份在實(shí)例自身,一份在__proto__里),造成了一些不必要的浪費(fèi)(雖然實(shí)例自身的屬性會(huì)屏蔽原型上的屬性,沒(méi)有功能問(wèn)題)。
4. 原型式繼承
是什么?
道格拉斯·克羅克福德提出的方法。其核心是:創(chuàng)建一個(gè)臨時(shí)的構(gòu)造函數(shù),將其原型指向某個(gè)對(duì)象,然后返回這個(gè)臨時(shí)構(gòu)造函數(shù)的實(shí)例。本質(zhì)上是對(duì)傳入的對(duì)象進(jìn)行了一次淺復(fù)制。
javascript
// object() 就是 ES5 中 Object.create() 的模擬實(shí)現(xiàn)
function object(o) {
function F() {} // 創(chuàng)建一個(gè)臨時(shí)構(gòu)造函數(shù)
F.prototype = o; // 將其原型指向傳入的對(duì)象o
return new F(); // 返回這個(gè)臨時(shí)構(gòu)造函數(shù)的實(shí)例
}
var person = {
name: 'Nicholas',
friends: ['Shelby', 'Court']
};
var person1 = object(person);
person1.name = 'Greg';
person1.friends.push('Rob');
var person2 = object(person);
person2.name = 'Linda';
person2.friends.push('Barbie');
console.log(person.friends); // ['Shelby', 'Court', 'Rob', 'Barbie'] (共享問(wèn)題依然存在)有什么作用?
在不必興師動(dòng)眾地創(chuàng)建構(gòu)造函數(shù)的情況下,基于一個(gè)已有對(duì)象創(chuàng)建新對(duì)象。
實(shí)際開(kāi)發(fā)運(yùn)用場(chǎng)景?
適用于簡(jiǎn)單對(duì)象的淺拷貝繼承。
ES5 的
Object.create()方法規(guī)范化了原型式繼承?,F(xiàn)在直接使用Object.create()即可。
優(yōu)點(diǎn):
無(wú)需創(chuàng)建構(gòu)造函數(shù),代碼簡(jiǎn)潔。
缺點(diǎn):
和原型鏈繼承一樣,存在引用屬性共享的問(wèn)題。
5. 寄生式繼承
是什么?
寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類(lèi)似。其核心是:創(chuàng)建一個(gè)僅用于封裝繼承過(guò)程的函數(shù),該函數(shù)在內(nèi)部以某種方式(如原型式繼承)增強(qiáng)對(duì)象,最后返回這個(gè)對(duì)象。
javascript
function createAnother(original) {
var clone = object(original); // 1. 通過(guò)調(diào)用函數(shù)(如object)創(chuàng)建一個(gè)新對(duì)象(原型式繼承)
clone.sayHi = function() { // 2. 以某種方式來(lái)增強(qiáng)這個(gè)對(duì)象
console.log('hi');
};
return clone; // 3. 返回這個(gè)對(duì)象
}
var person = {
name: 'Nicholas',
friends: ['Shelby', 'Court']
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); // 'hi'有什么作用?
主要關(guān)注對(duì)象而不是自定義類(lèi)型和構(gòu)造函數(shù),在主要考慮對(duì)象而非自定義類(lèi)型和構(gòu)造函數(shù)的情況下,實(shí)現(xiàn)簡(jiǎn)單的繼承和擴(kuò)展。
實(shí)際開(kāi)發(fā)運(yùn)用場(chǎng)景?
適用于為對(duì)象添加一些額外功能的場(chǎng)景,但不廣泛使用。
優(yōu)點(diǎn):
可以在不創(chuàng)建構(gòu)造函數(shù)的情況下,為對(duì)象添加函數(shù)。
缺點(diǎn):
函數(shù)難以復(fù)用,效率低(跟借用構(gòu)造函數(shù)模式一樣)。
存在引用屬性共享的問(wèn)題(跟原型式繼承一樣)。
6. 寄生組合式繼承
是什么?
這是組合繼承的優(yōu)化版本,也是目前公認(rèn)的最理想的繼承范式。它解決了組合繼承調(diào)用兩次父類(lèi)構(gòu)造函數(shù)的問(wèn)題。
其核心是:
使用借用構(gòu)造函數(shù)來(lái)繼承屬性。
使用寄生式繼承來(lái)繼承父類(lèi)原型,并將其賦值給子類(lèi)原型。
javascript
function inheritPrototype(child, parent) {
// 1. 創(chuàng)建父類(lèi)原型的一個(gè)副本(原型式繼承)
var prototype = Object.create(parent.prototype);
// 2. 修復(fù)副本的constructor指針
prototype.constructor = child;
// 3. 將子類(lèi)的原型指向這個(gè)副本
child.prototype = prototype;
}
// 父類(lèi)
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
// 子類(lèi)
function Child(name, type) {
// 只調(diào)用一次父類(lèi)構(gòu)造函數(shù)(繼承屬性)
Parent.call(this, name);
this.type = type;
}
// 關(guān)鍵!替換掉組合繼承中的 `Child.prototype = new Parent()`
inheritPrototype(Child, Parent);
// 添加子類(lèi)自己的方法
Child.prototype.sayType = function() {
console.log(this.type);
};
var child1 = new Child('小明', 'Child1');
// 實(shí)例的 __proto__ 指向 Child.prototype
// Child.prototype 的 __proto__ 指向 Parent.prototype
// 完美!有什么作用?
只調(diào)用一次父類(lèi)構(gòu)造函數(shù),并且避免了在子類(lèi)原型上創(chuàng)建不必要的、多余的屬性。同時(shí),原型鏈還能保持不變。
寄生組合式繼承核心目標(biāo):修復(fù)“組合繼承”的缺陷
要理解“寄生組合”,我們必須先回顧“組合繼承”的問(wèn)題。
組合繼承的做法:
Parent.call(this):在子類(lèi)構(gòu)造函數(shù)里調(diào)用父類(lèi)構(gòu)造函數(shù)。這會(huì)在子類(lèi)實(shí)例自身上創(chuàng)建一份父類(lèi)的屬性。Child.prototype = new Parent():將子類(lèi)的原型指向一個(gè)父類(lèi)的實(shí)例。這會(huì)在子類(lèi)的原型對(duì)象上創(chuàng)建第二份父類(lèi)的屬性。
這就導(dǎo)致了:
子類(lèi)實(shí)例上有
name和colors屬性。子類(lèi)實(shí)例的
__proto__(也就是Child.prototype)上也有name和colors屬性。
雖然實(shí)例自身的屬性會(huì)屏蔽掉原型上的同名屬性,功能上沒(méi)問(wèn)題,但多創(chuàng)建了一份多余的屬性,造成了內(nèi)存浪費(fèi)和不優(yōu)雅。
寄生組合式繼承的解決方案
它的核心思路非常巧妙:我們真的需要那個(gè) new Parent() 實(shí)例來(lái)充當(dāng)原型嗎?不,我們只需要父類(lèi)原型上的方法。
我們不需要 Parent 實(shí)例上的屬性(因?yàn)槲覀円呀?jīng)通過(guò) Parent.call(this) 在子類(lèi)實(shí)例上得到了一份),我們只需要能通過(guò)原型鏈找到 Parent.prototype 上的方法。
所以,新的方案是:
繼承屬性:保持不變,依然在子類(lèi)構(gòu)造函數(shù)里用
Parent.call(this)在子類(lèi)構(gòu)造函數(shù)里調(diào)用父類(lèi)構(gòu)造函數(shù),這會(huì)在子類(lèi)實(shí)例自身上創(chuàng)建一份父類(lèi)的屬性。這保證了每個(gè)實(shí)例都有自己獨(dú)立的屬性。繼承方法:不再用
new Parent(),而是直接創(chuàng)建一個(gè)純凈的、指向父類(lèi)原型的對(duì)象,用它來(lái)作為子類(lèi)的原型。
這個(gè)“純凈的、指向父類(lèi)原型的對(duì)象”就是 Object.create(Parent.prototype) 所做的事情。
一步步拆解(超級(jí)詳細(xì)版)
讓我們把 inheritPrototype(Child, Parent) 這個(gè)函數(shù)里的三步拆開(kāi)來(lái)看:
javascript
function inheritPrototype(child, parent) {
// 第一步:創(chuàng)建原型副本(核心)
var prototype = Object.create(parent.prototype);
// 第二步:修復(fù)constructor指向
prototype.constructor = child;
// 第三步:將子類(lèi)的原型指向這個(gè)新創(chuàng)建的對(duì)象
child.prototype = prototype;
}第一步:var prototype = Object.create(parent.prototype);
Object.create()方法會(huì)創(chuàng)建一個(gè)新對(duì)象。這個(gè)新對(duì)象的
__proto__會(huì)指向你傳入的參數(shù),也就是parent.prototype。想象一下:這就好比我們憑空造了一個(gè)空對(duì)象
{},并且讓這個(gè)空對(duì)象“認(rèn)”Parent.prototype為它的爸爸(原型)。這個(gè)空對(duì)象自己沒(méi)有任何屬性(解決了屬性重復(fù)的問(wèn)題),但它可以順著原型鏈找到 Parent.prototype 上的所有方法(sayName)。
第二步:prototype.constructor = child;
任何一個(gè)
prototype對(duì)象都有一個(gè)constructor屬性,默認(rèn)指向它關(guān)聯(lián)的構(gòu)造函數(shù)。因?yàn)槲覀冇?nbsp;
Object.create()創(chuàng)建的新對(duì)象,它的constructor指向的是parent(因?yàn)樗^承自parent.prototype,而parent.prototype.constructor指向parent)。這顯然不對(duì),我們希望子類(lèi)原型的 constructor 指向子類(lèi)自己 child。
所以我們需要手動(dòng)糾正一下,讓
prototype.constructor = child;。
第三步:child.prototype = prototype;
最后,我們把這個(gè)我們精心制作好的、純凈的、鏈接到了父類(lèi)原型的、constructor指正確的
prototype對(duì)象,賦值給子類(lèi)的prototype。從此,所有
new Child()出來(lái)的實(shí)例,它們的__proto__都指向我們這個(gè)prototype對(duì)象,從而可以順利地通過(guò)原型鏈調(diào)用父類(lèi)的方法。
終極比喻:“繼承家產(chǎn)”的故事
父類(lèi) (
Parent):一個(gè)富豪老爹,他有金庫(kù)(實(shí)例屬性name,colors)和一本生意經(jīng)(原型方法sayName)。組合繼承:老爹先給你復(fù)制了一本完整的生意經(jīng)(包括金庫(kù)的地圖),然后你又自己去金庫(kù)里拿了一次金子。你手里有金子,書(shū)上也有金子的地圖,地圖是多余的。
寄生組合繼承:一個(gè)聰明的律師(
Object.create)出現(xiàn)了。他沒(méi)有復(fù)制整本生意經(jīng),而是只做了一張神奇的索引卡。這張索引卡本身是空白的(沒(méi)有多余的屬性),但它直接指向了老爹那本生意經(jīng)的原始內(nèi)容(Parent.prototype)。然后你又自己去金庫(kù)里拿了一次金子。你手里有金子,也通過(guò)索引卡學(xué)會(huì)了老爹的生意經(jīng),完美!
總結(jié):為什么它是最佳的?
| 特性 | 組合繼承 | 寄生組合繼承 | 優(yōu)勢(shì) |
|---|---|---|---|
| 父類(lèi)屬性副本 | 2份 (實(shí)例上1份,原型上1份) | 1份 (僅在實(shí)例上) | 更高效,無(wú)浪費(fèi) |
| 父類(lèi)方法繼承 | 通過(guò)原型鏈繼承 | 通過(guò)原型鏈繼承 | 同樣有效 |
| 父類(lèi)構(gòu)造函數(shù)調(diào)用 | 2次 | 1次 | 性能更優(yōu) |
| 原型鏈 | 保持正確 | 保持正確 | 同樣正確 |
所以,寄生組合式繼承的核心貢獻(xiàn)就是:
它用一種極其巧妙的方式(Object.create)建立了子類(lèi)和父類(lèi)原型的直接聯(lián)系,完全跳過(guò)了創(chuàng)建父類(lèi)實(shí)例這個(gè)不必要的步驟,從而避免了創(chuàng)建多余的屬性,完美地實(shí)現(xiàn)了繼承。這也是為什么ES6的 class 和 extends 語(yǔ)法糖其底層實(shí)現(xiàn)原理是寄生組合繼承的原因,因?yàn)樗_實(shí)是理論上最完美的方案
實(shí)際開(kāi)發(fā)運(yùn)用場(chǎng)景?
這是實(shí)現(xiàn)基于構(gòu)造函數(shù)的繼承的最佳模式。在需要高度優(yōu)化和避免不必要的內(nèi)存開(kāi)銷(xiāo)的庫(kù)或框架中可能會(huì)看到。但在日常開(kāi)發(fā)中,我們更傾向于使用 ES6 的 class 和 extends,其底層原理就是寄生組合式繼承。
優(yōu)點(diǎn):
只調(diào)用一次父類(lèi)構(gòu)造函數(shù),效率高。
避免了在子類(lèi)原型上創(chuàng)建不必要的屬性。
原型鏈保持不變,能正常使用
instanceof和isPrototypeOf。
缺點(diǎn):
實(shí)現(xiàn)起來(lái)相對(duì)復(fù)雜。但通常可以封裝成一個(gè)函數(shù)(如上面的
inheritPrototype)來(lái)復(fù)用。
總結(jié)與建議
| 繼承方式 | 核心思想 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場(chǎng)景 |
|---|---|---|---|---|
| 原型鏈繼承 | 子類(lèi)原型 = 父類(lèi)實(shí)例 | 簡(jiǎn)單,方法可復(fù)用 | 引用共享,無(wú)法傳參 | 基礎(chǔ)學(xué)習(xí),幾乎不用 |
| 借用構(gòu)造函數(shù) | 在子類(lèi)中 Parent.call(this) | 屬性獨(dú)立,可傳參 | 方法不能復(fù)用 | 組合繼承的一部分 |
| 組合繼承 | 借用構(gòu)造 + 原型鏈 | 屬性獨(dú)立,方法可復(fù)用,可傳參 | 調(diào)用兩次父類(lèi)構(gòu)造函數(shù) | ES6前的主流方式 |
| 原型式繼承 | Object.create() | 無(wú)需構(gòu)造函數(shù),簡(jiǎn)單 | 引用共享 | 對(duì)象淺拷貝 |
| 寄生式繼承 | 工廠模式+增強(qiáng)對(duì)象 | 無(wú)需構(gòu)造函數(shù),可增強(qiáng)對(duì)象 | 方法不能復(fù)用,引用共享 | 為對(duì)象添加功能 |
| 寄生組合繼承 | 借用構(gòu)造 + 寄生式繼承父類(lèi)原型 | 近乎完美,只調(diào)用一次父類(lèi)構(gòu)造函數(shù) | 實(shí)現(xiàn)稍復(fù)雜 | 理想的繼承范式 |
現(xiàn)代開(kāi)發(fā)建議:
直接使用 ES6 的 class 和 extends 關(guān)鍵字。它們的語(yǔ)法更清晰、更易于理解,并且其底層實(shí)現(xiàn)的就是寄生組合式繼承這種最理想的方式。你不再需要手動(dòng)處理原型鏈,避免了出錯(cuò)的可能。
javascript
// ES6 的寫(xiě)法,底層是寄生組合式繼承
class Parent {
constructor(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
sayName() {
console.log(this.name);
}
}
class Child extends Parent {
constructor(name, type) {
super(name); // 相當(dāng)于 Parent.call(this, name)
this.type = type;
}
sayType() {
console.log(this.type);
}
}到此這篇關(guān)于JavaScript六種繼承方式的文章就介紹到這了,更多相關(guān)JS六種繼承方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js parseInt("08")未指定進(jìn)位制問(wèn)題
今天在做JS關(guān)于月份的判斷,對(duì)于parseInt("01")到parseInt("07");都能得到正確的結(jié)果,但如果是parseInt("08")或parseInt("09")則返回0,首先看parseInt語(yǔ)法:parseInt(string, radix);2010-06-06
Bootstrap 響應(yīng)式實(shí)用工具實(shí)例詳解
Bootstrap 提供了一些輔助類(lèi),以便更快地實(shí)現(xiàn)對(duì)移動(dòng)設(shè)備友好的開(kāi)發(fā)。這些可以通過(guò)媒體查詢(xún)結(jié)合大型、小型和中型設(shè)備,實(shí)現(xiàn)內(nèi)容對(duì)設(shè)備的顯示和隱藏。下面通過(guò)本文給大家分享Bootstrap 響應(yīng)式實(shí)用工具,一起看看吧2017-03-03
如何寫(xiě)出一個(gè)驚艷面試官的JavaScript深拷貝
淺拷貝是面試中經(jīng)常會(huì)被問(wèn)到的問(wèn)題,這篇文章主要給大家介紹了關(guān)于如何寫(xiě)出一個(gè)驚艷面試官的JavaScript深拷貝的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05
將input框中輸入內(nèi)容顯示在相應(yīng)的div中【三種方法可選】
本篇文章主要介紹了在input框中輸入內(nèi)容,會(huì)相應(yīng)的顯示在下面的div中的不同做法:js方法;jQuery方法;AngularJs方法,具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-05-05

