Saya berjanji untuk menerangkan warisan JavaScript, tetapi ia telah ditangguhkan sehingga sekarang. Tanpa berlengah lagi, mari kita terus ke intinya.
Memandangkan anda ingin memahami warisan, ini membuktikan bahawa anda sudah mempunyai pemahaman tertentu tentang JavaScript berorientasikan objek Jika anda masih tidak memahami apa-apa, anda boleh merujuk kepada "Penjelasan asas JS berorientasikan objek. mod kilang, mod pembina, mod prototaip, Mod campuran, mod prototaip dinamik 》, mari kita bincangkan tentang kaedah yang biasanya digunakan untuk melengkapkan warisan JavaScript.
Rantai prototaip
Cara paling mudah untuk melaksanakan pewarisan dalam JavaScript adalah dengan menggunakan rantaian prototaip hanya arahkan prototaip subjenis ke contoh jenis induk, iaitu, "subtype.prototype = new parent type ();". kaedah pelaksanaan adalah seperti berikut:
// 为父类型创建构造函数 function SuperType() { this.name = ['wuyuchang', 'Jack', 'Tim']; this.property = true; } // 为父类型添加方法 SuperType.prototype.getSuerperValue = function() { return this.property; } // 为子类型创建构造函数 function SubType() { this.test = ['h1', 'h2', 'h3', 'h4']; this.subproperty = false; } // 实现继承的关键步骤,子类型的原型指向父类型的实例 SubType.prototype = new SuperType(); // 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空 SubType.prototype.getSubValue = function() { return this.subproperty; } /* 以下为测试代码示例 */ var instance1 = new SubType(); instance1.name.push('wyc'); instance1.test.push('h5'); alert(instance1.getSuerperValue()); // true alert(instance1.getSubValue()); // false alert(instance1.name); // wuyuchang,Jack,Tim,wyc alert(instance1.test); // h1,h2,h3,h4,h5 var instance2 = new SubType(); alert(instance2.name); // wuyuchang,Jack,Tim,wyc alert(instance2.test); // h1,h2,h3,h4
Anda dapat melihat bahawa kod di atas ialah warisan mudah yang dilaksanakan melalui rantaian prototaip, tetapi masih terdapat beberapa masalah dalam contoh kod ujian. Saya percaya bahawa mereka yang telah membaca catatan blog saya "Penjelasan asas JS berorientasikan objek, mod kilang, mod pembina, mod prototaip, mod hibrid, mod prototaip dinamik" mesti tahu kewujudan kod rantai prototaipMasalah pertama ialah kerana prototaip subjenis adalah contoh jenis induk, iaitu atribut jenis induk yang terkandung dalam prototaip subjenis, atribut prototaip nilai jenis rujukan akan dikongsi oleh semua keadaan . Instance1.name.push('wyc'); kod di atas boleh membuktikan kewujudan masalah ini. Masalah kedua dengan rantaian prototaip ialah: Apabila mencipta contoh subjenis, parameter tidak boleh dihantar kepada pembina superjenis. Oleh itu, dalam pembangunan sebenar, kami jarang menggunakan rantai prototaip sahaja.
pinjam pembina
Untuk menyelesaikan dua masalah yang wujud dalam rantaian prototaip, pembangun mula menggunakan teknik yang dipanggil pembina yang dipinjam untuk menyelesaikan masalah yang wujud dalam rantaian prototaip. Idea pelaksanaan teknologi ini juga agak mudah Anda hanya perlu memanggil pembina jenis induk dalam pembina subjenis. Jangan lupa, fungsi hanyalah objek yang melaksanakan kod dalam persekitaran tertentu, jadi anda boleh melaksanakan pembina melalui kaedah apply() atau call(). Kodnya adalah seperti berikut:
// 为父类型创建构造函数 function SuperType(name) { this.name = name; this.color = ['pink', 'yellow']; this.property = true; this.testFun = function() { alert('http://tools.jb51.net/'); } } // 为父类型添加方法 SuperType.prototype.getSuerperValue = function() { return this.property; } // 为子类型创建构造函数 function SubType(name) { SuperType.call(this, name); this.test = ['h1', 'h2', 'h3', 'h4']; this.subproperty = false; } // 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空 SubType.prototype.getSubValue = function() { return this.subproperty; } /* 以下为测试代码示例 */ var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']); instance1.name.push('hello'); instance1.test.push('h5'); instance1.color.push('blue'); instance1.testFun(); // http://tools.jb51.net/ alert(instance1.name); // wuyuchang,Jack,Nick,hello // alert(instance1.getSuerperValue()); // error 报错 alert(instance1.test); // h1,h2,h3,h4,h5 alert(instance1.getSubValue()); // false alert(instance1.color); // pink,yellow,blue var instance2 = new SubType('wyc'); instance2.testFun(); // http://tools.jb51.net/ alert(instance2.name); // wyc // alert(instance2.getSuerperValue()); // error 报错 alert(instance2.test); // h1,h2,h3,h4 alert(instance2.getSubValue()); // false alert(instance2.color); // pink,yellow
Anda boleh melihat bahawa pembina subjenis SubType dalam kod di atas merealisasikan pewarisan atribut dengan memanggil supertype "SuperType.call(this, name);". daripada subjenis parameter jenis diluluskan, tetapi masalah baru timbul lagi. Anda boleh melihat bahawa saya menentukan kaedah dalam pembina jenis induk: testFun, dan kaedah dalam prototaip jenis induk: getSuperValue. Walau bagaimanapun, selepas membuat instantiat subjenis, ia masih tidak dapat memanggil kaedah getSuperValue yang ditakrifkan dalam prototaip jenis induk Ia hanya boleh memanggil kaedah pembina jenis induk: testFun . Ini adalah sama seperti hanya menggunakan corak pembina semasa mencipta objek, menjadikan fungsi itu tidak boleh digunakan semula. Memandangkan masalah ini, teknik meminjam pembina jarang digunakan secara bersendirian.
Warisan gabungan (pembina yang dipinjam rantai prototaip)
Seperti namanya, warisan gabungan ialah corak yang menggabungkan kelebihan menggunakan rantai prototaip dan pembina pinjaman. Pelaksanaannya juga sangat mudah. Memandangkan ia adalah gabungan, ia pastinya menggabungkan kelebihan kedua-dua pihak, iaitu kaedah pewarisan rantaian prototaip dan harta warisan pembina . Pelaksanaan kod khusus adalah seperti berikut:
// 为父类型创建构造函数 function SuperType(name) { this.name = name; this.color = ['pink', 'yellow']; this.property = true; this.testFun = function() { alert('http://tools.jb51.net/'); } } // 为父类型添加方法 SuperType.prototype.getSuerperValue = function() { return this.property; } // 为子类型创建构造函数 function SubType(name) { SuperType.call(this, name); this.test = ['h1', 'h2', 'h3', 'h4']; this.subproperty = false; } SubType.prototype = new SuperType(); // 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空 SubType.prototype.getSubValue = function() { return this.subproperty; } /* 以下为测试代码示例 */ var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']); instance1.name.push('hello'); instance1.test.push('h5'); instance1.color.push('blue'); instance1.testFun(); // http://tools.jb51.net/ alert(instance1.name); // wuyuchang,Jack,Nick,hello alert(instance1.getSuerperValue()); // true alert(instance1.test); // h1,h2,h3,h4,h5 alert(instance1.getSubValue()); // false alert(instance1.color); // pink,yellow,blue var instance2 = new SubType('wyc'); instance2.testFun(); // http://tools.jb51.net/ alert(instance2.name); // wyc alert(instance2.getSuerperValue()); // true alert(instance2.test); // h1,h2,h3,h4 alert(instance2.getSubValue()); // false alert(instance2.color); // pink,yellow
Kod di atas mewarisi sifat jenis induk melalui SuperType.call(ini, nama); dan mewarisi kaedah jenis induk melalui SubType.prototype = new SuperType();. Kod di atas dengan mudah menyelesaikan masalah yang dihadapi oleh rantai prototaip dan pembina yang dipinjam, dan telah menjadi kaedah pewarisan contoh yang paling biasa digunakan dalam JavaScript. Tetapi mod campuran bukan tanpa kekurangannya Anda dapat melihat bahawa dalam kod di atas, apabila mewarisi kaedah, sifat jenis induk sebenarnya telah diwarisi Walau bagaimanapun, jenis rujukan dikongsi pada masa ini, jadi ia dipanggil dua kali dalam pembina subjenis Pembina jenis induk mewarisi sifat jenis induk dan menimpa sifat yang diwarisi dalam prototaip Jelas sekali tidak perlu memanggil pembina dua kali, tetapi adakah ada cara untuk menyelesaikannya? Mari kita lihat dua corak berikut semasa menyelesaikan masalah ini.
Warisan prototaip
Kaedah pelaksanaan warisan prototaip adalah berbeza daripada warisan prototaip biasa tidak menggunakan pembina dalam erti kata yang ketat, sebaliknya, ia menggunakan prototaip untuk mencipta objek baharu tanpa perlu menciptanya . Kod khusus adalah seperti berikut:
function object(o) { function F() {} F.prototype = o; return new F(); }
Contoh kod:
/* 原型式继承 */ function object(o) { function F() {} F.prototype = o; return new F(); } var person = { name : 'wuyuchang', friends : ['wyc', 'Nicholas', 'Tim'] } var anotherPerson = object(person); anotherPerson.name = 'Greg'; anotherPerson.friends.push('Bob'); var anotherPerson2 = object(person); anotherPerson2.name = 'Jack'; anotherPerson2.friends.push('Rose'); alert(person.friends); // wyc,Nicholas,Tim,Bob,Rose
Warisan parasit
/* 寄生式继承 */ function createAnother(original) { var clone = object(original); clone.sayHi = function() { alert('hi'); } return clone; }
Contoh penggunaan:
/* 原型式继承 */ function object(o) { function F() {} F.prototype = o; return new F(); } /* 寄生式继承 */ function createAnother(original) { var clone = object(original); clone.sayHi = function() { alert('hi'); } return clone; } var person = { name : 'wuyuchang', friends : ['wyc', 'Nicholas', 'Rose'] } var anotherPerson = createAnother(person); anotherPerson.sayHi();
寄生组合式继承
前面说过了JavaScrip中组合模式实现继承的缺点,现在我们就来解决它的缺点,实现思路是,对于构造函数继承属性,而原型链的混成形式继承方法,即不用在继承方法的时候实例化父类型的构造函数。代码如下:
function object(o) { function F() {} F.prototype = o; return new F(); } /* 寄生组合式继承 */ function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; }
而在使用时只需要将组合模式中的“SubType.prototype = new SuperType();”这行代码替换成inheritPrototype(subType, superType);即可。寄生组合式继承的高效率体现在它只调用了一次父类型构造函数,避免了创建不必要的或多余的属性。与此同时,原型链还能保持不变,因此,还能够正常使用instanceof和isPrototypeof()。这也是目前来说最理想的继承方式了,目前也在向这种模式转型。(YUI也使用了这种模式。)
此博文参考《JavaScript高级程序设计第3版》,代码为经过改写,更具体,并加了注释使大家更易懂。如对JS继承方面有独到见解的童鞋不别吝啬,回复您的见解供大家参考!