欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          十分鐘帶你了解JavaScript的繼承

          本篇文章給大家?guī)砹薐avaScript中繼承的相關(guān)知識(shí),其中包括了原型鏈繼承、借用構(gòu)造函數(shù)繼承、組合繼承和多重繼承,希望對(duì)大家有幫助。

          十分鐘帶你了解JavaScript的繼承

          原型鏈繼承

          原理

          本質(zhì)是重寫原型對(duì)象,代之以一個(gè)新類型的實(shí)例。下面代碼中,原來存在于SuperType的實(shí)例對(duì)象的屬性和方法,現(xiàn)在也存在于SubType.prototype中了。

          實(shí)現(xiàn)

          function Super(){     this.value = true; } Super.prototype.getValue = function(){     return this.value } function Sub(){}; // Sub繼承了Super Sub.prototype = new Super(); Sub.prototype.constructor = Sub; const ins = new Sub(); console.log(ins.getValue()); // true

          Sub繼承了Super,而繼承是通過創(chuàng)建Super實(shí)例,并將實(shí)例賦給Sub.prototype實(shí)現(xiàn)的。原來存在于Super的實(shí)例中的所有屬性和方法,現(xiàn)在也存在與Sub.prototype中。如圖所示。

          十分鐘帶你了解JavaScript的繼承

          上圖可以看出,沒有使用Sub默認(rèn)提供的原型,而是給它換了一個(gè)新原型;這個(gè)新原型就是Super的實(shí)例。于是,新原型不僅具有作為一個(gè)Super的實(shí)例所擁有的屬性和方法,而且它還指向了Super的原型。最終結(jié)果就是這樣的:

          ins=>Sub的原型=>Super的原型

          getValue()方法仍然還在Sub.prototype中,但value屬性則位于Sub.prototype中。這是因?yàn)関alue是一個(gè)實(shí)例屬性,而getValue()則是一個(gè)原型方法。既然Sub.prototype現(xiàn)在是Super的實(shí)例,那么value位于該實(shí)例中。

          此外,要注意ins.constructor現(xiàn)在指向的是 Super,這是因?yàn)樵瓉?Sub.prototype 中的 constructor 被重寫了的緣故。

          缺點(diǎn)

          • 私有原型屬性會(huì)被實(shí)例共享

          • 在創(chuàng)建子類型的實(shí)例時(shí),不能向父類型的構(gòu)造函數(shù)傳遞參數(shù)

          原型鏈繼承最主要的問題:私有原型屬性會(huì)被實(shí)例共享,而這也正是為什么要在構(gòu)造函數(shù)中,而不是原型對(duì)象中定義屬性的原因。在通過原型來實(shí)現(xiàn)繼承時(shí),原型實(shí)例會(huì)變成另一個(gè)類的實(shí)例。于是,原先的實(shí)例屬性也就順理成章的變成了現(xiàn)在的原型屬性了。

          function Super(){     this.colors = ['red','green','blue']; } Super.prototype.getValue = function(){     return this.colors } function Sub(){}; //Sub繼承了Super Sub.prototype = new Super(); const ins1 = new Super(); ins1.colors.push('black'); console.log(ins1.colors);//['red','green','blue','black']; const ins2 = new Sub(); console.log(ins2.colors);//['red','green','blue','black'];

          原型鏈的第二個(gè)問題,在創(chuàng)建子類型的實(shí)例時(shí),不能向父類型的構(gòu)造函數(shù)傳遞參數(shù)。實(shí)際上,應(yīng)該說是沒有辦法在不影響所有都想實(shí)例的情況下,給父類型的構(gòu)造函數(shù)傳遞參數(shù)。再加上包含引用類型值的原型屬性會(huì)被所有實(shí)例共享的問題,在實(shí)踐中很少會(huì)單獨(dú)使用原型鏈繼承

          注意問題

          使用原型鏈繼承方法要謹(jǐn)慎地定義方法,子類型有時(shí)候需要重寫父類的某個(gè)方法,或者需要添加父類中不存在的某個(gè)方法。但不管怎樣,給原型添加方法的代碼一定要放在替換原型的語句之后。

          function Super() {     this.colors = ['red', 'green', 'blue']; } Super.prototype.getValue = function() {     return this.colors } function Sub() {     this.colors = ['black']; }; //Sub繼承了Super Sub.prototype = new Super(); //添加父類已存在的方法,會(huì)重寫父類的方法 Sub.prototype.getValue = function() {     return this.colors; } //添加父類不存在的方法 Sub.prototype.getSubValue = function(){     return false; } const ins = new Sub(); //重寫父類的方法之后得到的結(jié)果 console.log(ins.getValue()); //['black'] //在子類中新定義的方法得到的結(jié)果 console.log(ins.getSubValue());//false //父類調(diào)用getValue()方法還是原來的值 console.log(new Super().getValue());//['red', 'green', 'blue']

          借用構(gòu)造函數(shù)繼承

          原理

          借用構(gòu)造函數(shù)(有時(shí)候也叫做偽類繼承或經(jīng)典繼承)。這種技術(shù)的基本思想相當(dāng)簡單,即在子類構(gòu)造函數(shù)的內(nèi)部調(diào)用父類構(gòu)造函數(shù)。別忘了,函數(shù)只不過是在特定環(huán)境中執(zhí)行代碼的對(duì)象,因此通過使用apply()和call()方法也可以在新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù)。

          實(shí)現(xiàn)

          function Super() {     this.colors = ['red', 'green', 'blue']; } Super.prototype.getValue = function(){     return this.colors; } function Sub(){ //繼承了Super Super.call(this);//相當(dāng)于把構(gòu)造函數(shù)Super中的this替換成了ins實(shí)例對(duì)象,這樣在Super只有定義的私有屬性會(huì)被繼承下來,原型屬性中定義的公共方法不會(huì)被繼承下來 } const ins = new Sub(); console.log(ins.colors);

          傳遞參數(shù):相對(duì)于原型鏈來講,借用構(gòu)造函數(shù)繼承有一個(gè)很大的優(yōu)勢(shì),即可以在子類構(gòu)造函數(shù)中向父類構(gòu)造函數(shù)傳遞參數(shù)

          function B(name){     this.name = name; } function A(){     //繼承了B,同時(shí)還傳遞了參數(shù)     B.call(this,'ZZ');     //實(shí)例屬性     this.age = 100; } const p = new A(); alert(p.name);//'ZZ' alert(p.age);//100

          缺點(diǎn)

          如果僅僅是借用構(gòu)造函數(shù),那么將無法避免構(gòu)造函數(shù)模式存在的問題——方法都在構(gòu)造函數(shù)中定義,因此函數(shù)復(fù)用就無從談起。而且,在父類的原型中定義的方法,對(duì)子類而言是不可見的,所以這種方式使用較少。

          組合繼承

          原理

          組合繼承,指的是將原型鏈和借用構(gòu)造函數(shù)技術(shù)組合到一起,從而發(fā)揮兩者之長的一種繼承模式。其背后的思想是使用原型鏈實(shí)現(xiàn)對(duì)原型上的公共屬性和方法的繼承,而通過借用構(gòu)造函數(shù)繼承來實(shí)現(xiàn)對(duì)父類私有屬性的繼承。這樣,即通過在父類原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能夠保證每個(gè)實(shí)例都有父類的私有屬性。

          實(shí)現(xiàn)

          function Super(name){     this.name = name;     this.colors = ['red','blue','green']; } Super.prototype.sayName = function(){     alert(this.name); } function Sub(name,age){     Super.call(this,name);     this.age = age; } // 繼承方法 Sub.prototype = new Super(); Sub.prototype.constructor = Sub; Sub.prototype.sayAge = function(){     alert(this.age); } const ins = new Sub('jarvis',18); ins.colors.push('black'); console.log(ins.colors);// ["red", "blue", "green", "black"] ins.sayName();//'jarvis' ins.sayAge();//18 const ins2 = new Sub('ershiyi',21); console.log(ins2.colors);//["red", "blue", "green"] ins2.sayName();//'ershiyi' ins2.sayAge();//21

          在上個(gè)例子中,Sub構(gòu)造函數(shù)定義了兩個(gè)屬性:name和age。Super的原型定義了一個(gè)sayName()方法。在Sub構(gòu)造函數(shù)中調(diào)用Super構(gòu)造函數(shù)時(shí)傳入了name參數(shù),緊接著又定義它自己的屬性age。然后,將Super的實(shí)例賦值給Sub的原型,然后又在該新原型上定義了方法sayAge()。這樣一來,就可以讓不同的Sub實(shí)例分別擁有自己的屬性——包括colors屬性,又可以使用相同的方法組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺陷,融合了他們的優(yōu)點(diǎn),稱為JavaScript中最常用的繼承模式。

          缺點(diǎn)

          無論在什么情況下,都會(huì)調(diào)用兩次父類的構(gòu)造函數(shù):一次是在創(chuàng)建子類原型的時(shí)候,另一次是在子類構(gòu)造函數(shù)內(nèi)部。

          寄生組合式繼承

          原理

          組合繼承是JavaScript最常用的繼承模式;不過,它也有自己的不足。組合繼承最大的問題就是無論什么情況下,都會(huì)調(diào)用兩次父類構(gòu)造函數(shù):一次是在創(chuàng)建子類原型的時(shí)候,另一次是在子類構(gòu)造函數(shù)內(nèi)部。沒錯(cuò),子類型最終會(huì)包含超類型對(duì)象的全部實(shí)例屬性,但不得不在調(diào)用子類型構(gòu)造函數(shù)時(shí)重寫這些屬性。再來看一看下面組合繼承的例子。

          實(shí)現(xiàn)

          function Super(name){     this.name = name;     this.colors = ['red','blue','green']; } Super.prototype.sayName = function(){     alert(this.name); } function Sub(name,age){     Super.call(this,name);     this.age = age; } // 繼承方法 Sub.prototype = new Super(); Sub.prototype.constructor = Sub; Sub.prototype.sayAge = function(){     alert(this.age); } const ins = new Sub('jarvis',18); ins.colors.push('black'); console.log(ins.colors);// ["red", "blue", "green", "black"] ins.sayName();//'jarvis' ins.sayAge();//18 const ins2 = new Sub('ershiyi',21); console.log(ins2.colors);//["red", "blue", "green"] ins2.sayName();//'ershiyi' ins2.sayAge();//21

          所謂寄生組合式繼承,即通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法。其背 后的基本思路是:不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),所需要的無非就是超類型原型的一個(gè)副本而已。本質(zhì)上,就是使用寄生式繼承來繼承超類型的原型,然后再將結(jié)果指定給子類型的原型。寄生組合式繼承的基本模式如下所示。

          function Super(name){     this.name = name;     this.colors = ['red','blue','green']; } Super.prototype.sayName = function(){     alert(this.name); } function Sub(name,age){     //繼承實(shí)例屬性     Super.call(this,name);     this.age = age; } // 繼承公有的方法 Sub.prototype = Object.create(Super.prototype); Sub.prototype.constructor = Sub; Sub.prototype.sayAge = function(){     alert(this.age); } const ins = new Sub('jarvis',18); ins.colors.push('black'); console.log(ins.colors);// ["red", "blue", "green", "black"] ins.sayName();//'jarvis' ins.sayAge();//18 const ins2 = new Sub('ershiyi',21); console.log(ins2.colors);//["red", "blue", "green"] ins2.sayName();//'ershiyi' ins2.sayAge();//21

          多重繼承

          JavaScript中不存在多重繼承,那也就意味著一個(gè)對(duì)象不能同時(shí)繼承多個(gè)對(duì)象,但是可以通過變通方法來實(shí)現(xiàn)。

          <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>18 多重繼承</title> </head> <body> <script type="text/javascript"> // 多重繼承:一個(gè)對(duì)象同時(shí)繼承多個(gè)對(duì)象 // Person  Parent  Me function Person(){ this.name = 'Person'; } Person.prototype.sayName = function(){ console.log(this.name); } // 定制Parent function Parent(){ this.age = 30; } Parent.prototype.sayAge = function(){ console.log(this.age); } function Me(){ // 繼承Person的屬性 Person.call(this); Parent.call(this); } // 繼承Person的方法 Me.prototype = Object.create(Person.prototype); // 不能重寫原型對(duì)象來實(shí)現(xiàn) 另一個(gè)對(duì)象的繼承 // Me.prototype = Object.create(Parent.prototype); // Object.assign(targetObj,copyObj) Object.assign(Me.prototype,Parent.prototype); // 指定構(gòu)造函數(shù) Me.prototype.constructor = Me; const me = new Me(); </script> </body> </html>

          ES5 與 ES6 繼承差異

          在 ES5 的傳統(tǒng)繼承中, this 的值會(huì)先被派生類創(chuàng)建,隨后基類構(gòu)造器才被調(diào)用。這意味著 this 一開始就是派生類的實(shí)例,之

          后才使用了基類的附加屬性對(duì)其進(jìn)行了裝飾。

          在 ES6 基于類的繼承中, this 的值會(huì)先被基類創(chuàng)建,隨后才被派生類的構(gòu)造 器所修改。結(jié)果是 this 初始就擁有作為基類的內(nèi)置對(duì)象的所有功能,并能正確接收與之關(guān)聯(lián)的所有功能。

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)