ES 6クラスベース
概要
ES 6のclassはただ1つの文法糖で、完全に構造関数の別の書き方と見なすことができて、ES 5の構造関数はES 6の構造方法に対応します
class Point {
// ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true
コンストラクション関数のprototypeプロパティは、ES 6の「クラス」の上に引き続き存在します.実際、クラスのすべてのメソッドはクラスのprototypeプロパティに定義されています.
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
//
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
クラスのメソッドはprototypeオブジェクトの上に定義ため、クラスの新しいメソッドはprototypeオブジェクトの上に追加することができ、Object.assignメソッドは、クラスに複数のメソッドを一度に追加するのに便利です.
class Point {
constructor(){
// ...
}
}
Object.assign(Point.prototype, {
toString(){},
toValue(){}
});
prototypeオブジェクトのconstructorプロパティは、ES 5の動作と一致する「クラス」そのものを直接指します.
Point.prototype.constructor === Point // true
クラスの内部のすべての定義方法は,ES 5の挙動と一致しない枚挙にいとまがない.
class Point {
constructor(x, y) {
// ...
}
toString() {
// ...
}
}
Object.keys(Point.prototype)
// []
Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]
クラスのプロパティ名、式を使用できます
/*
,
Square getArea,
*/
let methodName = 'getArea';
class Square {
constructor(length) {
// ...
}
[methodName]() {
// ...
}
}
console.log(Square.prototype)
厳格モード
クラスとモジュールの内部は、デフォルトでは厳格なモードなので、use strictを使用して実行モードを指定する必要はありません.クラスまたはモジュールにコードが書かれている限り、厳格なモードしか使用できません.
constructorメソッド
class Foo {
constructor() {
return Object.create(null);
}
}
new Foo() instanceof Foo
クラスはnew呼び出しを使用する必要があります.そうしないと、エラーが発生します.これは通常の構造関数との主な違いであり、後者はnewを使わずに実行することができる.
class Foo {
constructor() {
return Object.create(null);
}
}
Foo()
// TypeError: Class constructor Foo cannot be invoked without 'new'
クラスのインスタンスオブジェクト
インスタンスのプロパティは、明示的に定義されていない限り(thisオブジェクトに定義されている)、プロトタイプに定義されています(classに定義されています).
//
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var point = new Point(2, 3);
point.toString() // (2, 3)
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
上記のコードでは、xとyはインスタンスオブジェクトpoint自身の属性(this変数に定義されているため)であるため、hasOwnPropertyメソッドはtrueを返し、toStringはPointクラスに定義されているため、hasOwnPropertyメソッドはfalseを返し、これらはES 5の動作と一致している
protoは言語そのものの特性ではなく、これは各メーカーが具体的に実装する際に追加したプライベート属性であり、現在多くの現代ブラウザのJSエンジンでこのプライベート属性が提供されているが、生産でこの属性を使用することを提案せず、環境への依存を避ける.生産環境ではObjectを使用できます.getPrototypeOfメソッドは、インスタンスオブジェクトのプロトタイプを取得し、プロトタイプにメソッド/プロパティを追加します.
var p1 = new Point(2,3);
var p2 = new Point(3,2);
p1.__proto__.printName = function () { return 'Oops' };
p1.printName() // "Oops"
p2.printName() // "Oops"
var p3 = new Point(4,2);
p3.printName() // "Oops"
使用例の__proto__プロパティはプロトタイプを書き換えるには、クラスの元の定義を変更し、すべてのインスタンスに影響を与えるため、使用を推奨しない必要があります.
Class式
関数と同様に、クラスは式の形式で定義することもできます.
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
上記のコードは、式を使用してクラスを定義します.なお、このクラスの名前はMeではなくMyClassであり、MeはClassの内部コードのみで使用でき、現在のクラスを指す
let inst = new MyClass();
inst.getClassName() // Me
Me.name // ReferenceError: Me is not defined
変数リフトは存在しません
クラスに変数のアップグレードは存在しません.これはES 5とは全く違います.
new Foo(); // ReferenceError
class Foo {}
上のコードでは、Fooクラスは前に使用され、後に定義されています.ES 6はクラスの宣言をコードヘッダに昇格させないため、エラーが発生します.
プライベートメソッド
1つの方法は、モジュール内部のすべての方法が外部に見られるため、プライベートメソッドをモジュールからいっそ削除することです.
class Widget {
foo (baz) {
bar.call(this, baz);
}
// ...
}
function bar(baz) {
return this.snaf = baz;
}
上のコードではfooは共通の方法で、内部でbarが呼び出されています.call(this, baz).これによりbarは実際には現在のモジュールのプライベートメソッドとなっている.
もう1つの方法は、Symbol値の一意性を利用して、プライベートメソッドの名前をSymbol値と命名することです.
const bar = Symbol('bar');
const snaf = Symbol('snaf');
export default class myClass{
//
foo(baz) {
this[bar](baz);
}
//
[bar](baz) {
return this[snaf] = baz;
}
// ...
};
上記のコードではbarとsnafがSymbol値であり、サードパーティが取得できないため、プライベートメソッドとプライベートプロパティの効果が得られます.
プライベート属性
プライベートメソッドと同様に、ES 6はプライベート属性をサポートしません.現在、classにプライベート属性を追加する提案があります.メソッドは、属性名の前に#を使用して表示します.
nameプロパティ
本質的には、ES 6のクラスはES 5の構造関数のパッケージにすぎないため、関数の多くの特性はClassによって継承され、name属性が含まれ、name属性は常にclassキーワードの後ろに続くクラス名を返す.
class Point {}
Point.name // "Point"
Classの値取り関数(getter)と保存関数(setter)
class CustomHTMLElement {
constructor(element) {
this.element = element;
}
get html() {
return this.element.innerHTML;
}
set html(value) {
this.element.innerHTML = value;
}
}
var descriptor = Object.getOwnPropertyDescriptor(
CustomHTMLElement.prototype, "html"
);
"get" in descriptor // true
"set" in descriptor // true
Classの静的アプローチ
クラスはインスタンスのプロトタイプに相当し、クラスで定義されたすべてのメソッドはインスタンスによって継承されます.1つのメソッドの前にstaticキーを付けると、そのメソッドはインスタンスに継承されず、クラスによって直接呼び出されることを示します.これを「静的メソッド」と呼びます.
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
上記のコードでは、FooクラスのclassMethodメソッドの前にstaticキーワードがあり、このメソッドがFooクラスのインスタンスではなく、Fooクラスで直接呼び出すことができる静的メソッドであることを示しています.インスタンスで静的メソッドを呼び出すと、メソッドが存在しないことを示すエラーが投げ出されます.
静的メソッドにthisキーワードが含まれている場合、このthisはインスタンスではなくクラスを指します.
class Foo {
static bar () {
this.baz();
}
static baz () {
console.log('hello');
}
baz () {
console.log('world');
}
}
Foo.bar() // hello
上記のコードでは、静的メソッドbarがthisを呼び出す.baz、ここでthisはFooのインスタンスではなくFooクラスを指し、Fooを呼び出すのと同じである.baz.また,この例から,静的手法は非静的手法と再名できることも分かる.
静的メソッドもsuperオブジェクトから呼び出すことができます.
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
static classMethod() {
return super.classMethod() + ', too';
}
}
Bar.classMethod() // "hello, too"
class Foo { static classMethod() {
return 'hello';
}}
class Bar extends Foo { static classMethod() {
return super.classMethod() + ', too';
}}
Bar.classMethod()//"hello, too"
Classの静的属性
静的属性とは、Class自体の属性であるClassを指す.インスタンスオブジェクト(this)に定義された属性ではなくpropName
class Foo {
}
Foo.prop = 1;
Foo.prop // 1
new.targetプロパティ
newは、コンストラクション関数からインスタンスオブジェクトを生成するコマンドです.ES 6はnewコマンドにnewを導入する.targetプロパティ.このプロパティは一般的にコンストラクション関数で使用され、newコマンドが作用するコンストラクション関数を返します.コンストラクション関数がnewコマンドで呼び出されない場合、new.targetはundefinedを返します.したがって、このプロパティは、コンストラクション関数がどのように呼び出されるかを決定するために使用できます.
function Person(name) {
if (new.target !== undefined) {
this.name = name;
} else {
throw new Error(' new ');
}
}
//
function Person(name) {
if (new.target === Person) {
this.name = name;
} else {
throw new Error(' new ');
}
}
var person = new Person(' '); //
var notAPerson = Person.call(person, ' '); //
子クラスが親クラスを継承する場合new.targetはサブクラスを返します
class Rectangle {
constructor(length, width) {
console.log(new.target === Rectangle);
// ...
}
}
class Square extends Rectangle {
constructor(length) {
super(length, length);
}
}
var obj = new Square(3); // false
この特徴を利用して,独立して使用できない,継承しなければ使用できないクラス(抽象クラス)を書くことができる.
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error(' ');
}
}
}
class Rectangle extends Shape {
constructor(length, width) {
super();
// ...
}
}
var x = new Shape(); //
var y = new Rectangle(3, 4); //