この記事では、例を通じて Javascript プロトタイプ チェーンの原理を分析します。参考のために皆さんと共有してください。詳細は次のとおりです:
1. JavaScript プロトタイプ チェーン
ECMAScript はプロトタイプ チェーンの概念を記述し、継承を実装するための主なメソッドとしてプロトタイプ チェーンを使用します。基本的な考え方は、プロトタイプを使用して、ある参照型が別の参照型のプロパティとメソッドを継承できるようにすることです。 JavaScript では、オブジェクトのプロトタイプ チェーンを表すために __proto__ 属性が使用されます。オブジェクトのプロパティを検索するとき、JavaScript は指定された名前のプロパティが見つかるまでプロトタイプ チェーンをたどります。
たとえば、次のコードがあります:
オブジェクト クラスを拡張し、Clone メソッドと Extend メソッドを追加します
/*扩展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; }
人物クラスを定義します
/*定义一个Person类*/ function Person(_name,_age){ this.name = _name; this.age = _age; }
JavaScript では、Object クラスはすべてのクラスの親クラスであるため、Person クラスは Object クラスを継承し、新しく追加された Clone と Extend を含む、Object クラスのすべてのパブリック プロパティとパブリック メソッドを継承します。 Object クラス
のメソッド次のコードを使用すると、Person クラスが実際に Object クラスを継承していることを証明できます
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("");
実行結果:
次に、Person クラスは Shenma メソッドを通じて Object クラスを継承します。これは、プロトタイプ (prototye) メソッドを使用して継承されます。
/*定义一个Person类*/ function Person(_name,_age){ this.name = _name; this.age = _age; } Person.prototype = new Object();//让Person类继承Object类
person.prototype = new Object();//Person クラスに Object クラスを継承させます 」と書かなくても、これは、JavaScript エンジンだと思います。また、この文も自動的に追加されます。または、「person.prototype = Object.prototype;」を使用して、Person クラスに Object クラスを継承させます。 "person.prototype = new Object();"、実際、これは Object オブジェクトが Person のプロトタイプであることと同等であり、Object オブジェクトのプロパティとメソッドを Person にコピーすることと同等です。 。
2. 新しい演算子の仕組み
まず、このコード部分を見てみましょう:
1.var p={}; オブジェクト p を初期化します。
2. p.__proto__=person.prototype;、オブジェクト p の __proto__ 属性を Person.prototype に設定します
3.person.call(p,"lonewolf",24); コンストラクター person を呼び出して p を初期化します。
鍵は 2 番目のステップにあります。それを証明しましょう:
var p = new Person("孤傲苍狼",24);//创建一个人,名字是孤傲苍狼 alert("p.__proto__ === Person.prototype的结果是:"+(p.__proto__ === Person.prototype));
このコードは true を返します。ステップ 2 が正しいことを説明します。
注: __proto__ 属性は Firefox または Chrome ブラウザーでのみ公開されているため、IE カーネルに基づく他のブラウザーは true を返しません。
それで、__proto__ とは何ですか?ここで簡単にお話しましょう。各オブジェクトはその内部の属性 (__proto__) を初期化します。オブジェクトの属性にアクセスするとき、この属性がオブジェクト内に存在しない場合、オブジェクトは __proto__ にアクセスして属性を見つけます。この __proto__ は独自の属性を持ちます。 __proto__ なので、それを探し続けます。これが、通常、プロトタイプ チェーンの概念と呼ばれるものです。標準によれば、__proto__ は公開されていません。つまり、IE では __proto__ 属性にアクセスできませんが、Firefox エンジンはそれを公開し、アクセスできるようにします。そして外部から設定します。
さて、概念は明確です。次のコードを見てみましょう:
<script type="text/javascript"> var Person = function () { }; Person.prototype.Say = function () { alert("Person say"); } var p = new Person(); p.Say(); </script>
まずは
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程序设计有所帮助。