Es6 类class的关键 super、static、constructor、new.target
ES6引入了Class(类)这个概念,作为对象的模板,通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
那么如何掌握类这项技能,让我来陪大家一起学习:
1.super关键字
super用在调用的时候有两种情况:
第一种情况,super作为函数调用时,代表父类的构造函数。
第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
class Person { constructor (name) { this.name = name; } height(){ console.log(1); } static weight(){ console.log(2); } } class Student extends Person { constructor (name, age) { super(); //代表父类的构造函数 this.age = age; } height(){ super.height(); //指向父类的原型对象 } static weight(){ super.weight(); //指向父类 } }
如果子类调用constructor,那么子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
总结下:
super 关键字用于调用一个对象的父对象上的函数。
super.prop 和 super[expr] 表达式在类 和 对象字面量 任何 方法定义 中都是有效的。
在构造函数中使用时,super关键字单独出现,必须在可以使用this关键字之前使用。此关键字也可用于调用父对象上的函数。
2.static关键字
类相当于实例的原型, 所有在类中定义的方法, 都会被实例继承。 如果在一个方法前, 加上static关键字, 就表示该方法不会被实例继承, 而是直接通过类来调用, 这就称为“ 静态方法”。
静态方法调用直接在类上进行,而在类的实例上不可被调用。
静态方法通常用于创建 实用/工具 函数。
通过例子我们可以发现,静态方法是通过类名直接调用的
从另一个静态方法为了在同一个类的另一个静态方法中调用一个静态方法,你可以使用 this 关键字。
class StaticMethodCall { static staticMethod() { return 'Static method has been called'; } static anotherStaticMethod() { return this.staticMethod() + ' from another static method'; } } StaticMethodCall.staticMethod(); // 'Static method has been called' StaticMethodCall.anotherStaticMethod(); // 'Static method has been called from another static method'
从类的构造函数和其他方法静态方法不能直接在非静态方法中使用 this 关键字来访问。你需要使用类名来调用它们:CLASSNAME.STATIC_METHOD_NAME() 或者将其作为构造函数的属性来调用该方法: this.constructor.STATIC_METHOD_NAME().
class StaticMethodCall { constructor() { console.log(StaticMethodCall.staticMethod()); // 'static method has been called.' console.log(this.constructor.staticMethod()); // 'static method has been called.' } static staticMethod() { return 'static method has been called.'; } }
3.new.target 关键字
new.target属性允许你检测函数或构造方法是否通过是通过new运算符被调用的。在通过new运算符被初始化的函数或构造方法中,new.target返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target 的值是undefined。
怎么理解这段话,也就是说new.target的功能就是用来检测函数的调用是不是通过 new 去创建一个新对象的,而且new.target返回的是一个指向函数的引用,也就是说我们能够确定是哪个函数进行了new操作
class A { constructor() { console.log(new.target.name); } } class B extends A { constructor() { super(); } } var a = new A(); // logs "A" var b = new B(); // logs "B"
new.target 最大的作用就是让构造器知道当前到底 new 的是哪个类。
延伸下。ES6之前怎么实现这个功能?
var A = function A() { if(!(this instanceof A)) throw 'Constructor A requires "new"'; // ··· };
然而这依然可以通过 call 或 apply 来调用。比如:
var a = A.call(Object.create(A.prototype));
那么用ES6就是下面这样操作了
var A = function A() { if(!new.target) throw 'Constructor A requires "new"'; // ··· };
4.constructor关键字
构造方法是创建和初始化使用类创建的一个对象的一种特殊方法。
class Square extends Polygon { constructor(length) { // 在这里调用父类的"length",赋值给矩形的"width"和"height"。 super(length, length); // 注意:子类必须在constructor方法中调用super方法,否则新建实例时会报错。 this.name = 'Square'; } get area() { return this.height * this.width; } set area(value) { this.area = value; } }
如果没有显式定义,会默认添加一个空的constructor方法。对于基类"Base classes",默认构造方法如下:
constructor() {}
对于派生类"Derived classes" ,默认构造方法如下:
constructor(...args) {
super(...args);
}