ES6看完必会第十章------ Class 类 (可私信解惑,不会来捶我)
class 声明
JavaScript语言的传统方法是通过构造函数,定义并生成新对象。
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6 的class可以看作只是一个语法糖(指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。),它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
Class不存在变量提升(hoist),这一点与ES5完全不同。
使用class关键字创建一个类代码如下:
class Person{
constructor(x, y) {
this.x = x;
this.y = y;
} // 方法之间不加逗号隔开,否则报错
sum(){ // 方法前面不用加function
var sum=this.x+this.y;
return sum
}
}
上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,通过new命令生成对象实例时,自动调用该方法。而this关键字则代表实例对象。
构造函数的prototype属性,在ES6的“类”上面继续存在。所有的方法还是在prototype属性上。
类的方法内部如果含有 this,它默认指向类的实例。
-
类的实例对象
生成类的实例对象的写法,与ES5完全一样,也是使用new命令。如果忘记加上new,像函数那样调用类,将会报错。
// 报错
var p= Person(2, 3);
// 正确
var p= new Person(2, 3);
与ES5一样,类的所有实例共享一个原型对象。
var p1 = new Person(2,3);
var p2 = new Person(3,2);
p1.__proto__ === p2.__proto__ // true
上面代码中,p1和p2都是Person的实例,它们的原型都是Point.prototype,所以__proto__属性是相等的。
可以通过实例的 __proto__ 属性为Class添加方法。在上一节Person类基础上添一个名为newF方法:
class Person{
constructor(x, y) {
this.x = x;
this.y = y;
}
sum(){
var sum=this.x+this.y;
return sum
}
}
p1= new Person()
p1.__proto__.newF= function () { return '这里是新创建的方法' }; // 给类添加一个新方法 newF
console.log( p1.newF() ) // 这里是新创建的方法
-
class的继承
Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承来得清晰、方便很多。
class childPerson extends Person{}
上面代码定义了一个childPerson 类,该类通过extends关键字,继承了Person类的所有属性和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个Person类。
如果继承父类后要添加自己的属性和方法,如下:
class childPerson extends Person {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
子类必须在constructor方法中调用super方法,且必须出现在 this 之前。否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。
-
super关键字
super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。
class A {}
class B extends A {
constructor() { // 构造函数
super(); // 作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。
}
}
上面代码中,子类B的构造函数之中的super()代表调用父类的构造函数。这是必须的,否则 JavaScript引擎会报错。
第二种情况,super作为对象时,指向父类的原型对象。
class B extends A {
constructor() {
super();
console.log(super.p()); // 指向父类的p方法
}
}
上面代码中,子类B当中的super.p(),就是将super当作一个对象使用。此时super相当于父类A。
这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性是无法通过super调用的。
super关键字
super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。
class A {}
class B extends A {
constructor() { // 构造函数
super(); // 作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。
}
}
上面代码中,子类B的构造函数之中的super()代表调用父类的构造函数。这是必须的,否则 JavaScript引擎会报错。
第二种情况,super作为对象时,指向父类的原型对象。
class B extends A {
constructor() {
super();
console.log(super.p()); // 指向父类的p方法
}
}
上面代码中,子类B当中的super.p(),就是将super当作一个对象使用。此时super相当于父类A。
这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性是无法通过super调用的。
-
class静态方法
类相当于实例的原型,所有在类中定义的方法都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello' 直接类调用
var foo = new Foo(); // 创建一个实例
foo.classMethod() // 报错内容: foo.classMethod is not a function 实例调用报错
上面代码中,Foo 类的classMethod 方法前有static 关键字,表明该方法是一个静态方法,可以直接在Foo 类上调用,而不是在Foo 类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。
父类的静态方法,可以被子类继承。静态方法也是可以从super对象上调用的。
上一篇: 开发效率的挑战
下一篇: Jboss7 JMS demo