Class关键字

Class关键字

类的声明

类是什么

ECMAScript 6提供了更接近传统开发语言的写法,引人了类(Class )的概念。类作为对象的模板,只是一个语法糖。class关键字只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

// ECMAScript 5使用构造函数定义
function Point(x, y) { this.x = x; this.y = y; }
Point.prototype.toString = function () {
	return '(' + this.x +', '+this.y + ')";
};
// ECMAScript 6使用类的概念定义
class Point {
	constructor(x, y) {
		this.x = x;
        this.y =y;
    }
    toString(){
		return '(' + this.x + ', ' + this.y + ')";
    }
}

类的声明

声明类具有以下两种方式:

  • 类的声明方式

    class name [extends] {
    	// class body
    }
    
    • name:表示当前声明的类名。
      但是不同于类表达式,类声明不允许再次声明已经存在的类,否则将会抛出一个类型错误。
  • 类的表达式方式

    const MyClass = class [className][extends]{
    	// class body
    };
    

    和函数表达式相同的一点是,类表达式可以是命名也可以是匿名的。如果是命名类表达式,这个名字只能在类体内部才能访问到。

构造函数

构造函数(Constructor )是用于创建和初始化类中创建的一个对象的一种特殊方法。

constructor([arguments]){... }
  • 在一个类中只能有一个名为“constructor”的特殊方法。一个类中出现多次构造函数(Constructor)方法将会抛出一个SyntaxError错误。
  • 在一个构造方法中可以使用super关键字来调用一个父类的构造方法。
  • 如果没有显式指定构造方法,则会添加默认的constructor方法。
  • 如果不指定一个构造函数( constructor )方法,则使用一个默认的构造函数(constructor ) 。

getter与setter

与ECMAScript 5一样,在“类”的内部可以使用get和 set 关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

class MyClass {
	constructor() {
        // ...
    }
    get prop() {
    	return 'getter";
    }
    set prop(value) {
    	console.log('setter: ' + value);
    }
let inst = new MyClass();

inst.prop = 123;// setter: 123
console.log(inst.prop);// 'getter'

不允许声明提前

声明类时,是不存在声明提前的现象的。如下示例代码所示:

new Foo(); // ReferenceError: Foo is not defined
class Foo {}

上逑代码示例中,Foo类调用在前,声明在后。由于 ECMAScript 6不允许类的声明提前,结果为报错。

这种规定的原因与继承有关,必须保证子类在父类之后定义。

不允许重复声明

声明类时,是不存在重复声明的。如果一个类被重复声明的话,则引起解析错误。如下示例代码所示:

class Foo {};
class Foo {};// SyntaxError: ldentifier 'Foo' has already been declared

若之前使用类表达式定义了一个类,则再次声明这个类同样会引起解析错误。

let Foo = class {};
class Foo {};// SyntaxError: ldentifier 'Foo' has already been declared

静态方法

静态方法的语法

static关键字为一个类定义了一个静态方法。静态方法不会在类的实例上被调用,相反被类本身调用。

static methodName() { ... }
  • methodName:表示指定类中的静态方法名称。

静态方法调用直接在类上进行,不能在类的实例上调用。

class ClassWithStaticMethod {
	static staticMethod(){
		return 'static method has been called.';
    }
}

console.log(ClassWithStaticMethod.staticMethod());
// "static method has been called."

静态方法的调用

  • 从另一个静态方法调用
    在同一个类中的一个静态方法调用另一个静态方法,可以使用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.STATICMETHOD.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.';
        }
    }
    

类的继承

实现类的继承

extends关键字用于类声明或者类表达式中,以创建一个类,该类作为另一个类的子类。

class ChildClass extends ParentClass { ... }

extends 关键字用来创建一个普通类或者内建对象的子类。

值得注意的是,继承的.prototype必须是一个Object或者null

  • 编写一个类作为父类,如下示例代码所示:
class Polygon {
	constructor(height, width){
		this.name = 'Polygon';
        this.height = height;
        this.width = width;
    }
	sayName(){
		console.log('Hi, l am a ' , this.name + '.');
    }
}
  • 编写一个类作为Polygon类的子类,如下示例代码所示:
class Square extends Polygon {
	constructor(length) {
		super(length, length);
        this.name = 'Square';
    }

    get area() {
    	return this.height * this.width;
    }
    set area(value) {
    	this.area = value;
    }
}
let s = new Square(5);
s.sayName();// Hi, l am a Square.

继承于内置对象

如下示例代码所示,实现了继承了内置的Date 对象。

class myDate extends Date {
  constructor() {
    super();
  }
  getFormattedDate() {
    var months = [
      "Jan",
      "Feb",
      "Mar",
      "Apr",
      "May",
      "Jun",
      "Jul",
      "Aug",
      "Sep",
      "Oct",
      "Nov",
      "Dec",
    ];
    return (
      this.getFullYear() + "-" + months[this.getMonth()] + "-" + this.getDate()
    );
  }
}
var mydate = new myDate();
console.log(mydate.getFormattedDate());

super关键字

super 关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

  • super关键字作为函数调用时,代表父类的构造函数。ECMAScript 6要求子类的构造函数必须执行一次 super 函数。
class A {}
class B extends A {
    constructor(){
    	super();
    }
}

值得注意的是,super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此 super()在这里相当于A.prototype.constructor.call(this)。

  • super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

    class A {
      p() {
        return 2;
      }
    }
    var a = new A();
    a.c = "C";
    
    class B extends A {
      constructor() {
        super();
      }
    }
    var b = new B();
    console.log(b.c); // undefined
    

    值得注意的是,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。

类的完整示例:

class Parent {
  constructor(name) {
    this.name = name;
  }
  // 当前类的(实例对象)方法,而不是当前类的原型方法
  toString() {
    return "this is parent method.";
  }
  static staticMethod() {
    return "this is parent method.";
  }
}
let parent = new Parent("东方月初");
// parent.toString(); // this is parent method.
// Parent.prototype.toString(); // this is parent method.
// parent.__proto__.toString(); // this is parent method.
class Child extends Parent {
  constructor(name, age) {
    super(name); // 指向父类的构造器
    this.age = age;
    // console.log(super.toString());
  }
  toString() {
    // super -> 指向父类的原型对象(Parent.prototype)
    return "this is child method." + super.toString();
  }
  static staticMethod() {
    // super -> 指向父类(Parent)
    return "this is child method." + super.staticMethod();
  }
}

let child = new Child("白月初", 18);
// console.log(child.toString());
// console.log(Child.staticMethod());
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码小余の博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值