ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript がプロトタイプ チェーンを使用して継承メソッドを実装する方法の概要

JavaScript がプロトタイプ チェーンを使用して継承メソッドを実装する方法の概要

伊谢尔伦
伊谢尔伦オリジナル
2017-07-25 16:08:001355ブラウズ

JavaScript 自体はオブジェクト指向言語ではなく、オブジェクトベースの言語です。他の OO 言語に慣れている人にとって、ここには「クラス」という概念がないため、最初は少し不快に感じます。 class" と " "親クラス" と "サブクラス" はおろか、"インスタンス" の間にも区別はありません。では、JavaScript のこれらのオブジェクトはどのようにして接続されているのでしょうか?

幸いなことに、JavaScript は設計の最初から「継承」の実装を提供しています。「継承」を理解する前に、まずプロトタイプ チェーンの概念を理解しましょう。

プロトタイプチェーン

具体的なコードは次のとおりです:


  function SuperClass(){
    this.name = "women"
  }
  SuperClass.prototype.sayWhat = function(){
    return this.name + ":i`m a girl!";
  }
  function SubClass(){
    this.subname = "your sister";
  }
  SubClass.prototype = new SuperClass();
  SubClass.prototype.subSayWhat = function(){
    return this.subname + ":i`m a beautiful girl";
  }
  var sub = new SubClass();
  console.log(sub.sayWhat());//women:i`m a girl!

プロトタイプチェーンを使用して継承を実装します

上記のコードから、サブクラスがスーパークラスのプロパティとメソッドを継承していることがわかります。この継承の実装は、SuperClass のインスタンスを SubClass のプロトタイプ オブジェクトに割り当てることで行われます。これにより、SubClass のプロトタイプ オブジェクトは SuperClass のインスタンスによって上書きされ、そのすべてのプロパティとメソッドが保持され、SuperClass プロトタイプへのポインタも保持されます。物体。

プロトタイプ チェーンを使用して継承を実装する場合は、注意する必要があることがいくつかあります。

継承後のコンストラクターの変更に注意してください。 SubClass のプロトタイプが SuperClass のプロトタイプを指すため、ここでの sub のコンストラクターは SuperClass を指します。プロトタイプ チェーンを理解するときは、最後にあるデフォルトの Object オブジェクトを無視しないでください。これが、すべてのオブジェクトで toString などの組み込みメソッドを使用できる理由です。

プロトタイプチェーンを介して継承を実装する場合、リテラルを使用してプロトタイプメソッドを定義することはできません。これは、プロトタイプオブジェクトをオーバーライドするためです:


  function SuperClass(){
    this.name = "women"
  }
  SuperClass.prototype.sayWhat = function(){
    return this.name + ":i`m a girl!";
  }
  function SubClass(){
    this.subname = "your sister";
  }
  SubClass.prototype = new SuperClass();
  SubClass.prototype = {//此处原型对象被覆盖,因为无法继承SuperClass属性和方法
    subSayWhat:function(){
      return this.subname + ":i`m a beautiful girl";
    }
  }
  var sub = new SubClass();
  console.log(sub.sayWhat());//TypeError: undefined is not a function

インスタンス共有の問題。前にプロトタイプとコンストラクターを説明したときに、参照型属性を含むプロトタイプはすべてのインスタンスで共有されることを紹介しました。同様に、参照を変更した後、継承するプロトタイプも「親クラス」プロトタイプの参照型属性を共有します。プロトタイプの継承を通じて「親クラス」の type 属性が変更されると、プロトタイプから継承された他のすべてのインスタンスが影響を受けます。これはリソースの無駄であるだけでなく、見たくない現象でもあります。
注: ここで要素が配列に追加されると、SuperClass から継承されたすべてのインスタンスが影響を受けますが、name 属性が変更されても、他のインスタンスには影響しません。これは、配列が参照型であり、名前が であるためです。基本的なタイプ。

インスタンス共有の問題を解決するにはどうすればよいですか?見下ろしてみましょう...


古典的な継承 (コンストラクターの盗用)


オブジェクトを定義するためにプロトタイプが単独で使用されることはほとんどないと紹介しましたが、実際の開発では、参照型を解決するためにプロトタイプ チェーンを単独で使用することはほとんどありません。共有の問題を解決するために、JavaScript 開発者は古典的な継承パターン (借用コンストラクター継承とも呼ばれます) を導入しました。その実装は、サブタイプ コンストラクターでスーパータイプ コンストラクターを呼び出すだけです。 JavaScript によって提供される call() または apply() 関数を使用する必要があります。例を見てみましょう。 この文は、インスタンス (context) で呼び出されることを意味します。 ) サブクラスの環境 スーパークラス コンストラクターの初期化作業により、各インスタンスが相互に影響を与えることなく bra 属性の独自のコピーを持つようになります。

ただし、この実装はまだ完全ではありません。コンストラクターが導入されたため、前の記事で説明したコンストラクターの問題にも直面します。コンストラクターにメソッド定義がある場合、各インスタンスにはメソッド定義がありません。私たちの目的はこのメソッドを共有することであり、スーパータイプ プロトタイプで定義したメソッドをサブタイプ インスタンスで呼び出すことはできません:

  function SuperClass(){
    this.name = "women";
    this.bra = ["a","b"];
  }
  function SubClass(){
    this.subname = "your sister";
  }
  SubClass.prototype = new SuperClass();
  var sub1 = new SubClass();
  sub1.name = "man";
  sub1.bra.push("c");
  console.log(sub1.name);//man
  console.log(sub1.bra);//["a","b","c"]
  var sub2 = new SubClass();
  console.log(sub1.name);//woman
  console.log(sub2.bra);//["a","b","c"]

組み合わせ 式の継承

組み合わせ継承は、利点を組み合わせる方法です。プロトタイプチェーンとコンストラクターのそれぞれの強みを生かして組み合わせて継承を実現するということです。簡単に言うと、プロトタイプチェーンを使用してプロパティとメソッドを継承し、借用したコンストラクターを使用してインスタンスの継承を実現します。これにより、インスタンス属性の共有の問題が解決されますが、スーパータイプの属性とメソッドの継承も可能になります。


function SuperClass() {
  this.name = "women";
  this.bra = ["a", "b"];
}
function SubClass() {
  this.subname = "your sister";
  //将SuperClass的作用域赋予当前构造函数,实现继承
  SuperClass.call(this);
}

var sub1 = new SubClass();
sub1.bra.push("c");
console.log(sub1.bra);//["a","b","c"]
var sub2 = new SubClass();
console.log(sub2.bra);//["a","b"]

結合継承の方法は、これまでのところ、実際の開発で継承を実装するために最も一般的に使用されている方法でもあります。実際の開発ニーズはすでに満たしていますが、人々の完璧さの追求には終わりがないため、必然的にこのモデルについて「細かい点にうるさい」人もいるでしょう。モデルはスーパータイプ コンストラクターを 2 回呼び出しています。 2回。 。 。 100倍に拡大するとパフォーマンスが低下すると思いますか?

最も強力な反論は、解決策を考え出すことです。幸いなことに、開発者はこの問題に対する最良の解決策を見つけました:

寄生結合継承

この継承方法を紹介する前に、まず寄生コンストラクターの概念を理解しましょう。寄生コンストラクターは、前述のファクトリ パターンに似ています。この関数は、オブジェクトの作成が完了した後に返されるパブリック関数を定義することに非常に似ています。コンストラクターですが、コンストラクター関数には戻り値がありません:


function Gf(name,bra){
  var obj = new Object();
  obj.name = name;
  obj.bra = bra;
  obj.sayWhat = function(){
    console.log(this.name);
  }
  return obj;
}

var gf1 = new Gf("bingbing","c++");
console.log(gf1.sayWhat());//bingbing

寄生式继承的实现和寄生式构造函数类似,创建一个不依赖于具体类型的“工厂”函数,专门来处理对象的继承过程,然后返回继承后的对象实例,幸运的是这个不需要我们自己实现,道哥(道格拉斯)早已为我们提供了一种实现方式:


function object(obj) {
  function F() {}
  F.prototype = obj;
  return new F();
}
var superClass = {
  name:"bingbing",
  bra:"c++"
}
var subClass = object(superClass);
console.log(subClass.name);//bingbing

在公共函数中提供了一个简单的构造函数,然后将传进来对象的实例赋予构造函数的原型对象,最后返回该构造函数的实例,很简单,但疗效很好,不是吗?这个方式被后人称为“原型式继承”,而寄生式继承正是在原型式基础上,通过增强对象的自定义属性实现的:


function buildObj(obj){
  var o = object(obj);
  o.sayWhat = function(){
    console.log("hello");
  }
  return o;
}
var superClass = {
  name:"bingbing",
  bra:"c++"
}
var gf = buildObj(superClass);
gf.sayWhat();//hello

寄生式继承方式同样面临着原型中函数复用的问题,于是,人们又开始拼起了积木,诞生了——寄生组合式继承,目的是解决在指定子类型原型时调用父类型构造函数的问题,同时,达到函数的最大化复用。基于以上基础实现方式如下:


//参数为两个构造函数
function inheritObj(sub,sup){
  //实现实例继承,获取超类型的一个副本
  var proto = object(sup.prototype);
  //重新指定proto实例的constructor属性
  proto.constructor = sub;
  //将创建的对象赋值给子类型的原型
  sub.prototype = proto;
}
function SuperClass() {
  this.name = "women";
  this.bra = ["a", "b"];
}
SuperClass.prototype.sayWhat = function() {
  console.log("hello");
}

function SubClass() {
  this.subname = "your sister";
  SuperClass.call(this);
}
inheritObj(SubClass,SuperClass);
var sub1 = new SubClass();
console.log(sub1.sayWhat()); //hello

这个实现方式避免了超类型的两次调用,而且也省掉了SubClass.prototype上不必要的属性,同时还保持了原型链。

以上がJavaScript がプロトタイプ チェーンを使用して継承メソッドを実装する方法の概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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