定义一个类的一种方法是使用一个类声明。要声明一个类,你可以使用带有class关键字的类名(这里是“Rectangle”)。
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}函数声明和类声明之间的一个重要区别是函数声明会提升,类声明不会。
原型方法
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()实例属性的新写法
实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层。这时,不需要在实例属性前面加上this。
class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}对比
class IncreasingCounter {
_count = 0;
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}静态属性
静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。
// 老写法
class Foo {
// ...
}
Foo.prop = 1;
// 新写法
class Foo {
static prop = 1;
}老写法的静态属性定义在类的外部。整个类生成以后,再生成静态属性。
Class 的继承
Class 可以通过extends关键字实现继承,
class Point {
}
class ColorPoint extends Point {
}上面代码定义了一个ColorPoint类,该类通过extends关键字,继承了Point类的所有属性和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个Point类。下面,我们在ColorPoint内部加上代码。
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
意思是super()方法回调用父类的constructor但是this指的是子类的实例
原型链思想
类本质上是一个函数(构造函数),类的所有方法都定义在类的prototype属性上面。即实例的__proto__上面,构造函数的prototype属性,在 ES6 的“类”上面继续存在。
继承机制
ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。实例对象同时是ColorPoint和Point两个类的实例,这与 ES5 的行为完全一致。
super
第一种情况,作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错,作用是调用父类的constructor,但是父类的this指向子类的实例
第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。super === A.prototype
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p()); // 2
}
}类的 prototype 属性和__proto__属性
大多数浏览器的 ES5 实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。
(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。
(2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true A.prototype //里面都是A的方法实例的 __proto__ 属性
var p1 = new Point(2, 3);
var p2 = new ColorPoint(2, 3, 'red');
p2.__proto__.__proto__ === p1.__proto__ // true
B.prototype.__proto__ === A.prototype // true
两个道理是一样的