ホームページ > ウェブフロントエンド > jsチュートリアル > JSでのプロトタイプチェーンの詳細説明

JSでのプロトタイプチェーンの詳細説明

小云云
リリース: 2018-03-22 17:19:08
オリジナル
1798 人が閲覧しました


JS はオブジェクト指向言語ではありませんが、これは JS が OOP 機能を実装できないという意味ではありません。 JSを使うとき、call、apply、hasOwnPropertyなどのObjectのプロトタイプメソッドを使ったことがあると思いますが、これらのメソッドはどこから来たのでしょうか? JS が継承を実装できない場合、これらのメソッドは使用できません。ここではJSでの継承、プロトタイプチェーンの実装方法についてお話します。

_proto_ とプロトタイプ

まず、通常のオブジェクトとは何か、関数オブジェクトとは何かを理解する必要があります。

  • 通常のオブジェクト

    • var a = {}

    • var a = new Object();

    • var a = new f1();//前の作成方法と同じオブジェクト

  • function object

    • var a = function(){};

    • var a = new Function(){};

    • f1()

    と同じ

_proto _ は、すべての通常のオブジェクトが所有する属性であり、コンストラクターのプロトタイプ (コンストラクターのプロトタイプ オブジェクト) を指すために使用されます。コンストラクターのプロトタイプオブジェクトは一般的には通常のオブジェクト(コンストラクターがFunctionの場合は関数オブジェクトになります)なので、_proto_属性も持ちます。そして、その _proto_ は、そのコンストラクターのプロトタイプ オブジェクト (Object.prototype) を指します。最後の Object.prototype._proto_ は null を指し、プロトタイプ チェーンの先頭に達します。
プロトタイプは、関数オブジェクトが所有する属性で、オブジェクトの作成時に新しいオブジェクト インスタンスに割り当てられます。もちろん、動的に変更することもできます。

   function Person(){};   var p = new Person();//创建一个普通对象
   //创建过程实际为
   var p={};
   p._proto_=Person.prototype;
   Person.apply(p,arguments);//或者是call...
   //执行构造函数,并返回创建的对象。
ログイン後にコピー

上記コードの補足説明

通常、コンストラクタ内にreturn文を記述する必要はありません。デフォルトで新しく作成されたオブジェクトが返されるためです。ただし、コンストラクターに return ステートメントが記述されている場合、戻り値がオブジェクトの場合、関数は新しく作成されたオブジェクトを上書きし、戻り値が文字列、数値、ブール値などの基本型の場合はこのオブジェクトを返します。などの場合、関数は return ステートメントを無視するか、新しく作成されたオブジェクトを返します。

コンストラクターのプロトタイプ オブジェクトのデフォルト値は次のとおりです:

  Person.prototype={
    constructor://指向构造函数本身
    _proto_://指向构造函数Person的原型对象的构造函数的原型对象,这里是指Object.prototype
  }
  //这里有一个特殊情况——当构造函数为Function的时候
  Function.prototype._proto_===Object.prototype 
  //我们知道Function.prototype是一个函数对象,它的_proto_应该指向它的构造函数的原型,也就是Function.prototype。
  //可是这样下去就没完没了了,毕竟一条链总是有顶端的。这里约定Function.prototype._proto_===Object.prototype;  //这时,Object.prototype._proto_===null;完美结束原型链。
ログイン後にコピー

最終的にチェーンを形成できるように、コンストラクターのプロトタイプ オブジェクトのポインティングを継続的に変更できます。上記のチェーンは、JS のデフォルトのプロトタイプ チェーンです。

コードの実装について話しましょう

コードを見てみましょう:

  function Parent(name){
        this.name=name||"parent";
    }    function Son(name){
        this.name=name||"son";        this.property="initial Son name";
    }    function Grandson(name){
        this.name=name||"grandson";        this.ggs="initial Grandson name";
    }

    Son.prototype = new Parent("原型中的Parent");
    Grandson.prototype = new Son("原型中的Son");    let grandson = new Grandson("孙子");
    console.log(grandson instanceof Son);//true
    console.log(grandson instanceof Grandson);//true
    console.log(grandson instanceof Parent);//true
ログイン後にコピー

JSでのプロトタイプチェーンの詳細説明
明らかに、最後には true が出力されます。しかし、コードを少し変更してみましょう:

    Grandson.prototype = new Son("原型中的Son");
    Son.prototype = new Parent("原型中的Parent");//其实上一步已经实例化了一个Son的对象给Grandson.prototype
    //这个时候Son的实例的_proto_已经确定指向那个时候的构造函数.prototype了(默认原型对象)
    let grandson = new Grandson("孙子");
    console.log(grandson instanceof Son);//false
    console.log(grandson instanceof Grandson);//true
    console.log(grandson instanceof Parent);//false
ログイン後にコピー

JSでのプロトタイプチェーンの詳細説明
なぜ結果が変わるのでしょうか?理由もとても簡単です。オブジェクト作成の作成プロセスの前に説明しました。オブジェクトがインスタンス化されると、コンストラクターのプロトタイプがオブジェクトの _proto_ に割り当てられます。つまり、上記コードの1行目でGrandson.prototype._proto_の値が決まっていますが、2行目でSon.prototypeを変更してもGrandson.prototype._proto_の値は変更できません。

結論: JS のプロトタイプチェーンの関係は、prototype ではなく _proto_ によって維持されます。

簡単なテスト

var animal = function(){}; var dog = function(){};

 animal.price = 2000;
 dog.prototype = animal; var tidy = new dog();
 console.log(dog.price) 
 console.log(tidy.price)
ログイン後にコピー

答えは何ですか?未定義で 2000 です。分析しましょう:
まず、animal と Dog は両方とも関数オブジェクトであることがわかります。4 行目で、dog のプロトタイプ オブジェクトがanimal に変更されます。次に、下を見てみましょう。 console.log(dog.price) この文では、まず犬の価格を探しますが、何もありません。次に、プロトタイプ チェーンでそれを探します。どうやって分かったの?コンストラクターのプロトタイプ オブジェクトにアクセスするために _proto_ を使用すると前述しましたが、dog は関数オブジェクトなので、そのコンストラクターのプロトタイプ オブジェクトは空の関数である Function.prototype です。そのため、unknown が返され、price 属性が見つかりません。 console.log(dog.price) 这一句首先会寻找dog的price,没有。然后去原型链上寻找。怎么找的呢?我们之前提到是通过_proto_去到它构造函数的原型对象上,这里因为dog是函数对象,那么它的构造函数的原型对象就是Function.prototype,这是一个empty function。于是返回undefined,没有找到price这个属性。
那么console.log(tidy.price) 呢?
tidy是一个普通对象,首先也是寻找它本身的属性price,也没有。通过_proto_去到它构造函数的原型对象上,也就是dog.prototype。因为tidy实例化在dog.prototype = animal;console.log(tidy.price) はどうですか?

Tidy は通常のオブジェクトです。まず、独自の属性価格を探しますが、ありません。 _proto_ を介してコンストラクターのプロトタイプ オブジェクト (dog.prototype) に移動します。 Tidy は dog.prototype = Animal; の後にインスタンス化されるため、tidy._proto_ のポイントはすでに変更された Dog.prototype を指しています。つまり動物を指しており、つまり価格属性が分かるので2000が出力されます。

プロトタイプ オブジェクトのすべてのプロパティとメソッドは、Java の親クラスのパブリック (保護された) プロパティとメソッドと見なすことができ、これらのメソッド内でこれを使用して、コンストラクターのプロパティとメソッドにアクセスできます。その理由については、JS での this のバインディングの問題について言及する必要があります。つまり、関数を呼び出す人が誰であっても、this はそれを指すことになります。アロー関数を除く...

関連する推奨事項:

JSプロトタイプとプロトタイプチェーンの詳細な説明(1)

🎜

JSプロトタイプとプロトタイプチェーンの詳細説明(2)

JSプロトタイプとプロトタイプチェーンの詳細説明(3)

以上がJSでのプロトタイプチェーンの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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