目次
はじめに
予備知識
1. コンストラクター、インスタンス
2.原型对象
3.构造函数,原型对象和实例的关系
继承
原型链
ホームページ ウェブフロントエンド jsチュートリアル jsの継承メカニズムの詳細な解釈

jsの継承メカニズムの詳細な解釈

Oct 24, 2017 am 09:16 AM
javascript 継承する

はじめに

最近 Vue を勉強していて、週末にようやく何かを書く時間ができました (また「いいね!」をもらえると思うとちょっと楽しみです!)。 JavaScript の基本では、クロージャに加えて、継承も難しいです。記事が長くなってしまったので、2回に分けて書く予定です。こちらも「Javascript Advanced Programming」をベースに詳しく解説しますので、間違っているところがあればご指摘ください。

予備知識

継承についてよりよく説明するために、最初にいくつかの予備知識を入れてみましょう。

1. コンストラクター、インスタンス

コンストラクターは、オブジェクトを作成するために使用される関数であり、本質的には関数です。他の関数との違いは、呼び出しメソッドです:

  • new 演算子を通じて呼び出された場合、それはコンストラクターです

    new操作符来调用的,就是构造函数

  • 如果没有通过new操作符来调用的,就是普通函数
    例子:

function Person(name, age) {
   this.name = name;
   this.age = age;
 }
 //当做构造函数调用
 var person1 = new Person('Mike',10);
 
 //当做普通函数调用,这里相当于给window对象添加了name和age属性,这个不是重点,只要注意调用方式
 Person('Bob',12);
 
 console.log(person1)//Person {name: "Mike", age: 10}
 console.log(name)//Bob
 console.log(age)//12
ログイン後にコピー

var person1 = new Person('Mike',10);中,通过new操作符调用了函数Person,并且生成了person1,
这里的Person就称为构造函数person1称为Person函数对象的一个实例。实例中会有一个constructor属性,指向对应的构造函数,看下面的例子:

 function Person(name, age) {
    this.name = name;
    this.age = age;
  }
 var person1 = new Person('Mike',10);
 var person2 = new Person('Alice',20);
 console.log(person1.constructor)//function Person(){省略内容...}
 console.log(person2.constructor)//function Person(){省略内容...}
ログイン後にコピー

2.原型对象

当我们每次创建一个函数的时候,函数对象都会有一个prototype属性,这个属性是一个指针,指向它的原型对象原型对象的本质也是一个对象。初次看这句话可能有点难以理解,举个例子,还是刚刚那个函数:

function Person(name, age) {
        this.name = name;
        this.age = age;
     }
     console.log(Person.prototype)//object{constructor:Person}
ログイン後にコピー

可以看到Person.prototype指向了一个对象,即Person的原型对象,并且这个对象有一个constructor属性,又指向了Person函数对象。是不是有点晕?没关系,接下来我们就上比举例子更好的手段--画图。

3.构造函数,原型对象和实例的关系

在前面,我们刚刚介绍过了构造函数,实例和原型对象,接下来我们用一张图来表示这三者之间的关系(用ps画这种图真是麻烦的要死,大家有好的工具推荐一下):
jsの継承メカニズムの詳細な解釈
从图上我们可以看到:

  • 函数对象的prototype指向原型对象,原型对象的constructor指向函数对象

  • 实例对象的[Protoptype]属性指向原型对象,这里的[Protoptype]内部属性,可以先理解为它是存在的,但是不允许我们访问(虽然在有些浏览器是允许访问这个属性的,但是我们先这样理解),这个属性的作用是:允许实例通过该属性访问原型对象中的属性和方法。比如说:

function Person(name, age) {
        this.name = name;
        this.age = age;
      }
      //在原型对象中添加属性或者方法
     Person.prototype.sex = '男'; 
     var person1 = new Person('Mike',10);
     var person2 = new Person('Alice',20);
     //只给person2设置性别
     person2.sex = '女';
     console.log(person1.sex)//'男'
     console.log(person2.sex)//'女'
ログイン後にコピー

这里我们没有给person1实例设置sex属性,但是因为[Protoptype]的存在,会访问原型对象中对应的属性;
同时我们给person2设置sex属性后输出的是'女',说明只有当实例本身不存在对应的属性或方法时,才会去找原型对象上的对应属性或方法

继承

原型链

在js中,继承的主要思路就是利用原型链,因此如果理解了原型链,继承问题就理解了一半。在这里可以稍微休息一下,如果对前面的准备知识已经理解差不多了,就开始讲原型链了。

原型链的原理是:让一个引用类型继承另一个引用类型的属性和方法。
先回顾一下刚刚讲过的知识:

  • 原型对象通过constructor属性指向构造函数

  • 实例通过[Prototype] を通じて呼び出されない場合new オペレーターによって呼び出されるのは通常の関数です

    例:

    function A() {
     
    }
    //在A的原型上绑定sayA()方法
    A.prototype.sayA = function(){
            console.log("from A")
    }
    function B(){

    }
    
     //让B的原型对象指向A的一个实例
     B.prototype = new A();
     
     //在B的原型上绑定sayB()方法
     B.prototype.sayB = function(){
            console.log("from B")
     }
     //生成一个B的实例
     var a1 = new A();
     var b1 = new B();
     
     //b1可以调用sayB和sayA
     b1.sayB();//'from B'
     b1.sayA();//'from A'
ログイン後にコピー
var person1 = new Person('Mike',10); では、関数 新しい演算子 person を通じて呼び出され、person1 が生成されます。ここでの person は
コンストラクター と呼ばれ、person1person と呼ばれます 関数オブジェクト の

インスタンス
。インスタンスには、対応するコンストラクター関数jsの継承メカニズムの詳細な解釈を指す
constructor 属性があります。次の例を参照してください:

rrreee
    2. プロトタイプ オブジェクト
  • 関数を作成するたびに、関数オブジェクトが作成されます。 prototype 属性があります。これは、プロトタイプ オブジェクトを指す

    ポインター🎜 です。 🎜プロトタイプオブジェクトの本質もオブジェクトです🎜。この文を初めて読むと、少し理解するのが難しいかもしれません。たとえば、今の関数を考えてみましょう: 🎜rrreee🎜 person.prototype がプロトタイプであるオブジェクトを指していることがわかります。このオブジェクトには constructor 属性があり、この属性は person 関数オブジェクトを指します。少しめまいを感じますか?問題はありません。次は、例を示すよりも優れた方法を使用します。図を描画します。 🎜🎜3. コンストラクター、プロトタイプ オブジェクト、インスタンスの関係 🎜🎜 先ほど、コンストラクター、インスタンス、プロトタイプ オブジェクトを紹介しました。次に、この 3 つの関係を図で表します (ps を使用してこのような図を描きます)。誰か良いツールを勧めてくれませんか?): 🎜jsの継承メカニズムの詳細な解釈🎜から私たちが見ることができる画像: 🎜🎜🎜🎜 関数オブジェクトの prototype はプロトタイプ オブジェクトを指し、プロトタイプ オブジェクトの constructor は関数オブジェクトを指します🎜🎜🎜 🎜インスタンスオブジェクト [Protoptype] 属性は 🎜プロトタイプオブジェクト🎜 を指します。ここでの [Protoptype] は、🎜内部属性🎜 であることがわかります。 (一部のブラウザではこの属性へのアクセスが許可されていますが、最初にこのように理解しましょう) この属性の機能は次のとおりです: 🎜この属性を通じてインスタンスがプロトタイプ オブジェクトのプロパティとメソッドにアクセスできるようにします。 🎜。例: 🎜🎜🎜rrreee🎜ここでは、person1 インスタンスの sex 属性を設定しません。これは、[Protoptype]が存在するためです。 >、プロトタイプはオブジェクト内の対応する属性にアクセスされます。同時に、sex 属性を person2 に設定すると、出力は「女性」になります。これは、🎜インスタンス自体には対応する属性やメソッドがない場合、🎜🎜🎜継承🎜🎜プロトタイプ チェーン🎜🎜 で対応するプロパティやメソッドが見つかります。js では、継承の主な考え方はプロトタイプ チェーンを使用することです。したがって、プロトタイプチェーンを理解すれば、継承の問題は半分理解できます。前の準備知識をほぼ理解したら、ここで少し休憩してください。プロトタイプ チェーンについて話し始めることができます。 🎜🎜🎜 プロトタイプ チェーンの原則は、ある参照型に別の参照型のプロパティとメソッドを継承させることです。 🎜🎜まず、今述べた知識を確認してください: 🎜🎜🎜🎜🎜プロトタイプ オブジェクト 🎜 は、constructor 属性を通じて 🎜 コンストラクター 🎜 を指します 🎜🎜🎜🎜🎜🎜 インスタンス 🎜 through [Prototype] code> 属性は 🎜prototype オブジェクトを指します🎜🎜🎜🎜🎜 ここで、次の質問について考えてみましょう: 🎜 プロトタイプ オブジェクトが別のコンストラクターのインスタンスと等しい場合はどうなりますか? 🎜🎜例: 🎜rrreee🎜何が起こったのかを簡単に理解するために、別の写真を撮りましょう: 🎜🎜🎜次に、画像と組み合わされたコードを見てください: 🎜🎜🎜🎜まず、2 つの関数オブジェクト A と B を作成しました。 🎜 同時に、プロトタイプオブジェクトが生成されます🎜🎜
  • 次に、A のプロトタイプ オブジェクトに sayA() メソッドを追加しましたsayA()方法
    * 然后是关键性的一步B.prototype = new A();,我们让函数对象B的protytype指针指向了一个A的实例,请注意我的描述:是让函数对象B的protytype指针指向了一个A的实例,这也是为什么最后,B的原型对象里面不再有constructor属性,其实B本来有一个真正的原型对象,原本可以通过B.prototype访问,但是我们现在改写了这个指针,使它指向了另一个对象,所以B真正的原型对象现在没法被访问了,取而代之的这个新的原型对象是A的一个实例,自然就没有constructor属性了

  • 接下来我们给这个B.prototype指向的对象,增加一个sayB方法

  • 然后,我们生成了一个实例b1

  • 最后我们调用了b1的sayB方法,可以执行,为什么?
    因为b1有[Prototype]属性可以访问B prototype里面的方法;

  • 我们调用了b1的sayA方法,可以执行,为什么?
    因为b1沿着[Prototype]属性可以访问B prototype,B prototype继续沿着[Prototype]属性访问A prototype,最终在A.prototype上找到了sayA()方法,所以可以执行

所以,现在的结果就相当于,b1继承了A的属性和方法,这种[Prototype]* 次に、重要なステップ B.prototype = new A(); が来ます。 >関数オブジェクト B の protytype ポインターが A のインスタンスを指すようにします 私の説明に注目してください: 関数オブジェクト B の protytype ポインターが指すようにします。 A のインスタンスです

。これが、 結局B のプロトタイプ オブジェクトにコンストラクター属性

がなくなった理由です。実際、B にはもともと実際のプロトタイプ オブジェクトがあり、B.prototype を通じてアクセスできました。このポインタは別のオブジェクトを指すようにするため、B の実際のプロトタイプ オブジェクトにはアクセスできなくなります。代わりに、新しいプロトタイプ オブジェクトは A のインスタンスであり、当然のことながら constructor はありません。


次に、B.prototype🎜🎜🎜🎜🎜が指すオブジェクトに sayB メソッドを追加します。次に、インスタンス b1🎜🎜🎜🎜を生成します。 b1のsayBメソッドが実行できるのはなぜでしょうか? 🎜b1 には [Prototype] 属性があり、B プロトタイプのメソッドにアクセスできるためです。🎜🎜🎜🎜🎜 b1 のsayA メソッドを呼び出して実行できるのはなぜでしょうか。 🎜b1 は [Prototype] プロパティに沿って B プロトタイプにアクセスできるため、B プロトタイプは [Prototype] プロパティに沿って A プロトタイプにアクセスし続け、最後に A にアクセスします。プロトタイプ SayA() メソッドが見つかったので、実行できます🎜🎜🎜🎜 したがって、現在の結果は次と同等です。b1 は A🎜 の属性とメソッドを継承します。これはによって[プロトタイプ]インスタンスとプロトタイプオブジェクトを連続的に接続する構造がプロトタイプチェーン🎜です。 jsにおける継承の主な実装方法でもあります。 🎜🎜原文はhttps://segmentfault.com/a/1190000007376061から🎜🎜🎜🎜

以上がjsの継承メカニズムの詳細な解釈の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C++関数継承の詳しい解説:継承で「基底クラスポインタ」と「派生クラスポインタ」を使うには? C++関数継承の詳しい解説:継承で「基底クラスポインタ」と「派生クラスポインタ」を使うには? May 01, 2024 pm 10:27 PM

関数の継承では、「基底クラス ポインター」と「派生クラス ポインター」を使用して継承メカニズムを理解します。基底クラス ポインターが派生クラス オブジェクトを指す場合、上方変換が実行され、基底クラスのメンバーのみにアクセスされます。派生クラス ポインターが基本クラス オブジェクトを指す場合、下向きキャストが実行される (安全ではない) ため、注意して使用する必要があります。

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

C++ 関数の継承の詳細な説明: 継承のエラーをデバッグするには? C++ 関数の継承の詳細な説明: 継承のエラーをデバッグするには? May 02, 2024 am 09:54 AM

継承エラーのデバッグのヒント: 正しい継承関係を確認します。デバッガーを使用してコードをステップ実行し、変数値を調べます。仮想修飾子を正しく使用してください。隠れた相続によって引き起こされる相続ダイアモンド問題を調べてください。抽象クラスに実装されていない純粋仮想関数がないか確認します。

継承とポリモーフィズムは C++ のクラス結合にどのような影響を与えますか? 継承とポリモーフィズムは C++ のクラス結合にどのような影響を与えますか? Jun 05, 2024 pm 02:33 PM

継承とポリモーフィズムはクラスの結合に影響します。派生クラスは基本クラスに依存するため、継承により結合が増加します。ポリモーフィズムにより、オブジェクトは仮想関数と基本クラス ポインターを通じて一貫した方法でメッセージに応答できるため、結合が軽減されます。ベスト プラクティスには、継承を控えめに使用すること、パブリック インターフェイスを定義すること、基本クラスへのデータ メンバーの追加を回避すること、依存関係の注入を通じてクラスを分離することが含まれます。ポリモーフィズムと依存性注入を使用して銀行口座アプリケーションの結合を軽減する方法を示す実践的な例。

C++ 関数の継承の詳細な説明: 継承における 'is-a' と 'has-a' の関係を理解するには? C++ 関数の継承の詳細な説明: 継承における 'is-a' と 'has-a' の関係を理解するには? May 02, 2024 am 08:18 AM

C++の関数継承を詳しく解説:「is-a」と「has-a」の関係をマスターしよう 関数継承とは?関数の継承は、派生クラスで定義されたメソッドを基本クラスで定義されたメソッドに関連付ける C++ の手法です。これにより、派生クラスが基本クラスのメソッドにアクセスしてオーバーライドできるようになり、基本クラスの機能が拡張されます。 「is-a」および「has-a」関係 関数継承では、「is-a」関係は、派生クラスが基本クラスのサブタイプであること、つまり、派生クラスが基本クラスの特性と動作を「継承」することを意味します。基本クラス。 「has-a」関係は、派生クラスに基本クラス オブジェクトへの参照またはポインターが含まれていること、つまり、派生クラスが基本クラス オブジェクトを「所有」していることを意味します。構文関数継承を実装する方法の構文は次のとおりです: classDerivedClass:pu

JavaScript で HTTP ステータス コードを簡単に取得する方法 JavaScript で HTTP ステータス コードを簡単に取得する方法 Jan 05, 2024 pm 01:37 PM

JavaScript で HTTP ステータス コードを取得する方法の紹介: フロントエンド開発では、バックエンド インターフェイスとの対話を処理する必要があることが多く、HTTP ステータス コードはその非常に重要な部分です。 HTTP ステータス コードを理解して取得すると、インターフェイスから返されたデータをより適切に処理できるようになります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法と、具体的なコード例を紹介します。 1. HTTP ステータス コードとは何ですか? HTTP ステータス コードとは、ブラウザがサーバーへのリクエストを開始したときに、サービスが

「PHP によるオブジェクト指向プログラミング入門: 概念から実践まで」 「PHP によるオブジェクト指向プログラミング入門: 概念から実践まで」 Feb 25, 2024 pm 09:04 PM

オブジェクト指向プログラミングとは何ですか?オブジェクト指向プログラミング (OOP) は、現実世界のエンティティをクラスに抽象化し、オブジェクトを使用してこれらのエンティティを表すプログラミング パラダイムです。クラスはオブジェクトのプロパティと動作を定義し、オブジェクトはクラスをインスタンス化します。 OOP の主な利点は、コードの理解、保守、再利用が容易になることです。 OOP の基本概念 OOP の主な概念には、クラス、オブジェクト、プロパティ、メソッドが含まれます。クラスはオブジェクトの設計図であり、オブジェクトのプロパティと動作を定義します。オブジェクトはクラスのインスタンスであり、クラスのすべてのプロパティと動作を備えています。プロパティは、データを保存できるオブジェクトの特性です。メソッドは、オブジェクトのデータを操作できるオブジェクトの関数です。 OOP の利点 OOP の主な利点は次のとおりです。 再利用性: OOP はコードをより高度なものにすることができます。

C++ 関数の継承の説明: 継承を使用すべきでないのはどのような場合ですか? C++ 関数の継承の説明: 継承を使用すべきでないのはどのような場合ですか? May 04, 2024 pm 12:18 PM

C++ 関数の継承は、次の状況では使用しないでください。 派生クラスが異なる実装を必要とする場合、異なる実装を持つ新しい関数を作成する必要があります。派生クラスが関数を必要としない場合は、空のクラスとして宣言するか、プライベートの未実装の基本クラス メンバー関数を使用して関数の継承を無効にする必要があります。関数が継承を必要としない場合は、コードの再利用を実現するために他のメカニズム (テンプレートなど) を使用する必要があります。

See all articles