ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptによるプロトタイプの包括的な分析

JavaScriptによるプロトタイプの包括的な分析

亚连
亚连オリジナル
2018-05-21 14:53:471387ブラウズ

この記事では、JavaScript におけるプロトタイプの完全な分析を主に紹介します。プロトタイプは、JS の世界における「すべてがオブジェクトである」という議論の重要なサポートであり、それを必要とする友人に役立つ情報について説明します。参考にしてください

JSのプロトタイプを理解するには、まず以下の概念を理解する必要があります
1. JSのすべてはオブジェクトです 2. JSのすべてはオブジェクトから派生します、つまり、すべてのもののプロトタイプチェーンの終点ですObject .prototype

  // ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", 
   // "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__",
   // "__lookupSetter__"]
   console.log(Object.getOwnPropertyNames(Object.prototype));

を指します 3. JS におけるコンストラクターとインスタンス (オブジェクト) の微妙な関係

コンストラクターはプロトタイプを定義することでインスタンスの仕様を合意し、new を通じてインスタンスを構築するのが役割です。コンストラクター (メソッド) 自体はメソッド (関数) のインスタンスであるため、その __proto__ (プロトタイプ チェーン) も見つかります


Object / function F() {} これがコンストラクターで、1 つは JS です ネイティブ API によって提供されます1 つはカスタマイズされています
new Object() / new F() これがインスタンスです

インスタンスは、どのプロトタイプに基づいているかを知るために __proto__ を表示すること「のみ」ができます

そして、インスタンスのプロトタイプを次のように再定義することは「できません」インスタンスのインスタンスを作成します。

実践することで真の知識が得られます。自分で観察したり考えたりすることによってのみ、真に理解することができます。

prototype

プロトタイプの出力形式は次のとおりです: コンストラクター名 プロトタイプ

まず、Object.prototype の出力を見てみましょう

Object {} -> 前のオブジェクトはコンストラクターの名前です。これがプロトタイプを表す後、A {}、つまり Object オブジェクト (空のオブジェクト) のインスタンスです

次に、F {} がコンストラクターの名前であり、プロトタイプも意味するものを理解します。空のオブジェクト

  // 先来看看构造函数到底是什么
  // 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__);
もう少し深くして 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__);

このようにすると、i が F から構築されており、プロトタイプが {a: function} であることが明確にわかります。元の空のオブジェクトのプロトタイプに新しい a メソッドがあるということです

もう一度状況を変えて、F のプロトタイプを完全にカバーしたらどうなるでしょうか

  function F() {}
  F.prototype.a = function() {};
  var i = new F();
  // undefined       F {a: function}
  console.log(i.prototype, i.__proto__);

どうしてですか? なぜ i が Object から構築されていることがわかりますか?

F のプロトタイプを完全にカバーしているため、実際には、プロトタイプはオブジェクト {a: function} として指定されていますが、これにより、元のコンストラクター情報が失われ、オブジェクト {a: function} で指定されたコンストラクターになります。

では、オブジェクト {a: function} のコンストラクターは何ですか?
オブジェクト {a: function} は実際には

function F() {}
  F.prototype = {
    a: function() {}
  };
  var i = new F();
  // undefined       Object {a: function}
  console.log(i.prototype, i.__proto__);

に相対しているため、o のコンストラクターはもちろん Object です

この間違いを修正しましょう

var o = {a: function() {}} // new了一个Object

正しいプロトタイプ情報を再度取得できます~

プロトタイプチェーン

では、プロトタイプチェーンとは何なのか見てみましょう

簡単に言うと、OOPの継承関係(チェーン)と同じで、レイヤーごとに上がっていきます。最終的な Object.prototype に到達するまで


最も重要なのは、JS 内のどのものが (インスタンス) オブジェクトであるかを理解することです。これは簡単です。すべてのオブジェクトにはプロトタイプがあるということです

それでは、それを証明してみましょう:2016510172352211.jpg (560×248)

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


プロトタイプと __proto__

すべてのオブジェクトには、このオブジェクトの「プロトタイプ」を指す __proto__ が含まれています。

同様に、すべての関数にはプロトタイプが含まれています。このプロトタイプ オブジェクトは何をするのでしょうか?

コンストラクターを使用してオブジェクトを作成する次のコードを見てみましょう (上記はリテラルの形式でオブジェクトを作成するものです)。

  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 的示例
考えてみてください、この foo オブジェクトの __proto__ は何を指しているのでしょうか?

コンストラクタープロパティを含むオブジェクト?よく理解できなくても問題ありません。関数 Foo のプロトタイプ属性を出力して比較してください。

function Foo(){};
var foo = new Foo();
console.log(foo.__proto__);

2016510172448163.png (163×68)

新しいオブジェクト foo の __proto__ は関数 Foo のプロトタイプのみを指していることがわかります。

rreee

このような JS のデザインには何の意味があるのでしょうか?上で述べたことを思い出してください。JS の世界では、オブジェクトはクラス (モールド) に基づいて作成されるのではなく、プロトタイプ (別のオブジェクト) から派生します。

2016510172512274.png (183×69) 新しいオブジェクトを作成するために新しい操作を実行するとき、新しい操作の具体的な実装には立ち入りませんが、1 つ確かなことは、新しいオブジェクトの __proto__ がプロトタイプ オブジェクトを指しているということです。

このコードだけ

function Foo(){};
var foo = new Foo();

foo.__proto__到底要指向谁了?你怎么不能指向Foo这个函数本身吧,虽然函数也是对象,这个有机会会详细讲。但如何foo.__proto__指向Foo固然不合适,因为Foo是一个函数,有很多逻辑代码,foo作为一个对象,继承逻辑处理没有任何意义,它要继承的是“原型对象”的属性。

所以,每个函数会自动生成一个prototype对象,由这个函数new出来的对象的__proto__就指向这个函数的prototype。

foo.__proto__ --> Foo.prototype

总结说了这么多,感觉还是没完全说清楚,不如上一张图。我曾经参考过其他网友的图,但总觉得哪里没说清楚,所以我自己画了一张图,如果觉得我的不错,请点个赞!(老子可是费了牛劲才画出来)。

2016510172555695.png (800×600)

咱们就着这张图,记住如下几个事实:

1. 每个对象中都有一个_proto_属性。

JS世界中没有类(模具)的概念,对象是从另一个对象(原型)衍生出来的,所以每个对象中会有一个_proto_属性指向它的原型对象。(参考左上角的那个用字面量形式定义的对象obj,它在内存中开辟了一个空间存放对象自身的属性,同时生成一个_proto_指向它的原型——顶层原型对象。)

2. 每个函数都有一个prototype属性。

“构造函数”为何叫构造函数,因为它要构造对象。那么根据上面第一条事实,构造出来的新对象的_proto_属性指向谁了?总不能指向构造函数自身,虽然它也是个对象,但你不希望新对象继承函数的属性与方法吧。所以,在每个构造函数都会有一个prototype属性,指向一个对象作为这个构造函数构造出来的新对象的原型。

3. 函数也是对象。

每个函数都有一些通用的属性和方法,比如apply()/call()等。但这些通用的方法是如何继承的呢?函数又是怎么创建出来的呢?试想想,一切皆对象,包括函数也是对象,而且是通过构造函数构造出来的对象。那么根据上面第二条事实,每个函数也会有_proto_指向它的构造函数的prototype。而这个构造函数的函数就是Function,JS中的所有函数都是由Function构造出来的。函数的通用属性与方法就存放在Function.prototype这个原型对象上。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

全面分析JavaScript面向对象概念中的Object类型与作用域(附有示例)

在javascript中创建对象的各种模式解析(图文教程)

详细解读JavaScript设计模式开发中的桥接模式(高级篇)

以上がJavaScriptによるプロトタイプの包括的な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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