购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.13 类的用法

JavaScript实现的面向对象编程是建立在函数原型上的面向对象编程,和大多数传统的面向对象语言(C++、Java、C#等)有很大的差别,ES6中提供了类似于Java中的类的写法,引入了类(class)的概念,通过class关键字定义类。

2.13.1 类的定义

ES6引入了传统的面向对象语言中的类概念。类的写法让对象原型的写法更加清晰、更像面向对象编程的语法,也更加通俗易懂。

下面对比ES6和ES5的类的写法,如代码示例2-157所示。

代码示例2-157

ES6的类可以看作ES5的一种新的语法糖,ES6类的本质还是一个函数,类本身指向构造函数,示例代码如下:

ES6类还有另外一种定义方式,也就是类的表达式写法,如代码示例2-158所示。

代码示例2-158 类表达式写法

在上面的代码中,Person没有作用,类名是const修饰的MyPerson。

需要注意的是,与ES5中的函数不同的是,ES6中类是不存在变量提升的,示例代码如下:

在上面的代码中,Person类使用在前,定义在后,这样会报错,因为ES6不会把类的声明提升到代码头部。这种规定的原因与继承有关,必须保证子类在父类之后定义。

说明: ES6类和模块的内部默认采用严格模式,所以不需要使用use strict指定运行模式。只要将代码写在类或模块中,就只有严格模式可用。编写的所有代码其实都运行在模块中,所以ES6实际上把整个语言升级到了严格模式。

2.13.2 类的构造函数与实例

下面了解类的构造函数和类的实例的创建。

1.constructor()方法

constructor()方法是类的构造函数,用于传递参数,返回实例对象。当通过new命令生成对象实例时,会自动调用该方法。如果没有显式定义,则类内部会自动创建一个constructor(),如代码示例2-159所示。

代码示例2-159 构造函数

和Java语言不一样,ES6中的构造函数是不支持构造函数重载的。

2.类的实例

类虽然也是函数,但是和ES5中的函数不同,如果不通过new关键字,而直接调用类,则会导致类型错误,下面创建一个Person类的实例,代码如下:

2.13.3 类的属性和方法

在传统的面向对象语言中,类包含属性和方法,ES6中的属性只有公有的属性,无法和其他语言一样定义私有和静态的属性,但是可以通过其他的方式实现与私有属性和静态属性相同的效果。

1.实例属性和实例方法

实例属性和方法都是通过类的实例访问的,下面通过一个Animal类看一看实例属性和方法的定义,如代码示例2-160所示。

代码示例2-160

在上面的例子中,Animal类中this引用的属性就是实例属性,speak()和walk()方法是实例方法。在使用Animal的对象时,实例属性和方法通过对象来引用,代码如下:

如果类的方法内部含有this,则它默认指向类的实例,但是必须非常小心,一旦单独使用该方法,就很可能会报错。

上面的方法在调用时,如果通过实例对象访问speak(),则speak()中的this指向当前类的实例对象,但是如果单独使用,this则会指向该方法运行时所在的环境,此时this的值为undefined,代码如下:

一个比较简单的解决方法是,在构造方法中绑定this,这样就不会找不到this了,如代码示例2-161所示。

代码示例2-161

另一种解决方法是使用箭头函数,如代码示例2-162所示。

代码示例2-162

2.静态属性和静态方法

静态属性或者方法,又被叫作类属性或者类方法,使用static关键字修饰属性或者方法就是类属性或者类方法,静态的属性或方法需要通过类直接调用,不能通过实例进行调用,如代码示例2-163所示。

代码示例2-163

3.可计算成员名称

可计算成员指使用方括号包裹一个表达式,如下面定义了一个变量methodName,然后使用[methodName]设置为类Person的原型方法,如代码示例2-164所示。

代码示例2-164

4.属性存储器(setter()/getter()方法)

与ES5一样,在Class内部可以使用get和set关键字,以此对某个属性设置存值函数和取值函数,以便拦截该属性的存取行为,如代码示例2-165所示。

代码示例2-165

在上面的代码中,prop属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了。存值函数和取值函数设置在属性的descriptor对象上,如代码示例2-166所示。

代码示例2-166

在上面的代码中,存值函数和取值函数定义在prop属性的描述对象上,这与ES5完全一致。

2.13.4 类的继承

ES6中的类通过extends关键字实现继承,这和ES5通过修改原型链实现继承不同。

子类必须在constructor()方法中调用super()方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super()方法,子类就得不到this对象,如代码示例2-167所示。

代码示例2-167

super指的是父类,通常在constructor()中调用。在此示例中,littleCat.speak()方法会覆盖在Animal类中定义的方法。

super这个关键字,既可以当作函数使用,也可以当作对象使用。第1种情况,super()作为函数调用时,代表父类的构造函数,只能用在子类的构造函数中。ES6要求,子类的构造函数必须执行一次super()函数。第2种情况,super作为对象时,指代父类的原型对象。 FYiy8eTV/O2FEh0Q5Ely9ghp71DFC54eU42j3SeuTyeXwHPzl+5ViBcuJuyP9sCD

点击中间区域
呼出菜单
上一章
目录
下一章
×