JavaScript中的“Class类”

97 阅读3分钟

JavaScript的类是ES6中实现的一种面向对象的设计模型。它是对组封和重用进行优化的一种方式,尽管它是一种较为面向类型语言的仿造,但它本质上仍然是一种基于原型的语言。


类的概述

在JavaScript中,类是为了实现对象面向类型结构而设计的。它使用class关键字定义,尽管是一种声明式规范,本质上依然基于原型和实例。


声明一个类

可以通过class 关键字声明一个类:

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    sayHello() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
}

构造函数

构造函数是类中的特殊方法,依赖于constructor关键字:

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}

const person = new Person('Alice', 30);
console.log(person.name); // Alice

实例方法

实例方法是为实例实现专属功能的方法:

class Person {
    sayHello() {
        console.log('Hello!');
    }
}

const person = new Person();
person.sayHello(); // Hello!

私有字段

私有字段通过# 声明,只能在类内部访问:

class Person {
    #id;

    constructor(id) {
        this.#id = id;
    }

    getId() {
        return this.#id;
    }
}

const person = new Person(123);
console.log(person.getId()); // 123
console.log(person.#id); // SyntaxError

Getter和Setter字段

通过getset实现属性的读写控制:

class Person {
    constructor(name) {
        this._name = name;
    }

    get name() {
        return this._name;
    }

    set name(newName) {
        this._name = newName;
    }
}

const person = new Person('Alice');
console.log(person.name); // Alice
person.name = 'Bob';
console.log(person.name); // Bob

公共字段

公共字段通过在构造函数之外直接声明:

class Person {
    name = 'Anonymous';
}

const person = new Person();
console.log(person.name); // Anonymous

静态属性

通过static 关键字声明属于类本身的属性或方法:

class MathUtil {
    static add(a, b) {
        return a + b;
    }
}

console.log(MathUtil.add(2, 3)); // 5

扩展与继承

通过extends 实现类之间的继承,并使用super 调用父类方法:

class Employee extends Person {
    constructor(name, age, position) {
        super(name, age); // 调用父类构造函数
        this.position = position;
    }

    sayHello() {
        super.sayHello(); // 调用父类方法
        console.log(`I work as a ${this.position}.`);
    }
}

const employee = new Employee('Bob', 25, 'Developer');
employee.sayHello();
// Hello, my name is Bob and I am 25 years old.
// I work as a Developer.

为什么用类?

  1. 规范化结构:使开发者更易给实例连续和维护。
  2. 重用和抽象化:优化了实现,减少重复代码。
  3. 实现应用情境中的复杂功能:如系统属性管理。
  4. 软件兼容性:便于从其他面向对象的语言迁移到JavaScript。

常见面试题

  1. 如何创建一个类?

    • 答案:使用class关键字定义类。类可以包含构造函数和方法。

    示例:

    class Person {
        constructor(name) {
            this.name = name;
        }
    
        sayHello() {
            console.log(`Hello, ${this.name}`);
        }
    }
    
  2. 构造函数的作用是什么?

    • 答案:构造函数是用于初始化类的实例的特殊方法。它在创建对象时自动调用。

    示例:

    class Person {
        constructor(name) {
            this.name = name;
        }
    }
    
    const person = new Person('Alice');
    console.log(person.name); // Alice
    
  3. 类的继承是如何实现的?

    • 答案:通过extends关键字实现继承,并用super调用父类的构造函数和方法。

    示例:

    class Animal {
        constructor(name) {
            this.name = name;
        }
    
        makeSound() {
            console.log('Generic animal sound');
        }
    }
    
    class Dog extends Animal {
        makeSound() {
            console.log('Bark!');
        }
    }
    
    const dog = new Dog('Buddy');
    dog.makeSound(); // Bark!
    
  4. 什么是静态方法?它与实例方法有何区别?

    • 答案:静态方法是属于类本身的方法,而不是实例的方法。通过类名调用,而非实例。

    示例:

    class MathUtil {
        static square(num) {
            return num * num;
        }
    }
    
    console.log(MathUtil.square(4)); // 16
    
  5. 如何实现私有字段?它们的作用是什么?

    • 答案:使用#声明私有字段,保护数据不被外部直接访问。

    示例:

    class Person {
        #id;
    
        constructor(id) {
            this.#id = id;
        }
    
        getId() {
            return this.#id;
        }
    }
    
    const person = new Person(123);
    console.log(person.getId()); // 123
    
  6. 如何通过getter和setter控制属性?

    • 答案:使用getset关键字定义属性访问器,控制属性读取和写入逻辑。

    示例:

    class Person {
        constructor(name) {
            this._name = name;
        }
    
        get name() {
            return this._name;
        }
    
        set name(newName) {
            this._name = newName;
        }
    }
    
  7. JavaScript中的类与传统面向对象语言(如Java)中的类有何不同?

    • 答案:JavaScript的类基于原型,而传统语言的类是基于类型的。
  8. 什么是多态?在JavaScript中如何实现多态?

    • 答案:多态指同一方法在不同对象中具有不同表现。通过继承和方法重写实现。
  9. 如何检测一个对象是否是某个类的实例?

    • 答案:使用instanceof操作符。

    示例:

    console.log(person instanceof Person); // true
    
  10. 类的属性和方法是否可以枚举?

    • 答案:实例属性可以通过Object.keysfor...in枚举,类的方法通常不可枚举。