概念
在ES6(也称为ECMAScript 2015)中,class关键字被引入,作为基于原型继承的语法糖,用于更清晰地表示对象之间的关系和创建对象。虽然JavaScript是基于原型的,但class提供了一种更接近传统面向对象编程语言的语法。
基本语法
类的组成部分
- constructor() : 类的构造函数,当创建类的新实例时,会自动调用该函数。如果不显式定义,类会有一个默认的构造函数。
- 方法: 类中定义的方法可以被实例调用。方法内部可以使用
this关键字来访问类的属性和其他方法。 - getter 和 setter: 允许你拦截对对象属性的访问和赋值操作。
- 静态方法: 使用
static关键字定义的方法,它们不能被类的实例调用,而只能被类本身调用。
1. 定义类
使用class关键字后跟类名来定义一个类。类名通常使用大驼峰命名法(PascalCase)。
class MyClass {
// 类体
}
2. 构造函数(constructor)
每个类都可以有一个特殊的方法,即构造函数constructor。当创建类的新实例时,构造函数会自动被调用。通常用于初始化新创建的对象。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const person1 = new Person('Alice', 30);
console.log(person1.name); // 输出: Alice
console.log(person1.age); // 输出: 30
3. 类的方法
类中可以定义方法,这些方法可以在类的实例上调用。方法内部可以通过this关键字访问类的属性和其他方法。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
const person1 = new Person('Bob', 25);
person1.greet(); // 输出: Hello, my name is Bob and I am 25 years old.
4. 静态方法
使用static关键字定义的方法称为静态方法。静态方法属于类本身,而不是类的实例。因此,静态方法不能通过类的实例调用,而必须通过类本身调用。
class MathUtils {
static sum(a, b) {
return a + b;
}
}
console.log(MathUtils.sum(2, 3)); // 输出: 5
// 注意:不能通过实例调用静态方法,如 new MathUtils().sum(2, 3) 会导致错误
5. 继承
JavaScript中的类支持继承,使用extends关键字来实现。子类可以继承父类的属性和方法,并可以添加或覆盖自己的属性和方法。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} says Woof!`);
}
}
const myDog = new Dog('Buddy');
myDog.speak(); // 输出: Buddy says Woof!
6. getter 和 setter(新增属性)
类中可以定义getter和setter方法,用于拦截对对象属性的访问和赋值操作。
class Phone {
constructor() {
this._price = 0;
// 使用下划线前缀表示这是一个私有属性(在JavaScript中,实际上没有真正的私有属性,但这是一种常见的约定)
}
get price() {
console.log("价格属性被读取了");
return this._price;
}
set price(newVal) {
if (typeof newVal === 'number' && newVal >= 0) {
console.log('价格属性被修改了');
this._price = newVal;
} else {
console.error('价格必须是非负数字');
}
}
}
let s = new Phone();
s.price = 1999; // 输出: 价格属性被修改了
console.log(s.price); // 输出: 价格属性被读取了, 然后是 1999
s.price = 'free'; // 输出: 价格必须是非负数字
例题
ES5中构造函数继承
//手机
//构造函数
function Phone(brand, price){
this.brand = brand;
this.price = price;
}
//添加方法(父级构造函数)
Phone.prototype.call = function(){
console.log("我可以打电话");
}
//子级构造函数
//智能手机
function SmartPhone(brand, price, color, size){
Phone.call(this, brand, price); //调用父级的构造函数
this.color = color;
this.size = size;
}
//设置子级构造函数的原型
SmartPhone.prototype = new Phone; //实例对象
SmartPhone.prototype.constructor = SmartPhone;
//声明子类的方法
SmartPhone.prototype.photo = function(){
console.log("我可以拍照")
}
SmartPhone.prototype.playGame = function(){
console.log("我可以玩游戏");
}
const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch');
console.log(chuizi);
以下是结果,属性和方法都继承了
ES6中类继承
class Phone{
//构造方法
constructor(brand, price){
this.brand = brand;
this.price = price;
}
//父类的成员属性
call(){
console.log("我可以打电话!!");
}
}
class SmartPhone extends Phone {
//构造方法
constructor(brand, price, color, size){
super(brand, price); //调用父类 Phone.call(this, brand, price)
this.color = color;
this.size = size;
}
photo(){
console.log("拍照");
}
playGame(){
console.log("玩游戏");
}
call(){
console.log('我可以进行视频通话');
}
}
const xiaomi = new SmartPhone('小米',799,'黑色','4.7inch');
// console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();