JSオブジェクト向けプログラミング——ES 6におけるclassの継承用法の詳細

9977 ワード

この例では,ES 6におけるclassの継承用法について述べる.皆さんの参考にしてください.具体的には以下の通りです.
JSはオブジェクトベースの言語で、オブジェクト向けを実現するには、伝統的なオブジェクト向けと書き方が大きく異なります.ES 6はClass構文糖を導入し,JSの継承を対象言語向けの書き方に似せる.
このブログは、基本的な紹介、Vueの使用例に分かれています.
基本的な紹介
Classはextendsキーワードで継承を実現することができ、これはES 5のプロトタイプチェーンを修正することによって継承を実現するよりも、明確で便利である.

class Father {
 }
class Son extends Father {
}

コードは1つのSonクラスを定義して、このクラスはextendsキーワードを通じて、Fatherクラスのすべての属性と方法を継承して、しかしいかなるコードを配置していないため、この2つのクラスは完全に同じで、1つのFatherクラスを複製したことに等しい.

class Son extends Father {
     constructor (name,age,city) {
        super(name,age);//     constructor(name,age);
        this.city = city;
      }
 
      toString () { 
         return this.city+ " " +super.toString();//     toString()
      }
}

constructorメソッドとtoStringメソッドには、親の構造関数を表し、親のthisオブジェクトを新規作成するsuperキーワードが表示されます.
サブクラスはconstructorメソッドでsuperメソッドを呼び出さなければなりません.そうしないと、インスタンスを新規作成するときにエラーが発生します.これは、サブクラスに独自のthisオブジェクトがなく、親クラスのthisオブジェクトを継承し、加工します.superメソッドを呼び出さないと、サブクラスはthisオブジェクトを取得できません.

class Father {  }
 
class Son extends Father {
     constructor(){ }
}
let s = new Son();
//referenceError : this is not defined 

Sonは親Fathermを継承したが、彼の構造関数はsuperメソッドを呼び出さず、新しいインスタンスタイムズが間違っていた.ES 5の継承は、本質的にはサブクラスのインスタンスオブジェクトthisを先に作成し、次に親クラスのメソッドをthisに追加します(Parent.apply(this))ES 6の継承メカニズムはまったく異なり、実質的には親クラスのインスタンスオブジェクトthisを先に作成します(したがってsuperメソッドを呼び出す必要があります)、その後、サブクラスの構造関数でthisを変更します.サブクラスにconstructorメソッドが定義されていない場合、このメソッドはデフォルトで追加されます.すなわち、明示的な定義があるかどうかにかかわらず、どのサブクラスにもconstructorメソッドがあります.

class Son extends Father {
}
 
//   
class Son extends Parent {
    constructor(...args) {
    super(...args);
   }
}

もう1つ注意しなければならないのは、サブクラスのコンストラクション関数でsuperが呼び出された後にのみthisキーワードが使用されます.そうしないと、エラーが表示されます.これは、サブクラスインスタンスの構築が、親インスタンスの加工に基づいており、superメソッドのみが親インスタンスを返すことができるためです.

class Father {
   constructor (x,y) {
      this.x= x;
      this.y = y;
    }
}
 
class Son extends Father {
   constructor (x, y, color) {
       this.color =color ;//ReferenceError : this is not defined
      super(x,y);
       this.color = color;//  
      }
}
 
let s = new Son(25,8,"green");
s instanceof Son //true 
s instanceof Father //true

サブクラスのconstructorメソッドはsuperを呼び出す前にthisキーワードを使用し、結果は間違っていますが、superメソッドの後に置くのが正しいです.
Object.getPrototypeOf()メソッドは、子クラスから親クラスを取得するために使用されます.

Object.getPrototypeOf( Son ) ===Father
//true
//           ,           

superキーワードsuperというキーワードは、関数としてもオブジェクトとしても使用できます.(1)第一に、superが関数呼び出しとして使用される場合、親を表す構造関数、ES 6は、サブクラスの構造関数がsuper関数を実行しなければならないことを要求します.

class Father { }
 
class Son extends Father {
    constructor () {
          super();
       }
}
//  Son        super(),           。     ,   JavaScript      。

superは親Fatherのコンストラクション関数を表すが、サブクラスSonの例、すなわちsuper内部のthisがSonを指すので、super()はここでFatherに相当する.constructor.call(this); また、関数としてsuper()はサブクラスの構造関数にしか使用できず、他の場所でエラーが報告されます.

class A {
     constructor (){
        console.log(new.target.name);
      }
 }
 
class B extends A {
   constructor () {
      super();
      }
 }
  new A()//A
 new B()//B 

new.targetは現在実行中の関数を指し、super()が実行されると、親Aの構造関数ではなくサブクラスBの構造関数を指し、super()内部のthisはBを指す.
(2)2つ目の場合,superがオブジェクトである場合,通常のメソッドでは親のプロトタイプオブジェクトを指し,静的メソッドでは親を指す.

class Father{
   getName ( ) {
     return "MGT360124";
   }
}
class Son extends Father {
    constructor () {
    super();
    console.log(super.getName() ) //“MGT360124”
    }
}
let s = new Son();

サブクラスSonのsuper.p()は、superを1つのオブジェクトとして使用する場合、superは通常の方法でFatherを指す.だから...getName()はFatherに相当します.prototype.getName();//「MGT 360124」は、superが親のプロトタイプオブジェクトを指すため、親インスタンスに定義されたメソッドまたは属性は、superによって呼び出されない.

class Father {
   constructor () {
       this.p =2
     }
}
 
class Son extends Father {
     get m ( ) {
          return super.p;
     }
     getValue ( ) {
          return super.a;
      }
}
let s = new Son();
s.m
//undefined

pは親Fatherインスタンスのプロパティ、super.pはそれを参照できません
属性が親クラスのプロトタイプオブジェクトに定義されている場合、superは取得できます.

class A {}
A.prototype.x = 2;
 
class B extends A {
 constructor() {
  super();
  console.log(super.x) // 2
 }
}
 
let b = new B();

属性xはA.prototypeの上に定義されているのでsuper.xはその値を取得できます.
ES 6では、superによって親クラスのメソッドが呼び出されると、superは子クラスのthisをバインドすることを規定している.

class Father {
   constructor () {
      this.x =1;//  this    Father     
   }
   print () {
      console.log(this.x);
   }
}
 
class Son extends Father {
   constructor () {
       super();
        this.x = 2;//  this    Son     
   }
     m() {
      super.print();    
     }
}
let s = new Son();
s.m();
//2 

super.print()はFatherを呼び出したが.prototype.だが...prototype.print()はサブクラスSonのthisをバインドし、1ではなく2を出力します.つまり、実際にはsuperが実行されます.print.call(this).
superがオブジェクトとして静的メソッドで使用される場合、superは親のプロトタイプオブジェクトではなく親を指します.

class Parent {
      static myMethod (msg) {
           console.log("static",msg);
        }
      myMethod (msg) {
          console.log("instance" ,msg);
        }
}
 
class Child extends Parent {
     static myMethod(msg) {
        super.myMethod(msg);
     }
      myMethod (msg) {
      super.myMethod(msg);
      }
 }
 
Child.myMethod(1);
//static 1
var child = new Child();
child.myMethod(2);
//instance 2

superは静的メソッドでは親を指し,通常のメソッドでは親のプロトタイプオブジェクトを指す.superを使用する場合は、関数として使用するか、オブジェクトとして使用するかを明示的に指定する必要があります.そうしないと、エラーが発生します.クラスのprototypeプロパティとprotoプロパティほとんどのブラウザのES 5実装では、各オブジェクトにprotoプロパティがあり、対応するコンストラクション関数のprototypeプロパティを指し、classはコンストラクション関数の構文糖として、prototypeプロパティとprotoプロパティが同時に存在するため、2つの継承チェーンが同時に存在する.(1)子クラスのproto属性は,構造関数の継承を表し,常に親クラスを指す.(2)サブクラスprototype属性のproto属性は、メソッドの継承を表し、常に親クラスのprototype属性を指す.

class A{
}
class B{
}
//B     A   
Object.setPrototypeOf(B.prototype, A.prototype);
 
//B      A     
Object.setPrototypeOf(B,A);
 
const b = new B();

『オブジェクトの拡張』1章Object.setPrototypeOf()メソッドの実装:

Object.setPrototypeOf = function (obj, proto) {
obj.__proto__ = proto;
  return obj ;
}

したがって

Object.setPrototypeOf( B.prototype , A.prototype );
//   
B.prototype.__proto__ = A.prototype ;
 
Object.setPrototypeOf(B, A);
//   
B.__proto__ = A;

この2つの継承チェーンは、1つのオブジェクトとして、サブクラスBのプロトタイプ(proto属性)が親(A)であると理解できる.コンストラクション関数として、サブクラスBのプロトタイプオブジェクト(prototypeプロパティ)は、親クラスのプロトタイプオブジェクト(prototype)のインスタンスである.
extendsの継承ターゲットextendsキーワードの後ろには多くのタイプの値が付いています.

class B extends A{
}

Aにprototype属性の関数が1つあればBに継承され、関数にはprototype属性(Function.prototype関数を除く)があるため、Aは任意の関数を使用することができ、以下の3つのケース:(1)サブクラスがObjectクラスを継承する

class A extends Object {
}
A.__proto__ === Object //true;
A.prototype.__proto__ === Object.prototype //true

この場合,Aはコンストラクション関数Objectのコピーであり,AのインスタンスはObjectのインスタンス(2)に継承は存在しない.

class A {
}
A.__proto__ === Function.prototype //true
A.prototype.__proto__ = Object.prototype //true

この場合、Aはベースクラス(継承は存在しない)として一般的な関数であるため、Functionを直接継承する.prototype.ただし、A呼び出し後に空のオブジェクト(すなわちObjectインスタンス)が返されるので、A.prototype.protoは構造関数(Object)のprototype属性を指す.インスタンスのprotoプロパティサブクラスインスタンスのprotoプロパティのprotoプロパティ.親インスタンスのprotoプロパティを指します.すなわち,子類の原型の原型は,親類の原型である.
オリジナルコンストラクション関数の継承オリジナルコンストラクション関数とは、言語に組み込まれたコンストラクション関数であり、通常、データ構造を生成するために使用されます.

Boolean()
Number()
String()
Array()
Date()
Function()
RegExp()
Error()
Object()

extendsキーワードはクラスを継承するだけでなく、元の構造関数を継承するためにも使用できます.したがって,オリジナルデータ構造に基づいて,独自のデータ構造を定義することができる.
vue使用
testClass.js

//   
class Person{ 
	//    
	constructor(x,y){ 
		this.x = x; 
		this.y = y; 
	} 
 
  //             function
	toString(){ 
		return (this.x + "    " +this.y+" "); 
	} 
} 
export {
	Person
}; 

test.vue



import {Person} from './testClass.js'; 
export default {  
	data() {
		return {
		}
	},
	mounted(){
		let text=document.getElementById("testJs");
		//  new           
		let person = new Person('  ',12); 
		text.innerHTML=person.toString();//      12 
		console.log(typeof Person);//function 
	}
}


興味のある方は、オンラインHTML/CSS/JavaScriptコードを使用してツールを実行できます.http://tools.jb51.net/code/HtmlJsRun上記のコードの実行効果をテストします.
JavaScriptに関する詳細について興味のある読者は、「javascriptオブジェクト向け入門チュートリアル」、「JavaScriptエラーとデバッグテクニックのまとめ」、「JavaScriptデータ構造とアルゴリズムテクニックのまとめ」、「JavaScript遍歴アルゴリズムとテクニックのまとめ」、「JavaScript数学演算の使い方のまとめ」を参照してください.
JavaScriptプログラムの設計に役立つことを願っています.