Selepas membaca banyak perkara tentang warisan js, tiba masanya untuk meringkaskan.
Izinkan saya memberi pemahaman umum kepada anda, saya harap anda boleh membetulkan saya jika saya salah, supaya saya dapat membetulkan tiga pandangan saya. Di samping itu, contoh berikut bukan asal, ia hanya ditukar nama pembolehubah, malah ada yang digunakan secara langsung.
Apakah warisan js digunakan untuk:
Pertama sekali, js tidak mempunyai konsep warisan yang sama seperti bahasa berorientasikan objek lain Warisan yang disebut dalam js merujuk kepada warisan simulasi.
Apakah sebenarnya yang dilakukan oleh warisan js? Apabila saya mula bekerja di bahagian hadapan, saya menggunakannya untuk temu duga (saya pada asasnya tidak menggunakannya apabila saya mula-mula menulis beberapa kesan kecil. Mengapa saya perlu membacanya? Kerana penemuduga suka untuk bertanya soalan ini), jadi saya hanya menggunakannya untuk temu duga Lihat secara kasar, dan jika anda boleh memberikan garis kasar semasa temu duga, anda dianggap sebagai penemuduga yang baik mengenai isu ini. Kemudian, saya mula menggunakannya secara beransur-ansur walaupun konsepnya tidak begitu jelas.
Untuk apa ia sebenarnya digunakan? Ia digunakan terutamanya untuk menggunakan semula kod yang telah kami tulis sebelum ini. Sebagai contoh, jika kita telah menulis fungsi, objek, atau menggunakan sesuatu yang ditulis oleh orang lain, dan kita ingin menambah sesuatu sendiri, kita tidak boleh mengubah barang orang lain Kita hanya boleh mewarisinya dan menggunakannya kegunaan sebenar harta pusaka.
Cara melaksanakan warisan js:
Saya tidak akan pergi ke kod dahulu, mari bercakap tentang pemikiran saya dahulu. Sebenarnya, pewarisan adalah untuk mencari cara untuk memindahkan sifat atau kaedah objek lain (semuanya dalam js adalah objek) ke objek kita sendiri, supaya objek kita sendiri boleh digunakan. Ini juga mencapai tujuan penggunaan semula.
Sekarang tujuannya jelas, berikut adalah cara untuk mencapainya.
Mengikut ciri-ciri js, pelaksanaan tidak lebih daripada satu atau gabungan kaedah berikut.
1. Pembina, js nampaknya tidak mempunyai definisi pembina yang ketat, tetapi anda boleh menggunakan baharu untuk mencipta objek baharu. Dikatakan bahawa pembina juga merupakan kaedah untuk melaksanakan warisan dalam bahasa berorientasikan objek yang ketat, jadi sudah tentu js boleh mensimulasikannya, jadi orang yang telah mempelajari bahasa oop akan memikirkan perkara ini terlebih dahulu.
2. Gunakan prototaip fungsi dan rantai prototaip untuk memautkan dua objek Kerana rantai prototaip js agak unik, mudah untuk memikirkan perkara ini.
Terdapat beberapa jenis prototaip, iaitu, apa yang digunakan sebagai prototaip objek yang diwarisi, prototaip objek yang diwarisi atau contoh objek yang diwarisi, atau pewaris langsung. Kesan pewarisan yang diperolehi oleh prototaip ini sebagai objek pewarisan adalah berbeza.
3. Salin atribut dan kaedah Hanya menyalin dan mengklon semua atribut atau kaedah objek yang diwarisi dan mengubahnya menjadi atribut dan kaedah objek kita sendiri. Sudah tentu, ini boleh dibahagikan kepada dua situasi: penyalinan cetek dan penyalinan mendalam.
4. Gunakan kedua-dua kaedah panggil dan gunakan kedua-dua kaedah ini agak ajaib dan boleh mengubah konteks pelaksanaan fungsi (ini, menggunakan kedua-dua kaedah ini juga boleh merealisasikan pewarisan dan penggunaan semula kaedah yang diwarisi). objek.
Secara umumnya, cara untuk mencapai warisan dalam js mungkin ini Kaedah pelaksanaan yang sentiasa berubah semuanya digabungkan dan dinaik taraf berdasarkan kaedah ini. Sudah tentu, ia adalah kerana kesan penggunaan satu kaedah. Sudah tentu, anda boleh memilih kaedah mana yang hendak digunakan berdasarkan keperluan sebenar projek anda, asalkan ia memenuhi keperluan anda sendiri dan tidak menyatakan kaedah mana yang mesti digunakan untuk mencapainya. Sama seperti mengatakan bahawa cara terpantas untuk pergi dari Beijing ke Shijiazhuang adalah dengan kapal terbang. Tetapi jika jauh dari lapangan terbang, termasuk ke lapangan terbang dan pergi dari lapangan terbang ke bandar, ia tidak sepantas kereta api berkelajuan tinggi secara keseluruhan, maka anda boleh menaiki kereta api berkelajuan tinggi. Sebagai contoh, jika anda mempunyai kereta dan boleh memandu, tetapi jika anda mahukan cabaran, anda boleh menunggang basikal Anda boleh memilih ini berdasarkan situasi sebenar anda.
Pelaksanaan kod, mari kita bercakap tentang kaedah pelaksanaan di atas berdasarkan kod sebahagian daripadanya diambil dari tempat lain dan menambah beberapa ulasan.
Selepas membaca banyak perkara tentang warisan js, tiba masanya untuk meringkaskan.
Izinkan saya memberi pemahaman umum kepada anda, saya harap anda boleh membetulkan saya jika saya salah, supaya saya dapat membetulkan tiga pandangan saya. Di samping itu, contoh berikut bukan asal, ia hanya ditukar nama pembolehubah, malah ada yang digunakan secara langsung.
Apakah warisan js digunakan untuk:
Pertama sekali, js tidak mempunyai konsep warisan yang sama seperti bahasa berorientasikan objek lain Warisan yang disebut dalam js merujuk kepada warisan simulasi.
Apakah sebenarnya yang dilakukan oleh warisan js? Apabila saya mula bekerja di bahagian hadapan, saya menggunakannya untuk temu duga (saya pada asasnya tidak menggunakannya apabila saya mula-mula menulis beberapa kesan kecil. Mengapa saya perlu membacanya? Kerana penemuduga suka untuk bertanya soalan ini), jadi saya hanya menggunakannya untuk temu duga Lihat secara kasar, dan jika anda boleh memberikan garis kasar semasa temu duga, anda dianggap sebagai penemuduga yang baik mengenai isu ini. Kemudian, saya mula menggunakannya secara beransur-ansur walaupun konsepnya tidak begitu jelas.
Untuk apa ia sebenarnya digunakan? Ia digunakan terutamanya untuk menggunakan semula kod yang telah kami tulis sebelum ini. Sebagai contoh, jika kita telah menulis fungsi, objek, atau menggunakan sesuatu yang ditulis oleh orang lain, dan kita ingin menambah sesuatu sendiri, kita tidak boleh mengubah barang orang lain Kita hanya boleh mewarisinya dan menggunakannya kegunaan sebenar harta pusaka.
Cara melaksanakan warisan js:
Mari kita tidak bercakap tentang kod dahulu, mari bercakap tentang idea dahulu. Sebenarnya, pewarisan adalah untuk mencari cara untuk memindahkan sifat atau kaedah objek lain (semuanya dalam js adalah objek) ke objek kita sendiri, supaya objek kita sendiri boleh digunakan. Ini juga mencapai tujuan penggunaan semula.
Sekarang tujuannya jelas, berikut adalah cara untuk mencapainya.
Mengikut ciri-ciri js, pelaksanaan tidak lebih daripada satu atau gabungan kaedah berikut.
1. Pembina, js nampaknya tidak mempunyai definisi pembina yang ketat, tetapi anda boleh menggunakan baharu untuk mencipta objek baharu. Dikatakan bahawa pembina juga merupakan kaedah untuk melaksanakan warisan dalam bahasa berorientasikan objek yang ketat, jadi sudah tentu js boleh mensimulasikannya, jadi orang yang telah mempelajari bahasa oop akan memikirkan perkara ini terlebih dahulu.
2. Gunakan prototaip fungsi dan rantai prototaip untuk memautkan dua objek Kerana rantai prototaip js agak unik, mudah untuk memikirkan perkara ini.
Terdapat beberapa jenis prototaip, iaitu, apa yang digunakan sebagai prototaip objek yang diwarisi, prototaip objek yang diwarisi atau contoh objek yang diwarisi, atau pewaris langsung. Kesan pewarisan yang diperolehi oleh prototaip ini sebagai objek pewarisan adalah berbeza.
3. Salin atribut dan kaedah Hanya menyalin dan mengklon semua atribut atau kaedah objek yang diwarisi dan mengubahnya menjadi atribut dan kaedah objek kita sendiri. Sudah tentu, ini boleh dibahagikan kepada dua situasi: penyalinan cetek dan penyalinan mendalam.
4. Gunakan kedua-dua kaedah panggil dan gunakan kedua-dua kaedah ini agak ajaib dan boleh mengubah konteks pelaksanaan fungsi (ini, menggunakan kedua-dua kaedah ini juga boleh merealisasikan pewarisan dan penggunaan semula kaedah yang diwarisi). objek.
Secara umumnya, cara untuk mencapai warisan dalam js mungkin ini Kaedah pelaksanaan yang sentiasa berubah semuanya digabungkan dan dinaik taraf berdasarkan kaedah ini. Sudah tentu, ia adalah kerana kesan penggunaan satu kaedah. Sudah tentu, anda boleh memilih kaedah mana yang hendak digunakan berdasarkan keperluan sebenar projek anda, asalkan ia memenuhi keperluan anda sendiri dan tidak menyatakan kaedah mana yang mesti digunakan untuk mencapainya. Sama seperti mengatakan bahawa cara terpantas untuk pergi dari Beijing ke Shijiazhuang adalah dengan kapal terbang. Tetapi jika jauh dari lapangan terbang, termasuk ke lapangan terbang dan pergi dari lapangan terbang ke bandar, ia tidak sepantas kereta api berkelajuan tinggi secara keseluruhan, maka anda boleh menaiki kereta api berkelajuan tinggi. Sebagai contoh, jika anda mempunyai kereta dan boleh memandu, tetapi jika anda mahukan cabaran, anda boleh menunggang basikal Anda boleh memilih ini berdasarkan situasi sebenar anda.
Pelaksanaan kod, mari kita bercakap tentang kaedah pelaksanaan di atas berdasarkan kod sebahagian daripadanya diambil dari tempat lain dan menambah beberapa ulasan.
1. Pelaksanaan Pembina (pembina pinjaman):
function Super(arg){ this.arr1 = "I'm super "+arg; this.show = function(){ alert(this.arr1); } } Super.prototype.say = function(){ alert(this.arr1); } function suber(arg){ Super.apply(this, arguments); //在suber的上下文中运行super } var sub =new suber("suber"); var sub2 = new suber("suber1"); console.log(sub.arr1); //I'm super suber console.log(sub.show); //function (){ alert(this.arr1);} console.log(sub.say); //undefined console.log(sub.show === sub2.show); //false
Op, saya mendapati bahawa sub.say tidak ditentukan, yang bermaksud ia belum diwarisi Pertunjukan kedua-dua objek sub dan sub2 di bawah adalah tidak sama, yang bermaksud bahawa kedua-dua fungsi menghala ke dua objek berbeza, yang bermaksud. mereka disalin dua salinan keluar.
Jadi jika kaedah ini melaksanakan pewarisan, sifat dan kaedah pada objek prototaip tidak akan diwarisi Sifat dan kaedah pada Super akan disalin secara berasingan untuk setiap objek baharu.
Oleh itu, adalah tidak wajar menggunakan kaedah ini sahaja untuk melaksanakan pewarisan, kerana tiada satu pun kaedah pada prototaip telah diwarisi. Jadi tuan-tuan datang dengan idea warisan prototaip
2. Warisan prototaip:
function Super(arg){ this.arr1 = "I'm super "+arg; this.show = function(){ alert(this.arr1); } } Super.prototype.say = function(){ alert(this.arr1); } function suber(arg){} suber.prototype = new Super(); var sub = new suber("suber1"); var sub2 = new suber("suber2"); console.log(sub.arr1); //I'm super undefined console.log(sub.show); //function (){ alert(this.arr1);} console.log(sub.say); //function (){ alert(this.arr1);} console.log(sub.show === sub2.show); //true; console.log(sub.say === sub2.say); //true;
Kali ini arr1 diwarisi, tetapi parameter tidak ditambah dan tidak ditentukan Oleh itu, apabila subkelas kaedah ini diisytiharkan, parameter diluluskan dan sifat yang diwarisi daripada subkelas tidak dapat diterima. Semua yang lain agak normal. Tunjukkan dan katakan kedua-duanya diwarisi. Tetapi satu perkara yang perlu diambil perhatian ialah say diwarisi melalui objek prototaip super, dan show ialah atribut contoh apabila mencipta tika objek super baharu.
Jadi bagaimana untuk melaksanakan penghantaran parameter dan mewarisi barangan dalam prototaip Sudah tentu, hanya menggabungkan dua kaedah di atas, jadi orang tua mencipta kaedah berikut
3. Warisan gabungan (pinjam pembina dan set prototaip):
function Super(arg){ this.arr1 = "I'm super "+arg; this.show = function(){ alert(this.arr1); } } Super.prototype.say = function(){ alert(this.arr1); } function suber(arg){ Super.apply(this, arguments); } suber.prototype = new Super(); var sub = new suber("suber1"); var sub2 = new suber("suber2"); console.log(sub.arr1); //I'm super suber1 console.log(sub.show); //function (){ alert(this.arr1);} console.log(sub.say); //function (){ alert(this.arr1);} console.log(sub.show === sub2.show); //false; console.log(sub.say === sub2.say); //true;
Kali ini ia hampir sempurna, tetapi anda boleh mendapati bahawa sub.show dan sub2.show adalah tidak sama. Mengapakah ini kerana tempat memohon menjadikan show menjadi atribut suber sendiri, kemudian masukkannya ke dalam prototaip suber Pertunjukan (Pertunjukan Super digunakan sebagai objek contoh objek prototaip suber) ditimpa, jadi ia disalin satu demi satu Sudah tentu, tiada cara untuk mengelakkan ini. Untuk tidak menanggung overhed yang tidak perlu ini, lebih banyak fungsi boleh kongsi ini boleh diletakkan dalam objek prototaip.
Oleh kerana panggilan dalam pembinaan suber dan panggilan apabila memberikan nilai kepada objek prototaip suber menyebabkan Super dipanggil dua kali, maka Super dipanggil dua kali setiap kali objek suber baharu dicipta, dan dua objek contoh akan dijana apabila dipanggil dua kali. Lebihan sumber perlu digunakan.
Jadi warga emas membuka minda mereka untuk menyelesaikan masalah ini dan membangunkan kaedah berikut.
4. Warisan gabungan parasit:
Perbezaan utama antara kaedah ini dan kaedah 3 ialah prototaip kelas induk diperuntukkan kepada prototaip kelas anak dan bukannya contoh kelas induk Lihat contoh
function Super(arg){ this.arr1 = "I'm super "+arg; } Super.prototype.show = function(){ //这个方法放到了原型对象上。 alert(this.arr1); } Super.prototype.say = function(){ alert(this.arr1); } function suber(arg){ Super.apply(this, arguments); } /*inherit函数的作用,使用一个新的空函数,来切断父类对象的原型对象与子类原型对象的直接联系,而是通过这个空构造的实例对象实现继承,这样可以避免更改子类原型的属性或者方法而影响了父类原型对象的属性或者方法。*/ function inherit(obj){ function F(){} F.prototype = obj; return new F(); } suber.prototype = inherit(Super.prototype); var sub = new suber("suber1"); var sub2 = new suber("suber2"); console.log(sub.arr1); //I'm super suber1 console.log(sub.show); //function (){ alert(this.arr1);} console.log(sub.say); //function (){ alert(this.arr1);} console.log(sub.show === sub2.show); //true; console.log(sub.say === sub2.say); //true;
好了,这样就把三方法的弊端干掉了,这个可以完美的使用了吧。
五、复制属性实现
拷贝我们可以写一个拷贝函数来实现。
function extend(Super,suber){ suber = suber || {}; for(var i in Super){ if(Super.hasOwnProperty(i)){ suber[i] = Super[i]; } } return suber; } var parent = { name:"dad", num:[1,2,3], say:function(){alert("dad");} } var child = { age:5, sex:"boy" }; child = extend(parent, child); //以下测试 console.log(child); /*{ age:5, sex:"boy", name:"dad", num:[1,2,3], say:function(){alert("dad");} }*/ console.log(child.say === parent.say); //true console.log(child.num === parent.num); //true
复制成功,那么child成功继承了parent的一些属性,但是后面两个测试发现他们是相等的,就表明了他们在公用同一个数组,同一个函数,函数这个可以,但是数组这个就有问题了,如果一个chiild改变了数组,几个被继承对象的数组也跟着变了,这就不给力了啊。
为什么会发生这种情况呢,js里边对象存储的是指针,然后这个指针指向这个值,我们在这复制的实际是指向该对象的指针的值,所以继承对象和被继承对象都指向了同一个对象,接下来看看如何使用深度复制来解决这个问题。
深度复制对象属性:
function extenddeep(Super, suber){ var tostr = Object.prototype.toString, astr = "[object Array]"; suber = suber || {}; for(var i in Super){ if(Super.hasOwnProperty(i)){ if(typeof Super[i] === "object"){ suber[i] = (tostr.call(Super[i]) == astr) ? [] : {}; extenddeep(Super[i],suber[i]); }else { suber[i] = Super[i]; } } } return suber; } var parent = { name:"papa", num:[1,2,3], say:function(){alert("I'm father of my son!");} } var child = { name:"jone", sex:"boy", } var kid = extenddeep(parent, child); console.log(kid); // {name: "papa" num: Array[3] say: () sex: "boy" // } console.log(kid.say === parent.say); //true console.log(kid.num === parent.num); //false console.log(kid.name); //papa
好了,深度复制完毕,但似有木有发现问题,name是parent的,也就是说如果继承对象有和被继承对象一样的属性名的属性如果不做处理就会被替换掉。那么我们可以做一下处理,先声明一个属性,保存parent里的东西,剩下的的当然就是child自己的东西了,最后再把属性给child对象就可以了。
六、利用call和apply这两个方法(借用方法)。
这个就是通过call和apply来复用其他对象的方法,达到复用的目的。
var one = { name:"object", say: function(greet){ return greet + ', ' + this.name; } } var tow = { name:"two" } one.say.call(tow, "hi"); //hi, two
这个就是借用了,好了,下课。
好吧,好吧,其实这里边还有其他东西要看。可以借用并不“带表”可以随便把某个方法赋值给谁然后跟没发生什么似的继续用。所以我们平时使用借用时要注意一下上下文,下面看下那些容易出错的地方。
//赋值给一个变量时候上下文会变化 var say = one.say; console.log(say('hoho')); // "hoho, undefined" //作为回调函数时也会发生变化 var yetother = { name:"yetother obj", method:function(callback){ return callback("Hola"); } } console.log(yetother.method(one.say)); //"Hola, "
神马意思呢,就是this.name是undefined,当one.say赋值给say是,实际上是say存储了指向函数对象的指针,say这个变量明显又是全局变量的一个属性,那么它运行的时候实际的上下文就变成了windows了,当然这个时候name就变成undefined了。回调这个也是一样,return 的是函数运行的结果。如果我们事先设置 windows.name="windows" 那么得到的结果就变成了 "hoho, windows" 和"Hola, windows" 了。
function bind(o, m){ return function(){ return m.apply(o, [].slice.call(arguments)); } } var othersay = bind(yetother, one.say); othersay("Hola"); //"Hola, yetother obj"
通过apply可以改变方法执行的上下文,那么我们构建一个函数来实现这样一个功能,通过使用方法调用实现上下文的改变,这样就不会出现上下文不是我们期望的上下文的情况了。
//这段是直接复制过来的。 // ECMAScript 5给Function.prototype添加了一个bind()方法,以便很容易使用apply()和call()。 if (typeof Function.prototype.bind === 'undefined') { Function.prototype.bind = function (thisArg) { var fn = this, slice = Array.prototype.slice, args = slice.call(arguments, 1); return function () { return fn.apply(thisArg, args.concat(slice.call(arguments))); }; }; } var twosay2 = one.say.bind(two); console.log(twosay2('Bonjour')); // "Bonjour, another object" var twosay3 = one.say.bind(two, 'Enchanté'); console.log(twosay3()); // "Enchanté, another object"
介绍完了,该说说自己的疑惑了,当复制属性方法遇到的被继承对象里边存在方法,如何单独复制出来呢,现在的是直接共用了,因为毕竟方法一般不会经常改动。求解答?
下面是转载过来的jQuery的extend方法,好像也没有特殊处理函数这块,继承完了两个函数也是共用的。
$.extend源码
jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false ; // Handle a deep copy situation //如果第一个参数是boolean类型 //修正参数,将第二个参数作为target if ( typeof target === "boolean" ) { deep = target; // skip the boolean and the target target = arguments[ i ] || {}; //i++是为了后续 i === length的判断 i++; } // Handle case when target is a string or something (possible in deep copy) //如果目标既不是对象也不是方法(例如给基本类型扩展属性方法和属性不会报错但是是无用的),修正target为 js对象 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed //如果只有一个参数,修正对象为JQuery函数或JQuery对象 if ( i === length ) { target = this ; //修正target所在位置,后面的都是要添加给target的对象 i--; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop //如果target和copy是同一个对象,略过,防止自己的属性引用了本身对象导致的循环引用,以致GC无法回收 if ( target === copy ) { continue ; } // Recurse if we're merging plain objects or arrays //如果是deep为true,并且要添加给target的copy为对象获数组 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false ; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them //很巧妙 ,用一个递归,实现引用对象的深克隆,递归的返回条件是属性石基本类型,基本类型都是深克隆 target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { //浅克隆 target[ name ] = copy; } } } } // Return the modified object return target; };
以上这篇javascript 继承学习心得总结就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。