JS継承(ES 5の4つの方式、ES 6と2つの違い)

7488 ワード

一、ES 6以前の継承
来た:https://www.jianshu.com/p/5cb692658704
プロトタイプの割り当て方式
簡単に言えば、父親の一例を直接にサブクラスの原型に与えます.以下の例を示します
function Person(name){
 this.name=name;
 this.className="person" 
}
Person.prototype.getClassName=function(){
 console.log(this.className)
}

function Man(){
}

Man.prototype=new Person();//1
//Man.prototype=new Person("Davin");//2
var man=new Man;
>man.getClassName()
>"person"
>man instanceof Person
>true
コードの1に示されているように、この方法は直接newである.親タイプの例を示して、サブタイプの原型を与える.これは、直接に親の原型の中の方法属性と、thisにかけられた各種の方法属性をサブタイプの原型に与えたものに相当し、簡単で乱暴です.マンを見に来ました.マン自体はget Class Name方法がないので、モデルチェーンに行って探します.見つけたのはpersonのget Class Nameです.このような継承方式では、すべてのサブクラスのインスタンスは、親タイプオブジェクトの一例を共有し、このようなスキームの最大の問題は、サブクラスが親タイプを通じてプライベート属性を作成できないことである.たとえばPersonには名前があります.それぞれのManを初期化するときには異なる名前を指定して、その名前を親に渡すという方法は、各マンにとっては、それぞれのpersonに保存されているnameが違っていますが、このような方法はまったくできません.ですから、この継承方式は、実戦ではほとんど使われません.
コンストラクタ方式を呼び出します.
function Person(name){
 this.name=name;
 this.className="person" 
}
Person.prototype.getName=function(){
 console.log(this.name)
}
function Man(name){
  Person.apply(this,arguments)
}
var man1=new Man("Davin");
var man2=new Man("Jack");
>man1.name
>"Davin"
>man2.name
>"Jack"
>man1.getName() //1   
>man1 instanceof Person
>true
ここでは、サブクラスの構造関数で、サブクラスのインスタンスのthisを使用して、親クラスの構造関数を呼び出して、親の属性を継承する効果があります.このように、new毎のサブクラスの例は、コンストラクタが実行された後、自分のリソースがあります.しかし、この方法は、父の構造関数によって宣言された例示的な属性のみを継承し、父のプロトタイプの属性と方法を継承していないので、get Name方法が見つからないので、1箇所はエラーを報告します.父種の原型を同時に継承するために、グループ継承方式が誕生しました.
グループ引継ぎ
function Person(name){
 this.name=name||"default name"; //1
 this.className="person" 
}
Person.prototype.getName=function(){
 console.log(this.name)
}
function Man(name){
  Person.apply(this,arguments)
}
//    
Man.prototype = new Person();
var man1=new Man("Davin");
> man1.name
>"Davin"
> man1.getName()
>"Davin"

この例は簡単で、構造関数の属性だけでなく、親のプロトタイプチェーンの属性もコピーされます.しかし、問題があります.Man.prototype = new Person();という文を実行した後、Manの原型は以下の通りです.
> Man.prototype
> {name: "default name", className: "person"}
つまりManのプロトタイプにはname属性があり、その後man 1を作成した時に構造の関数に伝達されるnameは、thisによって新たにname属性を定義したもので、プロトタイプを覆ったname属性に相当します.
分離グループ継承
これは現在のS 5の主流の継承方式で、一部の人は天を吊るして揚げた名前を「寄生組合相続」と名付けました.まず説明します.両者は同じことです.グループを分離して受け継ぐ名前は私がつけたので、1つは詰めないで少し良いと感じて、2は来て、更に適切です.以上のように、実は私達は相続を二段階に分けることができます.構造関数属性の継承と、サブクラスと親タイプのプロトタイプのリンクの確立です.分離とは二歩に分けて歩くことです.組み合わせとは、サブ構造関数とプロトタイプの属性を同時に継承することです.
function Person(name){
 this.name=name; //1
 this.className="person" 
}
Person.prototype.getName=function(){
 console.log(this.name)
}
function Man(name){
  Person.apply(this,arguments)
}
//    
Man.prototype = Object.create(Person.prototype);
var man1=new Man("Davin");
> man1.name
>"Davin"
> man1.getName()
>"Davin"
ここでは、Object.creat(obj)方法が用いられ、この方法は、入ってきたobjオブジェクトを浅いコピーする.上の組み合わせとの継承の主な違いは、親タイプの原型をサブタイプにコピーしたことです.このやり方ははっきりしています.
  • アーキテクチャー関数では、親の属性/方法を継承し、親のクラスを初期化する.
  • サブタイプの原型は親タイプの原型と関連しています.
  • もう一つの問題があります.つまりconstructorの属性です.見てみます.
    > Person.prototype.constructor
    < Person(name){
       this.name=name; //1
       this.className="person" 
     }
    > Man.prototype.constructor
    < Person(name){
       this.name=name; //1
       this.className="person" 
      }
    
    constructorはクラスのコンストラクタです.PersonとManのインスタンスのconstructorはPersonを指しています.もちろん、これはinstance ofの結果を変えません.しかし、constructorを使うシーンには問題があります.だから、私達は普通このように付け加えます.
    Man.prototype.constructor = Man
     
    二、ES 6類と継承
    来た:https://blog.csdn.net/qq_34645412/articale/detail/83584178?utm_source=ap
    まずコードを見ます
    class Person {
        constructor(name){
            console.log(`       ,${name}`)
        }
    }
    let p1= new Person('jona')
    ここでnewを呼び出すと自動的にコンストラクタが実行されますので、受信パラメータもコンストラクタから受信されます.
    class Person {
        constructor(name){
            console.log(`       ,${name}`)
            this.name=name
        }
        showName(){
            return `   ${this.name}`
        }
    }
    let p1= new Person('jona')
    console.log(p1.showName)
    この関数は自動的には実行されません.呼び出し時にのみ、consolie.log(p 1.showName)が実行されます.
    継承:
    //   
    class Person {
        constructor(name){
            console.log(`       ,${name}`)
            this.name=name
        }
        showName(){
            return `   ${this.name}`
        }
    }
    let p1= new Person('jona')
    console.log(p1.showName)
    //   
    class children  extends Person{
        constructor(agrs){
            super(ags) 
        }
     
     showName (){
            super.showName()//          super
        }
    }
    let p2 = new children('  ')
    console.log(p2.name)
    extensを継承するには、継承後にsuper()で父類のコンストラクタ構造関数を受信する必要がありますが、報告が間違っているかどうかは、newのサブクラスの場合は、まずパラメータをサブクラスのコンストラクタに導入してからsuper()で父類のコンストラクタを導入すると、父類を呼び出すことができます.
    三、ES 5/ES 6の継承は書き方以外に何の違いがありますか?
    来た:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/20 1.class 宣言はアップグレードされますが、割り当ては初期化されません.Foo 一時死区に入ると、似ています.  letconst 変数を宣言します
    const bar = new Bar(); // it's ok
    function Bar() {
      this.bar = 42;
    }
    
    const foo = new Foo(); // ReferenceError: Foo is not defined
    class Foo {
      constructor() {
        this.foo = 42;
      }
    }
    2.class 宣言の内部では、厳格なモードが有効になります.
    //           
    function Bar() {
      baz = 42; // it's ok
    }
    const bar = new Bar();
    
    class Foo {
      constructor() {
        fol = 42; // ReferenceError: fol is not defined
      }
    }
    const foo = new Foo();
     3.class 静的な方法と実例的な方法を含む全ての方法は列挙できない.
    //           
    function Bar() {
      this.bar = 42;
    }
    Bar.answer = function() {
      return 42;
    };
    Bar.prototype.print = function() {
      console.log(this.bar);
    };
    const barKeys = Object.keys(Bar); // ['answer']
    const barProtoKeys = Object.keys(Bar.prototype); // ['print']
    
    class Foo {
      constructor() {
        this.foo = 42;
      }
      static answer() {
        return 42;
      }
      print() {
        console.log(this.foo);
      }
    }
    const fooKeys = Object.keys(Foo); // []
    const fooProtoKeys = Object.keys(Foo.prototype); // []
     4.class のすべての方法(静的方法および例示的方法を含む)は、プロトタイプオブジェクトがないので、[[construct]]もなく、使用できません.  new を選択します
    function Bar() {
      this.bar = 42;
    }
    Bar.prototype.print = function() {
      console.log(this.bar);
    };
    
    const bar = new Bar();
    const barPrint = new bar.print(); // it's ok
    
    class Foo {
      constructor() {
        this.foo = 42;
      }
      print() {
        console.log(this.foo);
      }
    }
    const foo = new Foo();
    const fooPrint = new foo.print(); // TypeError: foo.print is not a constructor
     5.必ず使う  new 呼び出し  class
    function Bar() {
      this.bar = 42;
    }
    const bar = Bar(); // it's ok
    
    class Foo {
      constructor() {
        this.foo = 42;
      }
    }
    const foo = Foo(); // TypeError: Class constructor Foo cannot be invoked without 'new'
     6.class クラス名は内部では書き換えられません.
    function Bar() {
      Bar = 'Baz'; // it's ok
      this.bar = 42;
    }
    const bar = new Bar();
    // Bar: 'Baz'
    // bar: Bar {bar: 42}  
    
    class Foo {
      constructor() {
        this.foo = 42;
        Foo = 'Fol'; // TypeError: Assignment to constant variable
      }
    }
    const foo = new Foo();
    Foo = 'Fol'; // it's ok