Class 的基本语法
简介
- ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到
- 定义类方法的时候前面不需要加 function 关键字,且方法之间不用加都好分隔
- 类的数据类型就是函数,类本身就是指向构造函数
class Point {
// ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true
- 使用的时候直接对类使用 new 命令
- 构造函数的 prototype 属性在类上面继续存在,事实上类的所有方法都定义在类的 prototype 上面 在类的实例上调用方法其实就是调用原型上的方法
class B {}
let b = new B();
b.constructor === B.prototype.constructor // true
- Object.assign 方法可以很方便地一次向类添加多个方法
class Point {
constructor(){
// ...
}
}
Object.assign(Point.prototype, {
toString(){},
toValue(){}
});
- 类 prototype 对象的 constructor 属性,直接指向“类”的本身
Point.prototype.constructor === Point // true
- 类的内部所有定义的方法,都是不可枚举的,这与 ES5 不一致
- 类和模块的内部,默认就是严格模式
constructor 方法
constructor 方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法。 如果没有显式定义,会默认添加一个空的 constructor 方法。constructor 方法默认返回实例对象(即 this )
类的实例对象
- 与 ES5 一样,实例的属性除非显式定义在其本身(即定义在 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
- 类的所有实例共享一个原型对象
var p1 = new Point(2,3);
var p2 = new Point(3,2);
p1.__proto__ === p2.__proto__
//true
- Object.getPrototypeOf 方法来获取实例对象的原型,然后再来为原型添加方法/属性
Class 表达式
- 与函数一样类也可以使用表达式形式定义
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
- 采用 Class 表达式,可以写出立即执行的 Class
let person = new class {}()
不存在变量提升
new Foo(); // ReferenceError
class Foo {}
私有方法
ES6 不提供私有方法,只能通过变通方法模拟实现
- 在命名上加以区别
// 私有方法
_bar(baz) {
return this.snaf = baz;
}
- 将私有方法移出模块
class Widget {
foo (baz) {
bar.call(this, baz);
}
}
function bar(baz) {
return this.snaf = baz;
}
- 利用 Symbol 值的唯一性,将私有方法的名字命名为一个 Symbol 值
this 的指向
类的方法内部如果含有 this ,它默认指向类的实例
Class 的取值函数(getter)和存值函数(setter)
与 ES5 一样,在“类”的内部可以使用 get 和 set 关键字,对某个属性设置存值 函数和取值函数,拦截该属性的存取行为。
Class 的静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前, 加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
- 如果静态方法包含 this 关键字,这个 this 指的是类,而不是实例
class Foo {
static bar () {
this.baz();
}
static baz () {
console.log('hello');
}
baz () {
console.log('world');
}
}
Foo.bar() // hello
- 父类的静态方法,可以被子类继承
Class 的静态属性和实例属性
静态属性指的是 Class 本身的属性,即 Class.propName ,而不是定义在实例对 象( this )上的属性。目前有一个静态属性的提案,对实例属性和静态属性都规定了新的写法。
- 类的实例属性
class MyClass {
myProp = 42
}
- 类的静态属性
class MyClass {
static myProp = 42
}
new.target 属性
该属性一般用在构造函数中,返回 new 命令作用的那个构造函数,如果构造函数不是通过 new 命令调用的会返回 undefined Class 内部调用 new.target 返回当前 Class,子类继承父类时会返回子类
Class 的继承
简介
Class 可以通过 extends 关键字实现继承。
子类必须在 constructor 方法中调用 super 方法,否则在新建实例时会报错。这是因为子类没有自己的 this 对象 而是继承父类的 this 对象。
ES6 的继承机制实质是先创造父类的实例对象 this (所以必须先调用 super 方法),然后再用子类的构造函数修改 this 。
如果子类没有定义 constructor 方法,会被默认添加并调用 super 方法
super 关键字
既可以当作函数使用也可以当作对象使用
- 当作函数调用时,代表父类的构造函数,只能用在子类的构造函数中
- 当作对象时,在普通当法中只想父类的原型对象,在静态方法中指向父类