JavaScriptでプロトタイプを完全解析_基礎知識
JS のプロトタイプを理解するには、まず次の概念を理解する必要があります
1. JS 内のすべてはオブジェクトです
2. JS 内のすべては Object から派生します。つまり、すべてのプロトタイプ チェーンの終点は Object.prototype
を指します。
// ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", // "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", // "__lookupSetter__"] console.log(Object.getOwnPropertyNames(Object.prototype));
3. JS におけるコンストラクターとインスタンス (オブジェクト) の微妙な関係
コンストラクターは、プロトタイプを定義してインスタンスの仕様に同意し、new を使用してインスタンスを構築します。
コンストラクター (メソッド) 自体はメソッド (関数) のインスタンスであるため、その __proto__ (プロトタイプ チェーン) も見つけることができます
オブジェクト / 関数 F() {} これはコンストラクターであり、1 つは JS ネイティブ API によって提供され、もう 1 つはカスタマイズされます
new Object() / new F() これはインスタンスです
インスタンスは、__proto__ をチェックして、どのプロトタイプに基づいているかを知ること「しかできません」。
また、インスタンスのプロトタイプを再定義してインスタンスのインスタンスを作成することは「できません」。
実践は真の知識をもたらします。自分自身を観察/考えることによってのみ、真に理解することができます:
// 先来看看构造函数到底是什么 // function Empty() {} function Empty() {} console.log(Function.prototype, Function.__proto__); // Object {} function Empty() {} console.log(Object.prototype, Object.__proto__); function F() {} // F {} function Empty() {} console.log(F.prototype, F.__proto__);
あなたは気を失っているかもしれません。それを解消しましょう。
プロトタイプ
プロトタイプの出力形式は次のとおりです: コンストラクター名 プロトタイプ
まず、Object.prototype の出力を見てみましょう?
Object {} -> 前の Object はコンストラクターの名前で、後の Object はプロトタイプを表します。これは Object オブジェクト (空のオブジェクト) のインスタンスです
そうすれば、F {} が何を意味するのかがわかります。F はコンストラクターの名前であり、プロトタイプも空のオブジェクトです
// 再来看看由构造函数构造出来的实例 var o = new Object(); // var o = {}; // undefined Object {} console.log(o.prototype, o.__proto__); function F() {} var i = new F(); // undefined F {} console.log(i.prototype, i.__proto__);
もう少し詳しく F のプロトタイプを定義して、何が起こるか見てみましょう。
function F() {} F.prototype.a = function() {}; var i = new F(); // undefined F {a: function} console.log(i.prototype, i.__proto__);
このようにして、i が F から構築され、プロトタイプが {a: function} であることが明確にわかります。これは、元の空のオブジェクト プロトタイプに新しい a メソッドがあることを意味します
別の状況を変えてみましょう。F のプロトタイプを完全にカバーするとどうなりますか?
function F() {} F.prototype = { a: function() {} }; var i = new F(); // undefined Object {a: function} console.log(i.prototype, i.__proto__);
ねえ、なぜ i が Object から構築されていると表示されるのですか?
F のプロトタイプを完全に上書きするので、実際にはプロトタイプをオブジェクト {a: function} として指定しますが、元のコンストラクターの情報が失われ、オブジェクト {a: function} で指定されたコンストラクターになります。
では、オブジェクト {a: function} のコンストラクターは何でしょうか?
オブジェクト {a: function} は実際には
に相対的なものであるため、
var o = {a: function() {}} // new了一个Object
もちろん、o のコンストラクターは Object
この間違いを正しましょう
function F() {} F.prototype = { a: function() {} } // 重新指定正确的构造函数 F.prototype.constructor = F; var i = new F(); // undefined F {a: function, constructor: function} console.log(i.prototype, i.__proto__);
これで、正しいプロトタイプ情報を再び取得できます~
プロトタイプチェーン
それでは、プロトタイプチェーンとは何なのか見てみましょう?
簡単に言えば、OOP の継承関係 (チェーン) と同じで、最後の Object.prototype
に到達するまで階層を重ねていきます。
最も重要なことは、JS 内のどれが (インスタンス) オブジェクトであるかを理解することです。これは簡単です。
もう 1 つ理解すべきことは、すべてのオブジェクトにはプロトタイプがあるということです!
それでは、それを証明しましょう:
Object // 这是一个函数, 函数是 Function 的实例对象, 那么就是由 Function 构造出来的 Object.__proto__ == Function.prototype // 那么Object的原型, true // 这个是一个普通对象了, 因此属于 Object 的实例 Function.prototype.__proto__ == Object.prototype // true // 这已经是原型链的最顶层了, 因此最终的指向 null Object.prototype.__proto__ == null // true Function // 这也是一个函数, 没错吧! Function.__proto__ == Function.prototype // true function A() {} // 这是一个自定义的函数, 终归还是一个函数, 没错吧! A.__proto__ == Function.prototype // 任何函数都是 Function 的实例, 因此A的原型是? var a = new A() a.__proto__ == A.prototype // 实例a是由A构造函数构造出来的, 因此a的原型是由A的prototype属性定义的 A.prototype.__proto__ == Object.prototype // 普通对象都是 Object 的示例
プロトタイプと __proto__
各オブジェクトには、このオブジェクトの「プロトタイプ」を指す __proto__ が含まれています。
同様に、すべての関数にはプロトタイプが含まれています。このプロトタイプ オブジェクトは何を行うのでしょうか。
コンストラクターを使用してオブジェクトを作成する次のコードを見てみましょう (上記はリテラルの形式でオブジェクトを作成するものです)。
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__);
考えてみてください、この foo オブジェクトの __proto__ は何を指しているのでしょうか?
コンストラクタープロパティを含むオブジェクト?よく理解できなくても問題ありません。関数 Foo のプロトタイプ属性を出力して比較してください。
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__); console.log(Foo.prototype); console.log(foo.__proto__ === Foo.prototype);
新しいオブジェクト foo の __proto__ は関数 Foo のプロトタイプのみを指していることがわかります。
foo.__proto__ --> Foo.prototype
JS这么设计有何意义了?回忆下上面说的,在JS的世界中,对象不是根据类(模具)创建出来的,而是从原型(另一个对象)衍生出来的。
当我们执行new操作创建一个新的对象时,先不深入new操作的具体实现,但有一点我们是肯定的——就是为新对象的__proto__指向一个原型对象。
就刚才这段代码
function Foo(){}; var foo = new Foo();
foo.__proto__到底要指向谁了?你怎么不能指向Foo这个函数本身吧,虽然函数也是对象,这个有机会会详细讲。但如何foo.__proto__指向Foo固然不合适,因为Foo是一个函数,有很多逻辑代码,foo作为一个对象,继承逻辑处理没有任何意义,它要继承的是“原型对象”的属性。
所以,每个函数会自动生成一个prototype对象,由这个函数new出来的对象的__proto__就指向这个函数的prototype。
foo.__proto__ --> Foo.prototype
总结
说了这么多,感觉还是没完全说清楚,不如上一张图。我曾经参考过其他网友的图,但总觉得哪里没说清楚,所以我自己画了一张图,如果觉得我的不错,请点个赞!(老子可是费了牛劲才画出来)。
咱们就着这张图,记住如下几个事实:
1. 每个对象中都有一个_proto_属性。
JS世界中没有类(模具)的概念,对象是从另一个对象(原型)衍生出来的,所以每个对象中会有一个_proto_属性指向它的原型对象。(参考左上角的那个用字面量形式定义的对象obj,它在内存中开辟了一个空间存放对象自身的属性,同时生成一个_proto_指向它的原型——顶层原型对象。)
2. 每个函数都有一个prototype属性。
“构造函数”为何叫构造函数,因为它要构造对象。那么根据上面第一条事实,构造出来的新对象的_proto_属性指向谁了?总不能指向构造函数自身,虽然它也是个对象,但你不希望新对象继承函数的属性与方法吧。所以,在每个构造函数都会有一个prototype属性,指向一个对象作为这个构造函数构造出来的新对象的原型。
3. 函数也是对象。
每个函数都有一些通用的属性和方法,比如apply()/call()等。但这些通用的方法是如何继承的呢?函数又是怎么创建出来的呢?试想想,一切皆对象,包括函数也是对象,而且是通过构造函数构造出来的对象。那么根据上面第二条事实,每个函数也会有_proto_指向它的构造函数的prototype。而这个构造函数的函数就是Function,JS中的所有函数都是由Function构造出来的。函数的通用属性与方法就存放在Function.prototype这个原型对象上。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック









WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

顔の検出および認識テクノロジーは、すでに比較的成熟しており、広く使用されているテクノロジーです。現在、最も広く使用されているインターネット アプリケーション言語は JS ですが、Web フロントエンドでの顔検出と認識の実装には、バックエンドの顔認識と比較して利点と欠点があります。利点としては、ネットワーク インタラクションの削減とリアルタイム認識により、ユーザーの待ち時間が大幅に短縮され、ユーザー エクスペリエンスが向上することが挙げられます。欠点としては、モデル サイズによって制限されるため、精度も制限されることが挙げられます。 js を使用して Web 上に顔検出を実装するにはどうすればよいですか? Web 上で顔認識を実装するには、JavaScript、HTML、CSS、WebRTC など、関連するプログラミング言語とテクノロジに精通している必要があります。同時に、関連するコンピューター ビジョンと人工知能テクノロジーを習得する必要もあります。 Web 側の設計により、次の点に注意してください。

株式分析に必須のツール: PHP および JS でローソク足チャートを描画する手順を学びます。特定のコード例が必要です。インターネットとテクノロジーの急速な発展に伴い、株式取引は多くの投資家にとって重要な方法の 1 つになりました。株価分析は投資家の意思決定の重要な部分であり、ローソク足チャートはテクニカル分析で広く使用されています。 PHP と JS を使用してローソク足チャートを描画する方法を学ぶと、投資家がより適切な意思決定を行うのに役立つ、より直感的な情報が得られます。ローソク足チャートとは、株価をローソク足の形で表示するテクニカルチャートです。株価を示しています

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

インターネット金融の急速な発展に伴い、株式投資を選択する人がますます増えています。株式取引では、ローソク足チャートは一般的に使用されるテクニカル分析手法であり、株価の変化傾向を示し、投資家がより正確な意思決定を行うのに役立ちます。この記事では、PHP と JS の開発スキルを紹介し、株価ローソク足チャートの描画方法を読者に理解してもらい、具体的なコード例を示します。 1. 株のローソク足チャートを理解する 株のローソク足チャートの描き方を紹介する前に、まずローソク足チャートとは何かを理解する必要があります。ローソク足チャートは日本人が開発した

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

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

js と vue の関係: 1. Web 開発の基礎としての JS、2. フロントエンド フレームワークとしての Vue.js の台頭、3. JS と Vue の補完関係、4. JS と Vue の実用化ビュー。
