Artikel ini menganalisis prinsip rantaian prototaip Javascript melalui contoh. Kongsikan dengan semua orang untuk rujukan anda, butirannya adalah seperti berikut:
1. Rantaian prototaip JavaScript
ECMAScript menerangkan konsep rantaian prototaip dan menggunakan rantaian prototaip sebagai kaedah utama untuk melaksanakan pewarisan. Idea asas ialah menggunakan prototaip untuk membenarkan satu jenis rujukan mewarisi sifat dan kaedah jenis rujukan yang lain. Dalam JavaScript, atribut __proto__ digunakan untuk mewakili rantai prototaip objek. Apabila mencari sifat objek, JavaScript berjalan ke atas rantaian prototaip sehingga ia menemui sifat dengan nama tertentu!
Sebagai contoh, kami kini mempunyai kod berikut:
Melanjutkan kelas Objek dan menambah kaedah Klon dan Lanjutkan
/*扩展Object类,添加Clone,JS实现克隆的方法*/ Object.prototype.Clone = function(){ var objClone; if (this.constructor == Object){ objClone = new this.constructor(); }else{ objClone = new this.constructor(this.valueOf()); } for(var key in this){ if ( objClone[key] != this[key] ){ if ( typeof(this[key]) == 'object' ){ objClone[key] = this[key].Clone(); }else{ objClone[key] = this[key]; } } } objClone.toString = this.toString; objClone.valueOf = this.valueOf; return objClone; } /*扩展Object类,添加Extend方法来实现JS继承, 目标对象将拥有源对象的所有属性和方法*/ Object.prototype.Extend = function (objDestination, objSource) { for (var key in objSource) { if (objSource.hasOwnProperty(key) && objDestination[key] === undefined) { objDestination[key] = objSource[key]; } } return objDestination; }
Tentukan kelas Orang
/*定义一个Person类*/ function Person(_name,_age){ this.name = _name; this.age = _age; }
Dalam JavaScript, kelas Object ialah kelas induk bagi semua kelas, jadi kelas Person mewarisi daripada kelas Object dan mewarisi semua sifat awam dan kaedah awam kelas Object, termasuk Clone dan Extend yang baru ditambah kaedah kelas Objek
Anda boleh menggunakan kod berikut untuk membuktikan bahawa kelas Orang memang mewarisi kelas Objek
document.write("<pre class="brush:php;toolbar:false">"); var p = new Person("孤傲苍狼",24);//创建一个人,名字是孤傲苍狼 var cloneP = p.Clone();//p调用在Object类中定义的Clone方法来克隆自己,如果能得到一个cloneP,那就证明了Person类确实是继承了Object类,所以就拥有了Clone document.writeln("p是使用Person类以构造函数的方式创建出来的对象,p.name = "+p.name+",p.age = "+p.age); document.writeln("cloneP是p调用Clone方法克隆出来的对象,cloneP.name = "+cloneP.name+",cloneP.age = "+cloneP.age); document.writeln("cloneP对象和p对象是两个相互独立的对象,这两个对象的内存地址肯定是不相等,p == cloneP的结果是:"+(p == cloneP)); cloneP.name="白虎神皇";//修改cloneP的名字 document.writeln("cloneP的name被修改了,cloneP.name = "+cloneP.name); document.writeln("cloneP的name修改了,但是不影响到p,p.name = "+p.name); document.write("");
Hasil jalankan:
Kemudian kelas Orang mewarisi kelas Objek melalui kaedah Shenma Ia diwarisi menggunakan kaedah prototaip (prototye):
/*定义一个Person类*/ function Person(_name,_age){ this.name = _name; this.age = _age; } Person.prototype = new Object();//让Person类继承Object类
Memandangkan JavaScript menetapkan bahawa mana-mana kelas mewarisi daripada kelas Objek, jadi "Person.prototype = new Object();//Let the Person class mewarisi kelas Object " Walaupun kita tidak menulis ia, saya rasa enjin JavaScript Ia juga akan menambah ayat ini secara automatik untuk kita, atau gunakan "Person.prototype = Object.prototype;" untuk membenarkan kelas Person mewarisi kelas Objek. "Person.prototype = new Object();", sebenarnya, ini bersamaan dengan objek Object sebagai prototaip Orang, yang bersamaan dengan menyalin sifat dan kaedah objek Objek kepada Orang .
2. Cara pengendali baharu berfungsi
Mari kita lihat sekeping kod ini dahulu:
Sekeping kod yang sangat mudah, mari kita lihat apa yang baru ini lakukan? Kita boleh membahagikan proses baharu kepada tiga langkah berikut:
1.var p={};
2. p.__proto__=Person.prototype;, tetapkan atribut __proto__ objek p kepada Person.prototype
3.Person.call(p,"lonewolf",24);
Kuncinya terletak pada langkah kedua, mari kita buktikan:
var p = new Person("孤傲苍狼",24);//创建一个人,名字是孤傲苍狼 alert("p.__proto__ === Person.prototype的结果是:"+(p.__proto__ === Person.prototype));
Hasil berjalan di bawah Firefox ialah:
Kod ini akan kembali benar. Jelaskan bahawa langkah 2 kami adalah betul.
Nota: Atribut __proto__ hanya boleh diakses secara umum dalam pelayar Firefox atau Chrome, oleh itu, penyemak imbas lain berdasarkan kernel IE tidak akan kembali benar.
Jadi apakah itu __proto__? Mari bercakap secara ringkas di sini. Setiap objek akan memulakan atribut di dalamnya, iaitu __proto__ Apabila kita mengakses atribut objek, jika atribut ini tidak wujud di dalam objek, maka dia akan pergi ke __proto__ untuk mencari atribut, __proto__ ini akan mempunyai sendiri. __proto__, jadi saya terus mencarinya, yang biasanya kita panggil konsep rantaian prototaip.
Menurut piawaian, __proto__ tidak terbuka kepada umum, yang bermaksud ia adalah atribut peribadi. Atribut __proto__ tidak boleh diakses di bawah IE, tetapi enjin Firefox mendedahkannya dan menjadikannya sebagai atribut awam dan ditetapkan secara luaran.
Baiklah, konsepnya jelas, mari kita lihat kod berikut:
<script type="text/javascript"> var Person = function () { }; Person.prototype.Say = function () { alert("Person say"); } var p = new Person(); p.Say(); </script>
Kod ini sangat mudah. Mari lihat sebab p boleh mengakses Kata Orang.
Pertama sekali
Boleh disimpulkan bahawa
Jadi apabila kita memanggil p.Say(), pertama sekali, tiada atribut Say dalam p, jadi dia perlu mencarinya dalam __proto__nya, iaitu Person.prototype, dan kami mentakrifkannya di atas
Person.prototype.Say=function(){ alert("Person say"); };
于是,就找到了这个方法。
接下来,让我们看个更复杂的。
<script type="text/javascript"> var Person = function () { }; Person.prototype.Say = function () { alert("Person say"); } Person.prototype.Salary = 50000; var Programmer = function () { }; Programmer.prototype = new Person();//让程序员类从人这个类继承 Programmer.prototype.WriteCode = function () { alert("programmer writes code"); }; Programmer.prototype.Salary = 500; var p = new Programmer(); p.Say(); p.WriteCode(); alert(p.Salary); </script>
我们来做这样的推导:
可以得出
而在上面我们指定了
我们来这样拆分,
var p1=new Person(); Programmer.prototype=p1;
那么:
p1.__proto__=Person.prototype; Programmer.prototype.__proto__=Person.prototype;
由根据上面得到
可以得到:
好,算清楚了之后我们来看上面的结果,p.Say()。由于p没有Say这个属性,于是去 p.__proto__,也就是Programmer.prototype,也就是p1中去找,由于p1中也没有Say,那就去 p.__proto__.__proto__,也就是Person.prototype中去找,于是就找到了Say方法。这也就是原型链的实现原理。
以下代码展示了JS引擎如何查找属性:
function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop]; else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop);//递归 else return undefined; }
范例:查找p对象的Say方法
<script type="text/javascript"> /*查找obj对象的prop属性*/ function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop]; else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop);//递归 else return undefined; } var Person = function () { };//定义Person类 Person.prototype.Say = function () { alert("Person say"); } Person.prototype.Salary = 50000; var Programmer = function () { };//定义Programmer类 //Programmer.prototype = new Person();//让程序员类从人这个类继承,写法一 Programmer.prototype = Person.prototype;//让程序员类从人这个类继承,写法二 Programmer.prototype.WriteCode = function () { alert("programmer writes code"); }; Programmer.prototype.Salary = 500; var p = new Programmer(); var SayFn = getProperty(p,"Say");//查找p对象的Say方法 SayFn.call(p);//调用找到的Say方法 </script>
在火狐下的运行结果:
其实prototype只是一个假象,他在实现原型链中只是起到了一个辅助作用,换句话说,他只是在new的时候有着一定的价值,而原型链的本质,其实在于__proto__。
希望本文所述对大家JavaScript程序设计有所帮助。