Javascriptプロトタイプchain_javascriptスキルの原理を詳しく解説

WBOY
リリース: 2016-05-16 15:21:42
オリジナル
1411 人が閲覧しました

この記事では、例を通じて 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类

ログイン後にコピー
JavaScript では、どのクラスも Object クラスを継承することが規定されているため、「

person.prototype = new Object();//Person クラスに Object クラスを継承させます 」と書かなくても、これは、JavaScript エンジンだと思います。また、この文も自動的に追加されます。または、「person.prototype = Object.prototype;」を使用して、Person クラスに Object クラスを継承させます。 "person.prototype = new Object();"、実際、これは Object オブジェクトが Person のプロトタイプであることと同等であり、Object オブジェクトのプロパティとメソッドを Person にコピーすることと同等です。 。

2. 新しい演算子の仕組み

まず、このコード部分を見てみましょう:


コードをコピーします コードは次のとおりです:
var p = new Person("lonewolf",24);// 「Lone Ao Canglang
」という名前の人を作成します

非常に単純なコードです。この新しい機能が何をするのか見てみましょう。新しいプロセスは次の 3 つのステップに分割できます:

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));

ログイン後にコピー
Firefox で実行した結果は次のとおりです:

このコードは 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>

ログイン後にコピー
このコードは非常に簡単です。なぜ p が Person's Say にアクセスできるのかを見てみましょう。

まずは


コードをコピー コードは次のとおりです:
var p=new Person();

次のように結論付けることができます


コードをコピー コードは次のとおりです:
p.__proto__=person.prototype

したがって、p.Say() を呼び出すと、まず、p には Say 属性がないため、__proto__ (つまり Person.prototype) でそれを見つける必要があり、上で定義しました

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 p=new Programmer();

可以得出

复制代码 代码如下:
p.__proto__=Programmer.prototype;

而在上面我们指定了

复制代码 代码如下:
Programmer.prototype=new Person();

我们来这样拆分,

var p1=new Person();
Programmer.prototype=p1;

ログイン後にコピー

那么:

p1.__proto__=Person.prototype;
Programmer.prototype.__proto__=Person.prototype;

ログイン後にコピー

由根据上面得到

复制代码 代码如下:
p.__proto__=Programmer.prototype

可以得到:

复制代码 代码如下:
p.__proto__.__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程序设计有所帮助。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!