Rumah > Artikel > hujung hadapan web > Membawa anda memahami warisan JavaScript dalam sepuluh minit
Artikel ini membawa anda pengetahuan tentang pewarisan dalam JavaScript, termasuk pewarisan rantaian prototaip, pewarisan pembina yang dipinjam, pewarisan gabungan dan pewarisan berbilang saya harap ia akan membantu anda.
Warisan rantaian prototaip
Prinsip
Intipati Adalah untuk mengatasi objek prototaip dan menggantikannya dengan contoh jenis baharu. Dalam kod berikut, sifat dan kaedah yang pada asalnya wujud dalam objek contoh SuperType kini turut wujud dalam SubType.prototype.
Pelaksanaan
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 mewarisi Super, dan warisan dicapai dengan mencipta tika Super dan menugaskan tika itu kepada Sub.prototaip. Semua sifat dan kaedah yang pada asalnya wujud dalam contoh Super kini juga wujud dalam Sub.prototaip. Seperti yang ditunjukkan dalam gambar.
Seperti yang dapat dilihat daripada gambar di atas, prototaip yang disediakan oleh Sub secara lalai tidak digunakan, tetapi prototaip baharu diberikan kepadanya; daripada Super. Oleh itu, prototaip baharu bukan sahaja mempunyai sifat dan kaedah contoh Super, tetapi ia juga menunjukkan prototaip Super. Keputusan akhir adalah seperti ini:
ins=>Sub的原型=>Super的原型
kaedah getValue() masih dalam Sub.prototype, tetapi atribut value berada dalam Sub.prototype. Ini kerana nilai ialah sifat contoh dan getValue() ialah kaedah prototaip. Memandangkan Sub.prototype kini merupakan contoh Super, nilainya terletak dalam tika itu.
Selain itu, sila ambil perhatian bahawa ins.constructor kini menunjuk kepada Super Ini kerana pembina asal dalam Sub.prototype telah ditulis semula.
Kelemahan
Sifat prototaip peribadi akan dikongsi oleh contoh
Apabila mencipta tika subjenis Apabila, anda tidak boleh menghantar parameter kepada pembina jenis induk
Masalah utama dengan pewarisan rantaian prototaip: sifat prototaip persendirian akan dikongsi oleh contoh, dan inilah sebabnya anda perlu , dan bukannya sebab sifat ditakrifkan dalam objek prototaip. Apabila pewarisan dilaksanakan melalui prototaip, contoh prototaip menjadi contoh kelas lain. Oleh itu, atribut contoh asal secara semula jadi menjadi atribut prototaip semasa.
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'];
Masalah kedua dengan rantaian prototaip ialah apabila mencipta contoh subjenis, parameter tidak boleh dihantar kepada pembina jenis induk. Malah, harus dikatakan bahawa tidak ada cara untuk menghantar parameter kepada pembina jenis induk tanpa menjejaskan semua keadaan. Ditambah dengan masalah bahawa sifat prototaip yang mengandungi nilai jenis rujukan akan dikongsi oleh semua keadaan, dalam praktiknya pewarisan rantai prototaip jarang digunakan secara bersendirian
Perhatikan masalahnya
Kaedah pewarisan rantaian prototaip memerlukan definisi kaedah yang teliti Subjenis kadangkala perlu mengatasi kaedah kelas induk atau menambah kaedah yang tidak wujud dalam kelas induk. Tetapi tidak kira apa, kod yang menambah kaedah kepada prototaip mesti diletakkan selepas pernyataan yang menggantikan prototaip.
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(); //添加父类已存在的方法,会重写父类的方法 Sub.prototype.getValue = function() { return this.colors; } //添加父类不存在的方法 Sub.prototype.getSubValue = function(){ return false; } const ins = new Sub(); //重写父类的方法之后得到的结果 console.log(ins.getValue()); //['black'] //在子类中新定义的方法得到的结果 console.log(ins.getSubValue());//false //父类调用getValue()方法还是原来的值 console.log(new Super().getValue());//['red', 'green', 'blue']
Meminjam warisan pembina
Prinsip
Meminjam pembina (kadangkala Juga dipanggil pseudo -warisan kelas atau warisan klasik). Idea asas teknik ini agak mudah, iaitu memanggil pembina kelas induk di dalam pembina kelas kanak-kanak. Jangan lupa bahawa fungsi hanyalah objek yang melaksanakan kod dalam persekitaran tertentu, jadi pembina juga boleh dilaksanakan pada objek yang baru dibuat dengan menggunakan kaedah apply() dan call().
Pelaksanaan
function Super() { this.colors = ['red', 'green', 'blue']; } Super.prototype.getValue = function(){ return this.colors; } function Sub(){ //继承了Super Super.call(this);//相当于把构造函数Super中的this替换成了ins实例对象,这样在Super只有定义的私有属性会被继承下来,原型属性中定义的公共方法不会被继承下来 } const ins = new Sub(); console.log(ins.colors);
Lulus parameter: Berbanding dengan rantai prototaip, meminjam warisan pembina mempunyai kelebihan yang besar, iaitu, ia boleh digunakan dalam pembina subkelas Menghantar parameter kepada pembina kelas induk
function B(name){ this.name = name; } function A(){ //继承了B,同时还传递了参数 B.call(this,'ZZ'); //实例属性 this.age = 100; } const p = new A(); alert(p.name);//'ZZ' alert(p.age);//100
Kelemahan
Jika anda hanya meminjam pembina, anda tidak akan dapat mengelakkan masalah corak pembina - kaedah Mereka semua ditakrifkan dalam pembina, jadi penggunaan semula fungsi adalah di luar persoalan. Selain itu, kaedah yang ditakrifkan dalam prototaip kelas induk tidak dapat dilihat oleh subkelas, jadi kaedah ini jarang digunakan.
Warisan gabungan
Prinsip
Warisan gabungan merujuk kepada corak rantaian dan peminjaman prototaip Warisan di mana teknologi pembina digabungkan untuk memanfaatkan yang terbaik daripada kedua-dua dunia. Idea di sebaliknya ialah menggunakan rantai prototaip untuk mewarisi sifat dan kaedah awam pada prototaip, dan untuk mewarisi sifat peribadi kelas induk dengan meminjam warisan pembina. Dengan cara ini, penggunaan semula fungsi dicapai dengan mentakrifkan kaedah pada prototaip kelas induk, dan setiap contoh dijamin mempunyai sifat peribadi kelas induk.
Pencapaian
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
在上个例子中,Sub构造函数定义了两个属性:name和age。Super的原型定义了一个sayName()方法。在Sub构造函数中调用Super构造函数时传入了name参数,紧接着又定义它自己的属性age。然后,将Super的实例赋值给Sub的原型,然后又在该新原型上定义了方法sayAge()。这样一来,就可以让不同的Sub实例分别拥有自己的属性——包括colors属性,又可以使用相同的方法组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,称为JavaScript中最常用的继承模式。
缺点
无论在什么情况下,都会调用两次父类的构造函数:一次是在创建子类原型的时候,另一次是在子类构造函数内部。
寄生组合式继承
原理
组合继承是JavaScript最常用的继承模式;不过,它也有自己的不足。组合继承最大的问题就是无论什么情况下,都会调用两次父类构造函数:一次是在创建子类原型的时候,另一次是在子类构造函数内部。没错,子类型最终会包含超类型对象的全部实例属性,但不得不在调用子类型构造函数时重写这些属性。再来看一看下面组合继承的例子。
实现
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
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背 后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下所示。
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 = 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中不存在多重继承,那也就意味着一个对象不能同时继承多个对象,但是可以通过变通方法来实现。
<!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"> // 多重继承:一个对象同时继承多个对象 // 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); // 不能重写原型对象来实现 另一个对象的继承 // Me.prototype = Object.create(Parent.prototype); // Object.assign(targetObj,copyObj) Object.assign(Me.prototype,Parent.prototype); // 指定构造函数 Me.prototype.constructor = Me; const me = new Me(); </script> </body> </html>
ES5 与 ES6 继承差异
在 ES5 的传统继承中, this 的值会先被派生类创建,随后基类构造器才被调用。这意味着 this 一开始就是派生类的实例,之
后才使用了基类的附加属性对其进行了装饰。
在 ES6 基于类的继承中, this 的值会先被基类创建,随后才被派生类的构造 器所修改。结果是 this 初始就拥有作为基类的内置对象的所有功能,并能正确接收与之关联的所有功能。
【相关推荐:javascript学习教程】
Atas ialah kandungan terperinci Membawa anda memahami warisan JavaScript dalam sepuluh minit. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!