讲一讲ES6中的类
下面讲一讲ES6引入的类
1 | class Point { |
上述代码中定义了一个类,constructor代表构造函数,上述还定义了一个toString()方法,前面不需要加上function这个关键字,另外,方法与方法之间不需要逗号分隔,加了会报错。
1 | const p = new Point(); |
使用时与构造函数用法无异。
另,注意,类中的方法都是不可枚举的,例如下面代码
1 | Object.keys(Point.prototype) |
而如果采用ES5写法,则是可枚举的
constructor()方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
我们也可在类中对某个属性设置存值函数和取值函数
1 | class Point { |
另,如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。
补充知识:
Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。
1 | function* gen(x){ |
1 | var g = gen(1); |
上面代码中,调用 Generator 函数,会返回一个内部指针(即遍历器 )g 。这是 Generator 函数不同于普通函数的另一个地方,即执行它不会返回结果,返回的是指针对象。每次调用 next 方法,会返回一个对象,表示当前阶段的信息( value 属性和 done 属性)。value 属性是 yield 语句后面表达式的值,表示当前阶段的值;done 属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。
静态方法
顾名思义,在方法前加static,表示该方法不会被实例对象所继承,直接通过类调用。静态方法可以与非静态方法重名。父类的静态方法,可以被子类继承。
实例属性
类的实例属性有两种定义方式,如下面代码:
1 | //方法一 |
静态属性
类的静态属性方法有两种定义方式,如下面代码:
1 | // 方法一 |
私有方法与私有属性
类的私有方法方法有两种定义方式,如下面代码:
1 | //方法一:加入下划线形式class Widget { _bar(baz) { return this.snaf = baz; }}//方法二:将私有方法移出类class Widget { foo (baz) { bar.call(this, baz); }}function bar(baz) { return this.snaf = baz;} |
私有属性的定义如下:
1 | class IncreasingCounter { #count = 0; //也可用来定义私有方法 #sum() { return this.#a + this.#b; }} |
in运算符
1 | class A { use(obj) { if (#foo in obj) { // 私有属性 #foo 存在 } else { // 私有属性 #foo 不存在 } }} |
new.target属性
属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令或Reflect.construct()调用的,new.target会返回undefined。
1 | function Person(name) { if (new.target === Person) { this.name = name; } else { throw new Error('必须使用 new 命令生成实例'); }}var person = new Person('张三'); // 正确var notAPerson = Person.call(person, '张三'); // 报错 |
继承
类通过”extends“来继承,如下面代码:
1 | class Point {}class ColorPoint extends Point {} |
注意,子类的构造函数必须先调用父类的构造函数才能再进行自我加工。
1 | 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
super一方面充当父类的构造函数,另一方面当对象使用,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
注意:如果在子类中使用super对某个属性进行赋值,此时super会化身this
1 | class A { constructor() { this.x = 1; }}class B extends A { constructor() { super(); this.x = 2; super.x = 3; console.log(super.x); // undefined console.log(this.x); // 3 }} |
老生常谈的prototype和__proto__
在class中,它同时拥有prototype属性和_proto_属性,其中
子类的__proto__属性,表示构造函数的继承,总是指向父类
子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
正是因为上述规则,类的继承是按如下代码实现的。
1 | class A {}class B {}// B 的实例继承 A 的实例Object.setPrototypeOf(B.prototype, A.prototype);// B 继承 A 的静态属性Object.setPrototypeOf(B, A);const b = new B(); |
