一, class和自定义类型的区别:
1,类声明不会被提升。
2,类声明的代码自动运行在严格模式。
3,类的所有方法都是不可枚举的,而自定的方法必须使用Object.defineProperty来设置。
4,类的所有方法都没有[[Construct]],因此用new来调用会报错。
5,调用类构造器不使用new 会报错。
6,视图在类的内部重写类名会报错。
二,类的生成器方法
可以使用 Symbol.iterator来定义生成器方法,来生成类的默认迭代器。
class Iterator{ constructor() { this.arr = [1,2,3,4]; } *[Symbol.iterator]() { yield *this.arr.values(); } } let iter = new Iterator(); for (let i of iter) { console.log(i) }
这样每个实例就都可以使用for of来使用。
三, 静态成员
class中的静态方法 是直接在方法前加上static关键字。
静态属性的写法:
class Foo{} Foo.a = 1; console.log(Foo.a);
四,继承
使用extends关键字进行继承。
只要一个表达式能够返回一个具有[[Construct]]属性以及原型的函数,就可以对其使用extends。
function Animal(name){ this.name = name;} Animal.prototype.getName = function(){ console.log(this.name)}; class Sheep extends Animal{ constructor(name) { super(name) } } let sheep = new Sheep('yz');
sheep.getName();
上面的Animal是es5的构造器,但也满足上面的要求,因此可以直接使用extends被继承。
由于extends后可以接受任意的表达式,那么自然而然也可以创建混入:
const Mixin1 = { getName(){ console.log(this.name)} } const Mixin2 = { addName() { console.log(this.name + this.age)} } function mixin (...mixinObj){ let base = function () {}; Object.assigin(base.prototype, ...mixinObj); return base; } class MinxinAll extends mixin(Mixin1, Mixin2){
constructor(name, age){
super();
this.name = name; this.age = age;
}
}
这样所有MinxinAll的实例都可以使用 混入对象的方法。 若多个混入的对象有相同的属性, 则只有最后被添加的属性会被保留。
使用extends的子类, 也可以继承父类的静态成员。
五,super
super只能在子类中使用,如果在没有extends的类中使用会报错。
在构造器中,必须在访问this之前调用super();因为super是用来初始化this的。
子类中可以使用super.方法()来访问原型的方法。
当然,箭头函数无super。
由于super是用来生成this的, 如果你只是想继承原型,而对父类的构造器没兴趣, 可以在constructor中不使用super,返回一个对象即可。
class A { getOne() { return 1;} } class B extends A { constructor() { return Object.create(new.target.prototype); } getTwo() { return 2;} } let n = new B(); n.getOne(); n.getTwo();
六,继承内置对象与Symbol.species属性
继承内置对象的 子类, 调用内置对象的方法,返回的结果是子类的实例。
比如:
class MyArray extends Array{} let arr = new MyArray(1,2,3,4,5); let newArr = arr.slice(1, 4); // 按理来说 调用了slice之后,生成的应该是数组,结果返回的newArr却是 MyArray的实例
Symbol.species 知名符号被用于 定义一个能返回函数的静态访问器属性。一般默认拥有Symbol.species属性的类型默认返回的都是this,即自身的构造器。
子类继承的时候,可以重写 Symbol.species属性来指定生成的实例属于何种类型。
七, new.target
在简单的情况下, new.target就等于本类的构造函数。 这样的话,可以通过使用new.target来创建一个抽象基类。 即只能被继承,自身不能实例化的类。
class Animal { constructor() { if (new.target === 'Animal') { throw new Error('此类不能被实例化') } } } class Row extends Animal{ constructor(name) { super(); this.name = name; } } let r = new Row('yz'); // 正常 let a = new Animal(); // 抛出错误。