ES6之class的写法及继承

本文深入探讨了ES6中类的定义与使用,包括构造函数、静态方法、属性表达式及类的继承,对比了与ES5的区别,帮助读者更好地理解和运用ES6面向对象编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JS 语言中,生成实例对象的传统方法是通过构造函数。构造函数的一个例子如下代码:

  function Point(x, y) {
  this.x = x;
  this.y = y;}

  Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';};

  var p = new Point(1, 2);

这种写法跟传统的面向对象语言(比如 C++ 和 Java)差异很大,让新学习这门语言的程序员很容易就感到困惑,感到很不理解。而ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用 ES6 的class改写,就是下面这样。

//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}

toString() {
return '(' + this.x + ', ' + this.y + ')';
}}

上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5 的构造函数Point,对应 ES6 的Point类的构造方法。
point类除了构造方法,还定义了一个toString方法。注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。

//hasOwnProperty 可以用来判断对象是否有每一个属性
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true

ES6 的类,完全可以看作构造函数的另一种写法:

class Point {
// ...
}

typeof Point // "function"

通过上面的代码可以看出来,类的数据类型就是函数,类本身就指向构造函数。
类的属性名,可以采用表达式。

let methodName = 'getArea';

class Square {
 constructor(length) {
 // ...
 }

[methodName]() {
// ...
}}

上面代码中,Square类的方法名getArea,是从表达式得到的。

类内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。

考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。

constructor 方法

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

class Point {}
// 等同于
class Point {
constructor() {}}

在上面的代码中,定义了一个空的类Point,JS 引擎会自动为它添加一个空的constructor方法。constructor方法默认返回实例对象(即this)。类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。

class Foo {
   constructor() {

}}

Foo()
// TypeError: Class constructor Foo cannot be invoked without 'new'

生成类的实例对象的写法,与 ES5 完全一样,也是使用new命令。前面说过,如果忘记加上new,像函数那样调用Class,将会报错。

class Point {
// ...
}
// 报错
var point = Point(2, 3);
// 正确
var point = new Point(2, 3);

类不存在变量提升,这一点与 ES5 完全不同。

new Foo(); // ReferenceError
class Foo {}

类方法

加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

class Foo {
     static classMethod() {
     return 'hello';
     }
}

Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function

从上面的代码中可以看出,Foo类的classMethod方法前有static关键字,表明该方法是一个静态方法,可以直接在Foo类上调用(Foo.classMethod()),而不是在Foo类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。

类的继承
Class 可以通过extends关键字实现继承 这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

class Point {}

class ColorPoint extends Point {}

上面代码定义了一个ColorPoint类,该类通过extends关键字,继承了Point类的所有属性和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个Point类。下面,我们在ColorPoint内部加上代码。

class ColorPoint extends Point {
   constructor(x, y, color) {
   super(x, y); // 调用父类的constructor(x, y)
   this.color = color;
   }

   toString() {
   return this.color + ' ' + super.toString(); // 调用父类的toString()
   }
}

上面代码中,constructor方法和toString方法之中,都出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。而ES6也要求,子类的构造函数必须执行一次super函数。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。

class Point { /* ... */ }

class ColorPoint extends Point {
    constructor() {
    }
}

let cp = new ColorPoint(); // ReferenceError

上面代码中,ColorPoint继承了父类Point,但是它的构造函数没有调用super方法,导致新建实例时报错。

需要注意的地方是,在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例

class Point {
   constructor(x, y) {
   this.x = x;
   this.y = y;
   }
}

class ColorPoint extends Point {
    constructor(x, y, color) {
    this.color = color; // ReferenceError
    super(x, y);
    this.color = color; // 正确
    }
}

上面代码中,子类的constructor方法没有调用super之前,就使用this关键字,结果报错,而放在super方法之后就是正确的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值