含义:类是用来创建对象的模板。
了解类概念之前最好了解以下的知识:
- 懂点闭包
- 构造函数
- 原型
JS和其他语言不同,它是没有Class的,它本质就是JS的构造函数封装的语法糖。ES6提供一种更为清晰的方式来遵循面向对象的编程方式。
首先我们要了解JS的构造函数:
注:构造函数一般都以大写字母开头
/**
* Demo内部定义的方法,可以防止全局命名空间的污染,因为所有方法都是在构造函数中定义的。
*/
function Demo(name, age) {this.name = name;this.age = age;
}const demo1 = new Demo('张三', 23);/**
* 给自定义构造函数的添加方法,此时构造函数就属于原型
*/Demo.prototype.message = function(){console.log(this.name, this.age)
}
JS类
“语法糖”意味着该语言不是新功能并不是真正的新功能,算是改进机制。类构造允许为程序员定义具有干净语法的基于原型的类。
class Demo2 {constructor(name, age) {this.name = name;this.age = age;}message() {console.log(this.name, this.age)}
}const demo2 = new Demo('李四', 34);
demo2.message(); // 李四34
注:
- 如果没有“new”运算符,则无法调用类构造函数
- 类中不能存在多个构造函数
- 在对象创建期间,第一步是使用一组特定的初始属性和值运行“构造函数”方法
- 如果类中不存在“构造函数”,那么生成的就是一个空函数。然后你可以在创建的对象上执行其他实现的方法
- 类内的代码自动处于严格模式
关于class 的继承和super关键字
继承:extends关键字去实现继承。
super是用于继承父类后,获取父类中的构造方法的。
为什么要使用super关键字,这也是因为es6和es5的继承机制有很大的不同。ES5 的继承机制,是先创造一个独立的子类的实例对象,然后再将父类的方法添加到这个对象上面,即“实例在前,继承在后”。ES6 的继承机制,则是先将父类的属性和方法,加到一个空的对象上面,然后再将该对象作为子类的实例,即“继承在前,实例在后”。这就是为什么 ES6 的继承必须先调用super()方法,因为这一步会生成一个继承父类的this对象,没有这一步就无法继承父类。
参考:阮一峰ES6 Class 继承
注:这里的super虽然代表了父类的构造函数,但是因为返回的是子类的this(即子类的实例对象),所以super内部的this代表子类的实例,而不是父类的实例,这里的super()相当于A.prototype.constructor.call(this)(在子类的this上运行父类的构造函数)。
class Parent {constructor(name, age) {this.name = name;this.age = age;}message() {console.log(this.name, this.age)}
}const parent = new Parent('李四', 34);
parent.message()/**1. 此类继承于Demo2类,继承关键字:extends*/
class Child extends Parent {/**2. 以下的super关键字,用来表示父类的构造函数*/constructor(name, age, color) {super(name, age); // 调用父类的constructor内的name, age/**3. 在子类中,如果不先调用super,就使用this则会报错,原因就在于es6的继承机制与es5*/this.color = color}getMessage() {console.log(`我是${this.name},我今年${this.age},我喜欢${this.color}`)/**4. 调用父类的message*/super.message()}
}
const child = new Child('王五', 34, '红色');
child.getMessage()
注:关于class的什么静态、私有等概念省略,需要去看下阮一峰的详细class概念
很多面试官也会问到js类的使用场景:
- 大概念:类用来创建可重用组件、状态管理和行为。一般用于定义组件、封装功能、以及创建模块化、可维护的代码。
- 我自己的工作场景中:除使用js插件需要用new关键字这些以外,我如果不使用react的提供的一些钩子,例如useReducer【useReducer:管理状态更新逻辑从事件处理函数中移动到组件外面(人话就是:用来统一组织管理不同的事件状态,例如:右击的菜单可能会有,复制、粘贴、选中、转发等 功能,那我们可以统一用一个函数,在函数里面进行不同状态下的处理)】,我就会使用class进行状态管理,用于封装方法的复用性,降低耦合。也是为了在迭代时,不影响其他同事的代码,去增加自己的代码功能。还有就是用来做“封装”。
自我理解:虽然目前我们用现成的UI框架、JS插件、JS数据处理的方法也好,但这些都是别人处理好的,底层还都是建立在JS Class去将封装的代码形式去处理数据。但是!只用Class这个概念是无法真正掌握到核心的,需要搭配设计模式,与其说是设计模式,其本质就是通过一种工程建筑的思维去思考如何将自己的代码复用,如何增强可读性,增强可维护性!在代码中,我们应该追求极简和代码洁癖的编码思维去编写优雅的代码。
参考:
class MDN
阮一峰 ES6 class
freeCodeCamp class