1 Class 的基本语法
let methodName = 'getArea';
class MyClass {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
[methodName]() {
// ...
}
get prop() {
return 'getter';
}
set prop(value) {
console.log('setter: '+value);
}
}
// 报错
var point = Point(2, 3);
// 正确
var point = new Point(2, 3);
constructor
类的数据类型就是函数,类本身就指向构造函数。
类相当于实例的原型。
实例属性this._count定义在constructor()方法里面。另一种写法是,这个属性也可以定义在类的最顶层,其他都不变。
静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。写法是在实例属性的前面,加上static关键字。
Point === Point.prototype.constructor // true
this指向
在构造方法中绑定this,这样就不会找不到方法了。
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
// ...
}
另一种解决方法是使用箭头函数。箭头函数内部的this总是指向定义时所在的对象。
class Obj {
constructor() {
this.getThis = () => this;
}
}
const myObj = new Obj();
myObj.getThis() === myObj // true
方法
类的方法都定义在prototype对象上面。
Object.assign方法可以很方便地一次向类添加多个方法。
Object.assign(Point.prototype, {
toString(){},
toValue(){}
});
类的内部所有定义的方法,都是不可枚举的(non-enumerable)。
属性表达式:使用 [ ] 即可
getter和setter
在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
类的实例
如果忘记加上new,像函数那样调用Class,将会报错。
class 表达式
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
上面代码使用表达式定义了一个类。需要注意的是,这个类的名字是Me,但是Me只在 Class 的内部可用,指代当前类。在 Class 外部,这个类只能用MyClass引用。
如果类的内部没用到的话,可以省略Me。
其他
- 不存在提升
- 都是严格模式
- name属性
静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
如果静态方法包含this关键字,这个this指的是类,而不是实例。
静态方法可以与非静态方法重名。
父类的静态方法,可以被子类继承。
借助babal研究类的实现
转换前:
class Parent {
constructor(a){
this.filed1 = a;
}
filed2 = 2;
func1 = function(){}
}
转换后:
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Parent = function Parent(a) {
_classCallCheck(this, Parent);
this.filed2 = 2;
this.func1 = function () { };
this.filed1 = a;
};
class的底层依然是构造函数。
2 Class 的继承
ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
super方法
子类必须在constructor方法中调用super方法,否则新建实例时会报错。
实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
super对象
在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
获取父类
Object.getPrototypeOf方法可以用来从子类上获取父类。
类的 prototype 属性和__proto__属性
Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。
子类的__proto__属性,表示构造函数的继承,总是指向父类。
子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
继承的实现
转换前:
class Child extends Parent {
constructor(a,b) {
super(a);
this.filed3 = b;
}
filed4 = 1;
func2 = function(){}
}
转换后:
Child的实现:
var Child = function (_Parent) {
_inherits(Child, _Parent);
function Child(a, b) {
_classCallCheck(this, Child);
var _this = _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, a));
_this.filed4 = 1;
_this.func2 = function () {};
_this.filed3 = b;
return _this;
}
return Child;
}(Parent);
es6实际上是为我们提供了一个“组合寄生继承”的简单写法。
参考文章:
- https://segmentfault.com/a/1190000017816134
- https://es6.ruanyifeng.com/#docs/class