类
类是用于创建对象的模板。它们用代码封装数据以对其进行处理。JS 中的类建立在原型之上,同时还具有一些类独有的语法和语义。
类实际上是“特殊的函数”
构造函数
ES6之前
对比以下通过面向对象的构造函数实现的封装:
js
function Person(name,age) {
this.name = name
this.age = age
// 对象方法
this.sing = () => {
console.log('我会唱歌')
}
}
// 实例对像,获得了构造函数中封装的所有逻辑
let p1 = new Person('刘德华', 50)
console.log(p1.name) // 刘德华
// 实例对象
let p2 = new Person('张学友', 55)
console.log(p2.name) //
// 不同对象的方法内存不一样,浪费内存
console.log(p1.sing === p2.sing) // false
封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。
同样的将变量和函数组合到了一起并能通过 this 实现数据的共享,所不同的是借助构造函数创建出来的实例对象之间是彼此不影响的。
总结:
- 构造函数体现了面向对象的封装特性
- 构造函数实例创建的对象彼此独立、互不影响
封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。
前面我们学过的构造函数方法很好用,但是 存在浪费内存
的问题
js
// 定义构造函数
function Person(name, age) {
this.name = name;
this.age = age;
// 实例方法
this.sayHello = function() {
console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
};
}
// 添加原型方法,不会浪费内存
Person.prototype.getDetails = function() {
return `${this.name} is ${this.age} years old.`;
};
// 创建实例
var john = new Person('John Doe', 30);
// 调用实例方法
john.sayHello();
console.log(john.getDetails());
Class语法糖
在JavaScript中,class
是 ECMAScript 6(ES6)引入的一种新的语法结构,它使得开发者能够以一种更加清晰、简洁的方式定义类(classes),从而更好地支持面向对象编程(OOP)特性。尽管JavaScript本质上是一种基于原型的语言,但 class
语法让开发者可以像在其他支持类的编程语言中那样创建类,并通过继承实现复用和扩展。
constructor
方法是用于创建和初始化一个由类创建的对象的特殊方法。
js
// 定义类
class Person {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
// 原型方法(默认就是定义在原型上)
getDetails() {
return `${this.name} is ${this.age} years old.`;
}
}
// 创建实例
const jane = new Person('Jane Smith', 28);
// 调用实例方法
console.log(jane.getDetails());
class
还支持继承:
js
// 定义一个Employee类,继承自Person类
class Employee extends Person {
constructor(name, age, position) {
super(name, age); // 使用super调用父类的构造函数
this.position = position;
}
introduce() {
console.log(`I am ${this.name}, a ${this.position}.`);
}
}
let bob = new Employee('Bob', 30, 'Engineer');
bob.sayHello(); // 继承自Person类的方法
bob.introduce(); // Employee类特有的方法
静态属性和方法
static
关键字用来定义类的静态方法或字段。静态属性(字段和方法)被定义在类的自身而不是类的实例上。
js
class Person {
static age = 18
static getName() {
console.log('hello world');
}
}
const p = new Person();
Person.getName() // 通过类调用静态方法
console.log(Person.age); // 通过类调用静态属性
私有属性
从类的外部引用私有字段是错误的,它们只能在类主体的内部被读写。私有字段只能在字段声明中预先声明。它们不像普通属性那样可以通过赋值创建。
js
class Rectangle {
// 私有字段必须在封闭类中声明。
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
getHeight() {
return this.#height;
}
}
const r = new Rectangle(10, 20);
console.log(r.height); // undefined
console.log(r.getHeight()); // 10
继承
extends
关键字用于类声明或类表达式中,用以创建一个类作为另一构造函数(类或函数)的子类。
如果子类中定义了构造函数,那么它必须先调用 super()
才能使用 this
。super
关键字也可以用来调用父类中对应的方法。
js
class Animal {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 使用super关键字调用父类构造函数
this.breed = breed;
}
bark() {
console.log('Woof!');
}
}
let dog = new Dog('Charlie', 'Poodle');
dog.sayName(); // 输出: Charlie
dog.bark(); // 输出: Woof!