JavaScript面向对象—深入ES6的class
JavaScript面向对象—深入ES6的class
前言
在前面一篇中主要介绍了JavaScript中使用构造函数+原型链实现继承,从实现的步骤来说还是比较繁琐的。在ES6中推出的class的关键字可以直接用来定义类,写法类似与其它的面向对象语言,但是使用class来定义的类其本质上依然是构造函数+原型链的语法糖而已,下面就一起来全面的了解一下class吧。
1.类的定义
class关键字定义类可使用两种方式来定义:
class Person {} // 类声明
const Person = class {} // 类表达式
2.类的构造函数
从上面class定义类可以发现是没有
()让我们来传递参数的,当希望在实例化对象的给类传递一些参数,这个时候就可以使用到类的构造函数constructor了。
每个类都可以有一个自己的
constructor方法,注意只能有一个,如果有多个会抛出异常;class Person {
constructor(name, age) {
this.name = name
this.age = age
} constructor() {}
}

当通过new操作符来操作类时,就会去调用这个类的
constructor方法,并返回一个对象(具体new操作符调用函数时的默认操作步骤在上一篇中有说明);class Person {
constructor(name, age) {
this.name = name
this.age = age
}
} const p = new Person('curry', 30)
console.log(p) // Person { name: 'curry', age: 30 }
3.类的实例方法
在构造函数中实现方法继承是将其放到构造函数的原型上,而在class定义的类中,可直接在类中定义方法,最终class还是会帮我们放到其原型上,供多个实例来使用。
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
eating() {
console.log(this.name + 'is eating.')
}
running() {
console.log(this.name + 'is running.')
}
}
4.类的访问器方法
在使用
Object.defineProperty()方法来控制对象的属性时,在其数据属性描述符中可以使用setter和getter函数,在class定义的类中,也是可以使用这两个访问器方法的。
class Person {
constructor(name, age) {
this.name = name
this._age = 30 // 使用_定义的属性表示为私有属性,不可直接访问
}
get age() {
console.log('age被访问')
return this._age
}
set age(newValue) {
console.log('age被设置')
this._age = newValue
}
}
const p = new Person('curry', 30)
console.log(p) // Person { name: 'curry', _age: 30 }
p.age // age被访问
p.age = 24 // age被设置
console.log(p) // Person { name: 'curry', _age: 24 }
5.类的静态方法
什么叫类的静态方法呢?该方法不是供实例对象来使用的,而是直接加在类本身的方法,可以使用类名点出来的方法,可以使用static关键字来定义静态方法。
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
static foo() {
console.log('我是Person类的方法')
}
}
Person.foo() // 我是Person类的方法
6.类的继承
6.1.extends关键字
在ES6之前实现继承是不方便的,ES6中增加了extends关键字,可以方便的帮助我们实现类的继承。
实现Student子类继承自Person父类:
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
eating() {
console.log(this.name + ' is eating.')
}
}
class Student extends Person {
constructor(sno) {
this.sno = sno
}
studying() {
console.log(this.name + ' is studying.')
}
}
那么子类如何使用父类的属性和方法呢?
6.2.super关键字
使用super关键字可以在子类构造函数中调用父类的构造函数,但是必须在子类构造函数中使用this或者返回默认对象之前使用super。
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
eating() {
console.log(this.name + ' is eating.')
}
}
class Student extends Person {
constructor(name, age, sno) {
super(name, age)
this.sno = sno
}
studying() {
console.log(this.name + ' is studying.')
}
}
const stu = new Student('curry', 30, 101111)
console.log(stu) // Student { name: 'curry', age: 30, sno: 101111 }
// 父类的方法可直接调用
stu.eating() // curry is eating.
stu.studying() // curry is studying.
但是super关键字的用途并不仅仅只有这个,super关键字一般可以在三个地方使用:
子类的构造函数中(上面的用法);
实例方法中:子类不仅可以重写父类中的实例方法,还可以通过super关键字复用父类实例方法中的逻辑代码;
class Person {
constructor(name, age) {
this.name = name
this.age = age
} eating() {
console.log(this.name + ' is eating.')
} parentMethod() {
console.log('父类逻辑代码1')
console.log('父类逻辑代码2')
console.log('父类逻辑代码3')
}
} class Student extends Person {
constructor(name, age, sno) {
super(name, age)
this.sno = sno
} // 直接重写父类eating方法
eating() {
console.log('Student is eating.')
} // 重写父类的parentMethod方法,并且复用逻辑代码
parentMethod() {
// 通过super调用父类方法,实现复用
super.parentMethod() console.log('子类逻辑代码4')
console.log('子类逻辑代码5')
console.log('子类逻辑代码6')
}
}

静态方法中:用法就和实例方法的方式一样了;
class Person {
constructor(name, age) {
this.name = name
this.age = age
} static parentMethod() {
console.log('父类逻辑代码1')
console.log('父类逻辑代码2')
console.log('父类逻辑代码3')
}
} class Student extends Person {
constructor(name, age, sno) {
super(name, age)
this.sno = sno
} // 重写父类的parentMethod静态方法,并且复用逻辑代码
static parentMethod() {
// 通过super调用父类静态方法,实现复用
super.parentMethod() console.log('子类逻辑代码4')
console.log('子类逻辑代码5')
console.log('子类逻辑代码6')
}
} Student.parentMethod()

6.3.继承内置类
extends关键字不仅可以实现继承我们自定义的父类,还可以继承JavaScript提供的内置类,可对内置类的功能进行扩展。
比如,在Array类上扩展两个方法,一个方法获取指定数组的第一个元素,一个方法数组的最后一个元素:
class myArray extends Array {
firstItem() {
return this[0]
}
lastItem() {
return this[this.length - 1]
}
}
const arr = new myArray(1, 2, 3)
console.log(arr) // myArray(3) [ 1, 2, 3 ]
console.log(arr.firstItem()) // 1
console.log(arr.lastItem()) // 3
7.类的混入
何为类的混入?在上面的演示代码中,都只实现了子类继承自一个父类,因为JavaScript的类只支持单继承,不能继承自多个类。如果非要实现继承自多个类呢?那么就可以引入混入(Mixin)的概念了。
看看JavaScript中通过代码如何实现混入效果:
// 封装混入Animal类的函数
function mixinClass(BaseClass) {
// 返回一个匿名类
return class extends BaseClass {
running() {
console.log('running...')
}
}
}
class Person {
eating() {
console.log('eating...')
}
}
class Student extends Person {
studying() {
console.log('studying...')
}
}
const NewStudent = mixinClass(Student)
const stu = new NewStudent
stu.running() // running...
stu.eating() // eating...
stu.studying() // studying...
混入的实现一般不常用,因为参数不太好传递,过于局限,在JavaScript中单继承已经足够用了。
8.class定义类转ES5
上面介绍ES6中类的各种使用方法,极大的方便了我们对类的使用。我们在日常开发中编写的ES6代码都是会被babel解析成ES5代码,为了对低版本浏览器做适配。那么使用ES6编写的类被编译成ES5语法会是什么样呢?通过babel官网的试一试可以清楚的看到ES6语法转成ES5后的样子。
- 刚开始通过执行自调用函数得到一个Person构造函数;
- 定义的实例方法和类方法会分别收集到一个数组中,便于后面直接调用函数进行遍历添加;
- 判断方法类型:如果是实例方法就添加到Person原型上,是类方法直接添加到Person上;
- 所以class定义类的本质还是通过构造函数+原型链,class就是一种语法糖;

这里可以提出一个小问题:定义在constructor外的属性最终会被添加到哪里呢?还是会被添加到类的实例化对象上,因为ES6对这样定义的属性进行了单独的处理。
class Person {
message = 'hello world'
constructor(name, age) {
this.name = name
this.age = age
}
eating() {
console.log(this.name + ' is eating.')
}
static personMethod() {
console.log('personMethod')
}
}
const p = new Person('curry', 30)
console.log(p) // Person { message: 'hello world', name: 'curry', age: 30 }

扩展:在上图中通过通过babel转换后的代码中,定义的Person函数前有一个/*#__PURE__*/,那么这个有什么作用呢?
- 实际上这个符号将函数标记为了纯函数,在JavaScript中纯函数的特点就是没有副作用,不依赖于其它东西,独立性很强;
- 在使用webpack构建的项目中,通过babel转换后的语法更有利于webpack进行
tree-shaking,没有使用到的纯函数会直接在打包的时候被压缩掉,达到减小包体积效果;
JavaScript面向对象—深入ES6的class的更多相关文章
- JavaScript面向对象轻松入门之概述(demo by ES5、ES6、TypeScript)
写在前面的话 这是一个JavaScript面向对象系列的文章,本篇文章主要讲概述,介绍面向对象,后面计划还会有5篇文章,讲抽象.封装.继承.多态,最后再来一个综合. 说实话,写JavaScript面向 ...
- JavaScript面向对象轻松入门之封装(demo by ES5、ES6、TypeScript)
本章默认大家已经看过作者的前一篇文章 <JavaScript面向对象轻松入门之抽象> 为什么要封装? 封装(Encapsulation)就是把对象的内部属性和方法隐藏起来,外部代码访问该对 ...
- javaScript - 面向对象 - ES5 和 ES6
javaScript - 面向对象 - ES5 和 ES6 ES5之前用 构造函数 构造函数的特点 就是一个普通函数, 他的函数名要大写.: 带方法的写法: 原型的方式: prototype 为内置的 ...
- 【转】javascript面向对象编程
摘要:本文本来是想自己写的,奈何花了好长时间写好之后忘记保存,还按了刷新键,一键回到解放前,索性不写了,所以本文是转载的. 面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式,主要包括模块化. ...
- 深入解读JavaScript面向对象编程实践
面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式,主要包括模块化.多态.和封装几种技术.对JavaScript而言,其核心是支持面向对象的,同时它也提供了强大灵活的基于原型的面向对象编程能力 ...
- JavaScript 面向对象开发知识基础总结
JavaScript 面向对象开发知识基础总结 最近看了两本书,书中有些内容对自己还是很新的,有些内容是之前自己理解不够深的,所以拿出来总结一下,这两本书的名字如下: JavaScript 面向对象精 ...
- 深入理解 JavaScript 面向对象
我们在学习编程时,避免不了会接触一个概念,叫:面向对象编程(Object-oriented programming,缩写:oop) (不是搞对象那个对象哈),其实我们的编程方式,不止有面向对象,还有 ...
- 重学js之JavaScript 面向对象的程序设计(创建对象)
注意: 本文章为 <重学js之JavaScript高级程序设计>系列第五章[JavaScript引用类型]. 关于<重学js之JavaScript高级程序设计>是重新回顾js基 ...
- JavaScript面向对象小抄集
前言 本文旨在记录JavaScript中面向对象的基础知识 搞明白JavaScript中的面向对象 一切都是对象 JavaScript中,除了基本类型外,其它类型都是对象类型 所谓对象就是若干属性的集 ...
随机推荐
- Git 保存和恢复工作进度(stash)
感谢原文作者:滑稽的命运 原文链接:https://www.jianshu.com/p/1e65e938f93c 作用: 封存工作区与暂存区已经被Git版本控制,但没有提交(Commit)版本库的文件 ...
- linux下core 相关设置
1)core文件简介core文件其实就是内存的映像,当程序崩溃时,存储内存的相应信息,主用用于对程序进行调试.当程序崩溃时便会产生core文件,其实准确的应该说是core dump 文件,默认生成位置 ...
- 浅谈AngularJS中使用$resource
这个服务可以创建一个资源对象,我们可以用它非常方便地同支持RESTful的服务端数据源进行交互,当同支持RESTful的数据模型一起工作时,它就派上用场了. REST是Representational ...
- Mysql Json函数创建 (二)
本节中列出的功能由组件元素组成JSON值. JSON_ARRAY([val[, val] ...]) 计算(可能为空)值列表,并返回包含这些值的JSON数组. mysql> SELECT JSO ...
- 3.Flink实时项目之流程分析及环境搭建
1. 流程分析 前面已经将日志数据(ods_base_log)及业务数据(ods_base_db_m)发送到kafka,作为ods层,接下来要做的就是通过flink消费kafka 的ods数据,进行简 ...
- 虫师Selenium2+Python_6、Selenium IDE
P155--创建测试用例 录制脚本 编辑脚本 定位辅助 P159--Selenium IDE 命令 在浏览器中打开URL,可以接受相对路径和绝对路径两种形式 open open(url) 单击链接 ...
- Solution -「JLOI 2015」「洛谷 P3262」战争调度
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 层的完全二叉树,你把每个结点染成黑色或白色,满足黑色叶子个数不超过 \(m\).对于一个叶子 \(u\), ...
- [LeetCode]7. 整数反转(Java)
原题地址: reverse-integer 题目描述: 给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果. 如果反转后整数超过 32 位的有符号整数的范围 [−2^31, ...
- Spring5基础
基于Spring 5.2.6 版本. Spring概念 IOC容器 IOC底层原理的演进过程--本质就是为了高内聚,低耦合 在原始方式中,我们通过new创建对象来实现创建对象的逻辑,但是这样做当对象路 ...
- CobaltStrike逆向学习系列(4):Beacon 上线协议分析
这是[信安成长计划]的第 4 篇文章 关注微信公众号[信安成长计划] 0x00 目录 0x01 Beacon 发送 0x02 TeamServer 处理 0x03 流程图 0x04 参考文章 在上一篇 ...