JavaScriptの理解(四)
28910 ワード
第四編はずいぶん長引いて、本当に申し訳ありません.正直に言うと、長引く原因は主にどう書くか考えていないことです.このテーマには挑戦性があるからです.原型と原型ベースの継承--あ~やっと言いました.これで遅らせる口実はありません.==
私(個人)が嫌いなのは、原型を話すときに上がってきて類を比較することなので、そうは言いません.しかし、私は確かにコンストラクタ関数を話したことがありますが、この点ではクラスと多少共通点がありません.私の提案は、クラスを忘れることです.「類」学の氾濫は対象への過度な発展であり、悲しみであり、多くの開発者がほとんど対象と類に等号をつけているという見方が多い.原型を学ぶ前に、この言葉を覚えて味わってください.
オブジェクト向け設計の真髄は「抽象」の二字にあり、クラスは実体抽象を実現する手段であるが、唯一ではない.
事前に宣言します:永遠に、真実のコードの中で
JavaScriptでは、関数が対象になります(これを学んだら、関数がどのように対象になったのかを検討してみてはいかがでしょうか).オブジェクトは、意外にも属性があり(方法も属性)、そして意外にも
考えてみてください.
これは問題を示しています.
関数のプロトタイププロパティは、関数自体ではなく、コンストラクタとして作成されたオブジェクトに使用されます.
疑問なことに、
ああ~コピーしたのではなく、
間違いない!これがプロトタイプメカニズムの真髄です.すべての詳細(表象の下に隠されているものを含む)をまとめましょう.
関数には
関数がコンストラクタとして機能する場合、
オブジェクトのプロパティ(メソッドを含む)にアクセスすると、まず、そのオブジェクト自体にそのプロパティがあるかどうかを検索し、ない場合はそのプロトタイプ(つまり
OK、上の4つ目は事実上JavaScriptのオブジェクト属性検索メカニズムです.以下のようになります.
プロトタイプの意味は、オブジェクトのプロパティ検索メカニズムに方向を提供すること、またはルートを提供することです.
1つのオブジェクトで、多くのプロパティがあり、1つのプロパティが別のオブジェクトのプロトタイププロパティを指します.後者には、別のオブジェクトのプロトタイプ属性を指す属性もあります.これは1つの輪に1つの輪の鎖のように、この鎖のいずれかの点から探して、最後にチェーンの起点、すなわち
次に、使用する用語(少なくとも本明細書の範囲内)を統一したいと思います.
関数の
オブジェクトの
例:
言い換えれば、オブジェクトのプロトタイプ属性やプロトタイプオブジェクトは自分用ではなく、オブジェクトのプロトタイプは直接使用できます.
これは設計上のミスであり、
オブジェクトを介してプロトタイプにアクセスする場合、ES 5は新しい方法を提供します.
これは安全ですから、安心して使ってください.低バージョンブラウザの互換性の問題を考慮してes 5-shimを使用できます
オブジェクトのプロトタイプは、割り当てではなく参照であるため、プロトタイプのプロパティを変更すると、すべてのインスタンスオブジェクトにすぐに作用します.このプロパティは、オブジェクトのインスタンスメソッドを定義するのに最適です.
ただし、独自のプロパティを変更すると、新しく作成したインスタンスオブジェクトにのみ影響を与えます.
この例は少し無厘頭に見え、あまり役に立たないが、現実世界では複雑なオブジェクトの行為が状況に応じて書き換えられるかもしれないが、オブジェクトの内部状態を変えたくないという精神がある.あるいは、親オブジェクトのいくつかの動作を他の同じ部分に導かずに上書きする継承を実現します.これらの場合、プロトタイプは私たちに最大限の柔軟性を与えます.
属性が独自であるか、プロトタイプから来ているかをどのように知るか.上コード~
コードは簡単で、過度に説明する必要はありません.最後の2つの文は実際に等価な書き方に注意してください.
さっきのこのコード:
オブジェクト
本当に!しかし、私たちは面白いからこれを研究したわけではありません.
プロトタイプオブジェクトのプロパティを変更すると、すぐにすべてのインスタンスオブジェクトに作用しますが、プロトタイプオブジェクトを完全に上書きすると、奇妙なことになります.(次の例を読んで、自分の考えを一言一言検証してください)
え?
1つのオブジェクトを作成するだけでは、プロトタイプの役割はすべて発揮されません.プロトタイプとプロトタイプチェーンの特性をさらに利用して、私たちのコードを拡張し、プロトタイプベースの継承を実現します.
プロトタイプ継承は非常に大きな話題の範囲であり、プロトタイプ継承はクラス継承ほど整っていないように見えますが(相対的に)、より柔軟であることが徐々にわかります.単一継承でも多重継承でも、Mixinや他の名前さえ言えない継承方式でも、原型継承は実現する方法があり、一つの方法ではないことが多い.
まず簡単なことから始めましょう
これは非常に良い例で、以下のポイントを示しています.
私が撫でてみます.
最後から2番目の行、
まだ終わっていないので、続けてみます.
上記の例では、
思考が活発で反応が速い学生はもう考えているかもしれません.
親のプロトタイプ属性ではなく、親のインスタンスを子のプロトタイプ属性に割り当てる必要があるのはなぜですか.
いい質問だ!この考え方は非常に理にかなっており,これにより属性検索の回数を減らすことができる.上を検索するときに親インスタンスの
しかし、そうしない理由も簡単です.もしあなたがそうしたら:
Javascriptは参照付与値であるため、等号の両端の2つの属性が同じオブジェクトを指すことに等しいため、サブクラスでメソッドをリロードすると、親のメソッドも一緒に変化し、リロードの意味がなくなります.したがって、リロードが不要であることが確認された場合にのみ可能です.
プロトタイプ
私(個人)が嫌いなのは、原型を話すときに上がってきて類を比較することなので、そうは言いません.しかし、私は確かにコンストラクタ関数を話したことがありますが、この点ではクラスと多少共通点がありません.私の提案は、クラスを忘れることです.「類」学の氾濫は対象への過度な発展であり、悲しみであり、多くの開発者がほとんど対象と類に等号をつけているという見方が多い.原型を学ぶ前に、この言葉を覚えて味わってください.
オブジェクト向け設計の真髄は「抽象」の二字にあり、クラスは実体抽象を実現する手段であるが、唯一ではない.
prototypeと_proto__
事前に宣言します:永遠に、真実のコードの中で
__proto__
の属性を使わないでください、本文の中でそれを使って純粋に研究に使います!すぐに代替品についてお話ししますので、申し訳ありませんが我慢してください.JavaScriptでは、関数が対象になります(これを学んだら、関数がどのように対象になったのかを検討してみてはいかがでしょうか).オブジェクトは、意外にも属性があり(方法も属性)、そして意外にも
prototype
が関数の属性であり、最後に意外なprototype
もオブジェクトである.ほら、どんなに順調なことか.
prototype
は何の役に立つの?ええ、関数を関数として使うと、全然役に立ちません.ただし、関数をコンストラクタとして使用すると、新しく生成されたオブジェクトはprototype
オブジェクトのプロパティに直接アクセスできます.
考えてみてください.
f
のconstructor
の属性はどこから来ましたか.もしあなたが分からないなら、console.dir(Foo.prototype)
で真相を探してください.これは問題を示しています.
関数のプロトタイププロパティは、関数自体ではなく、コンストラクタとして作成されたオブジェクトに使用されます.
疑問なことに、
prototype
属性はFoo
関数オブジェクト内に存在するが、Foo
によって作成されたインスタンスオブジェクトf
は、prototype
にどのようにアクセスするのか.prototype
オブジェクトをコピーしますか?次のコードを見てみましょう.
ああ~コピーしたのではなく、
__proto__
という属性がコンストラクタのprototype
オブジェクトを指していますね.間違いない!これがプロトタイプメカニズムの真髄です.すべての詳細(表象の下に隠されているものを含む)をまとめましょう.
関数には
prototype
のプロパティがありますが、関数自体はを使用しません.関数がコンストラクタとして機能する場合、
new
オペレータの組み合わせが必要な新しいオブジェクトを作成できます.その仕事の原理は私はすでに第1編で大部分の述べをしましたまだ言及していないのは、new
が新しいオブジェクトを作成するときに、コンストラクタを指すprototype
のプロパティを新しいオブジェクトに与えます.この新しいプロパティは、いくつかのブラウザ環境では__proto__
と呼ばれています.オブジェクトのプロパティ(メソッドを含む)にアクセスすると、まず、そのオブジェクト自体にそのプロパティがあるかどうかを検索し、ない場合はそのプロトタイプ(つまり
__proto__
が指すprototype
オブジェクト)、ない場合はプロトタイプのプロトタイプ(prototype
も独自の__proto__
もあり、より上位のprototype
オブジェクトを指す)を検索し、Object
が見つかるまでを検索する.OK、上の4つ目は事実上JavaScriptのオブジェクト属性検索メカニズムです.以下のようになります.
プロトタイプの意味は、オブジェクトのプロパティ検索メカニズムに方向を提供すること、またはルートを提供することです.
1つのオブジェクトで、多くのプロパティがあり、1つのプロパティが別のオブジェクトのプロトタイププロパティを指します.後者には、別のオブジェクトのプロトタイプ属性を指す属性もあります.これは1つの輪に1つの輪の鎖のように、この鎖のいずれかの点から探して、最後にチェーンの起点、すなわち
Object
を見つけることができます.したがって,このメカニズムをプロトタイプチェーンと呼ぶ.次に、使用する用語(少なくとも本明細書の範囲内)を統一したいと思います.
関数の
prototype
プロパティ:プロトタイププロパティまたはプロトタイプオブジェクトと呼びます.オブジェクトの
__proto__
プロパティ:プロトタイプと呼びます.例:
Foo
のプロトタイプ属性(またはプロトタイプオブジェクト)=Foo.prototype
f
のプロトタイプ=f.__proto__
統一用語は、Foo.prototype
およびf.__proto__
が等価であるにもかかわらず、prototype
および__proto__
が異なるためである.固定されたオブジェクトを考慮すると、prototype
はプロトタイプチェーンの下に使用され、__proto__
はプロトタイプチェーンの上を指す.したがって,いったん「プロトタイプ属性」や「プロトタイプオブジェクト」と言うと,これは子孫や孫たちに与えられたものであることを暗示し,「プロトタイプ」というのは親世代から受け継がれたものであることを示唆している.言い換えれば、オブジェクトのプロトタイプ属性やプロトタイプオブジェクトは自分用ではなく、オブジェクトのプロトタイプは直接使用できます.
__proto__ の質問
__proto__
がオブジェクトのプロトタイプにアクセスできる以上、なぜ実際に使用できないのでしょうか.これは設計上のミスであり、
__proto__
の属性が修正可能であると同時に、JavaScriptの属性検索メカニズムが「マヒ」することを意味するため、それを強く推奨しない.オブジェクトを介してプロトタイプにアクセスする場合、ES 5は新しい方法を提供します.
これは安全ですから、安心して使ってください.低バージョンブラウザの互換性の問題を考慮してes 5-shimを使用できます
固有属性とプロトタイプ属性の違い
オブジェクトのプロトタイプは、割り当てではなく参照であるため、プロトタイプのプロパティを変更すると、すべてのインスタンスオブジェクトにすぐに作用します.このプロパティは、オブジェクトのインスタンスメソッドを定義するのに最適です.
ただし、独自のプロパティを変更すると、新しく作成したインスタンスオブジェクトにのみ影響を与えます.
この例は少し無厘頭に見え、あまり役に立たないが、現実世界では複雑なオブジェクトの行為が状況に応じて書き換えられるかもしれないが、オブジェクトの内部状態を変えたくないという精神がある.あるいは、親オブジェクトのいくつかの動作を他の同じ部分に導かずに上書きする継承を実現します.これらの場合、プロトタイプは私たちに最大限の柔軟性を与えます.
属性が独自であるか、プロトタイプから来ているかをどのように知るか.上コード~
コードは簡単で、過度に説明する必要はありません.最後の2つの文は実際に等価な書き方に注意してください.
気をつけて
さっきのこのコード:
p1.constructor.prototype.hasOwnProperty("greeting");
、実は面白い問題が隠されています.オブジェクト
p1
は、constructor
のプロパティを提供してくれたプロトタイプに感謝して、独自のコンストラクタにアクセスできます.次に、constructor
プロパティを使用して、プロトタイプオブジェクトに逆アクセスできます.これは輪のようです.試してみましょう.
本当に!しかし、私たちは面白いからこれを研究したわけではありません.
プロトタイプオブジェクトのプロパティを変更すると、すぐにすべてのインスタンスオブジェクトに作用しますが、プロトタイプオブジェクトを完全に上書きすると、奇妙なことになります.(次の例を読んで、自分の考えを一言一言検証してください)
え?
Person
のプロトタイプ属性にはsay
の方法があるのに?プロトタイプオブジェクトは即時に有効ではありませんか?プロトタイプ継承
1つのオブジェクトを作成するだけでは、プロトタイプの役割はすべて発揮されません.プロトタイプとプロトタイプチェーンの特性をさらに利用して、私たちのコードを拡張し、プロトタイプベースの継承を実現します.
プロトタイプ継承は非常に大きな話題の範囲であり、プロトタイプ継承はクラス継承ほど整っていないように見えますが(相対的に)、より柔軟であることが徐々にわかります.単一継承でも多重継承でも、Mixinや他の名前さえ言えない継承方式でも、原型継承は実現する方法があり、一つの方法ではないことが多い.
まず簡単なことから始めましょう
これは非常に良い例で、以下のポイントを示しています.
私が撫でてみます.
最後から2番目の行、
new Person()
はオブジェクトを作成し、Programmer.prototype
に割り当てられ、コンストラクタのプロトタイプ属性はPerson
のインスタンスオブジェクトになります. Person
オブジェクトは書き換えられたtoString()
メソッドを有し、このメソッドは宿主オブジェクトのklass
プロパティを返すので、Programmer
にgreeting()
メソッドを定義し、継承されたtoString()
を使用することができる. someone
オブジェクトがtoString()
メソッドを呼び出すと、this
はそれ自体を指すので、
ではなく
を出力することができる. まだ終わっていないので、続けてみます.
メソッドの再ロード
上記の例では、
toString()
メソッドのリロード(このメソッドの始祖オブジェクトはObject.prototype
)が実現されています.同じ精神を持って、私たち自身が書いたサブコンストラクタも、プロトタイプ属性によって親コンストラクタが提供するメソッドをリロードすることができます.
プロパティ検索とメソッドの再ロードの矛盾
思考が活発で反応が速い学生はもう考えているかもしれません.
親のプロトタイプ属性ではなく、親のインスタンスを子のプロトタイプ属性に割り当てる必要があるのはなぜですか.
いい質問だ!この考え方は非常に理にかなっており,これにより属性検索の回数を減らすことができる.上を検索するときに親インスタンスの
__proto__
をスキップし,(前例のように)Person.prototype
を直接見つけたからである.しかし、そうしない理由も簡単です.もしあなたがそうしたら:
Javascriptは参照付与値であるため、等号の両端の2つの属性が同じオブジェクトを指すことに等しいため、サブクラスでメソッドをリロードすると、親のメソッドも一緒に変化し、リロードの意味がなくなります.したがって、リロードが不要であることが確認された場合にのみ可能です.