《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux... 。

文章目录
- 一、本文面试题目录
-
-
- [55. ES6中的class与ES5的构造函数有何区别?](#55. ES6中的class与ES5的构造函数有何区别?)
- [56. 如何定义一个类?类的构造函数(constructor)有什么作用?](#56. 如何定义一个类?类的构造函数(constructor)有什么作用?)
- [57. 类的静态方法(static)与实例方法有何区别?](#57. 类的静态方法(static)与实例方法有何区别?)
- [58. 类的继承如何实现?extends和super关键字的作用是什么?](#58. 类的继承如何实现?extends和super关键字的作用是什么?)
- [59. 子类如何重写父类的方法?](#59. 子类如何重写父类的方法?)
- [60. 类的getter和setter方法有什么作用?如何定义?](#60. 类的getter和setter方法有什么作用?如何定义?)
- [61. 类的私有属性和私有方法如何声明?](#61. 类的私有属性和私有方法如何声明?)
-
- [二、80道ES6 面试题目录列表](#二、80道ES6 面试题目录列表)
一、本文面试题目录
55. ES6中的class与ES5的构造函数有何区别?
ES6的class
是基于ES5构造函数的语法糖,但在语法、功能和行为上存在显著区别:
特性 | ES6 class | ES5 构造函数 |
---|---|---|
定义方式 | 使用class 关键字声明(class A {} ) |
使用function 声明(function A() {} ) |
原型方法定义 | 方法直接写在类体中(method() {} ),自动挂载到原型 |
需手动挂载到prototype (A.prototype.method = function() {} ) |
静态方法 | 通过static 关键字定义(static method() {} ) |
直接挂载到构造函数上(A.method = function() {} ) |
继承 | 使用extends 关键字(class B extends A {} ) |
通过Object.create() 和call 实现(B.prototype = Object.create(A.prototype); B.call(this) ) |
构造函数 | 必须在constructor 中显式调用super() (子类) |
需手动调用父类构造函数(A.call(this) ) |
提升 | 不存在函数提升(需先定义后使用) | 存在函数提升(可先调用后定义) |
私有成员 | 支持通过# 声明私有属性/方法(ES2022) |
无原生支持,需通过闭包模拟 |
语法约束 | 类体中不能有同名方法(会报错) | 允许覆盖原型方法(后定义的生效) |
示例:
javascript
// ES5 构造函数
function PersonES5(name) {
this.name = name;
}
PersonES5.prototype.sayHi = function() {
console.log(`Hi, ${this.name}`);
};
// ES6 class
class PersonES6 {
constructor(name) {
this.name = name;
}
sayHi() {
console.log(`Hi, ${this.name}`);
}
}
56. 如何定义一个类?类的构造函数(constructor)有什么作用?
定义类的方式
ES6通过class
关键字定义类,类体中可包含构造函数、实例方法、静态方法等。
基本语法:
javascript
class ClassName {
// 构造函数
constructor(参数) {
// 初始化实例属性
}
// 实例方法
method1() {}
// 静态方法
static staticMethod() {}
}
示例:
javascript
class Student {
// 构造函数
constructor(name, age) {
this.name = name; // 实例属性
this.age = age;
}
// 实例方法
introduce() {
return `我是${this.name},今年${this.age}岁`;
}
// 静态方法
static getSchool() {
return "阳光小学";
}
}
// 使用类创建实例
const student = new Student("小明", 12);
console.log(student.introduce()); // 输出:我是小明,今年12岁
console.log(Student.getSchool()); // 输出:阳光小学
构造函数(constructor)的作用
- 初始化实例属性 :在实例创建时,为实例绑定属性(如
this.name = name
)。 - 返回实例对象 :默认返回
this
(即新创建的实例),也可手动返回其他对象(但通常不建议)。 - 处理实例创建逻辑:如参数验证、默认值设置等。
注意:
- 一个类只能有一个
constructor
方法,若定义多个会报错。 - 若未显式定义
constructor
,默认会生成一个空构造函数(constructor() {}
)。 - 通过
new
调用类时,会自动执行constructor
。
57. 类的静态方法(static)与实例方法有何区别?
静态方法和实例方法是类中两种不同类型的方法,核心区别如下:
特性 | 静态方法(static) | 实例方法 |
---|---|---|
定义方式 | 用static 关键字修饰 |
直接定义在类体中,无static |
调用方式 | 通过类名调用(ClassName.method() ) |
通过实例调用(instance.method() ) |
this 指向 |
指向类本身(构造函数) | 指向调用该方法的实例 |
作用 | 处理与类相关的通用逻辑(如工具方法、工厂方法) | 处理实例的具体逻辑(依赖实例属性) |
继承关系 | 可被子类继承,子类调用时this 指向子类 |
可被实例继承,子类实例可重写 |
示例:
javascript
class MathUtil {
// 静态方法(工具函数)
static add(a, b) {
return a + b; // this指向MathUtil类
}
// 实例方法(依赖实例属性)
constructor(base) {
this.base = base;
}
multiply(num) {
return this.base * num; // this指向实例
}
}
// 调用静态方法(类名调用)
console.log(MathUtil.add(2, 3)); // 输出:5
// 调用实例方法(实例调用)
const util = new MathUtil(10);
console.log(util.multiply(5)); // 输出:50
应用场景:
- 静态方法:工具类(如
MathUtil
)、工厂方法(如create()
创建实例)。 - 实例方法:操作实例状态的方法(如
user.updateName()
)。
58. 类的继承如何实现?extends和super关键字的作用是什么?
类的继承实现
ES6通过extends
关键字实现类的继承,让子类继承父类的属性和方法。
基本语法:
javascript
class Parent {
// 父类代码
}
class Child extends Parent {
// 子类代码
}
extends
关键字的作用
用于声明子类继承自父类,让子类拥有父类的所有实例方法、静态方法和原型属性。
示例:
javascript
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name}在吃东西`);
}
static getType() {
return "动物";
}
}
// 继承Animal
class Dog extends Animal {
bark() {
console.log(`${this.name}在汪汪叫`);
}
}
const dog = new Dog("旺财");
dog.eat(); // 继承父类方法:输出"旺财在吃东西"
console.log(Dog.getType()); // 继承父类静态方法:输出"动物"
super
关键字的作用
-
在子类构造函数中 :
super(参数)
用于调用父类的构造函数,必须在访问this
之前调用。javascriptclass Dog extends Animal { constructor(name, age) { super(name); // 调用父类constructor(name) this.age = age; // 必须在super之后访问this } }
-
在子类方法中 :
super.method()
用于调用父类的同名方法。javascriptclass Dog extends Animal { eat() { super.eat(); // 调用父类的eat() console.log(`${this.name}爱吃骨头`); } } const dog = new Dog("旺财"); dog.eat(); // 输出: // 旺财在吃东西 // 旺财爱吃骨头
注意:
- 子类若显式定义
constructor
,必须先调用super()
,否则报错。 - 若子类未定义
constructor
,会默认生成包含super(...arguments)
的构造函数。
59. 子类如何重写父类的方法?
子类重写父类方法是指在子类中定义与父类同名的方法,覆盖父类的实现,实现多态特性。
重写规则
- 子类方法名与父类完全一致。
- 可通过
super.方法名()
调用父类的原方法。 - 重写后,实例调用该方法时会执行子类的实现。
示例:
javascript
class Shape {
getArea() {
return 0; // 父类默认实现
}
}
// 子类重写getArea()
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
// 重写父类的getArea()
getArea() {
return Math.PI * this.radius **2; // 圆的面积公式
}
}
// 另一个子类重写getArea()
class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
// 重写父类的getArea()
getArea() {
return this.width * this.height; // 矩形的面积公式
}
}
// 多态:同一方法在不同子类中有不同实现
const circle = new Circle(5);
console.log(circle.getArea()); // 输出:78.5398...
const rectangle = new Rectangle(4, 5);
console.log(rectangle.getArea()); // 输出:20
调用父类方法
重写时若需保留父类逻辑,可通过super
调用:
javascript
class Parent {
greet() {
return "Hello";
}
}
class Child extends Parent {
greet(name) {
// 调用父类greet(),再添加子类逻辑
return `${super.greet()}, ${name}!`;
}
}
const child = new Child();
console.log(child.greet("小明")); // 输出:Hello, 小明!
60. 类的getter和setter方法有什么作用?如何定义?
getter
和setter
是类中用于控制属性访问的特殊方法,分别用于获取和设置属性值。
作用
1.** 封装属性访问 :隐藏属性的实际存储方式,对外提供统一的访问接口。
2. 数据验证 :在setter
中验证输入值的合法性。
3. 计算属性 **:getter
可返回动态计算的结果(如基于其他属性的值)。
定义方式
通过get
和set
关键字定义,语法如下:
javascript
class ClassName {
constructor() {
// 通常用下划线开头的变量存储实际值(约定)
this._property = value;
}
// getter:获取属性值
get property() {
return this._property;
}
// setter:设置属性值
set property(value) {
// 可添加验证逻辑
this._property = value;
}
}
示例:
javascript
class User {
constructor(name) {
this._name = name; // 实际存储的属性
this._age = 0;
}
// 姓名的getter(直接返回)
get name() {
return this._name;
}
// 年龄的getter和setter(带验证)
get age() {
return this._age;
}
set age(value) {
if (value < 0 || value > 150) {
throw new Error("年龄必须在0-150之间");
}
this._age = value;
}
// 计算属性:获取全名(假设_name是名,这里简化)
get fullName() {
return `用户:${this._name}`; // 动态计算
}
}
const user = new User("张三");
console.log(user.name); // 调用getter:输出"张三"
user.age = 25; // 调用setter
console.log(user.age); // 调用getter:输出25
// user.age = 200; // 报错:年龄必须在0-150之间
console.log(user.fullName); // 调用计算属性的getter:输出"用户:张三"
注意:
getter
不能有参数,setter
只能有一个参数。- 访问属性时直接用
user.age
(而非user.age()
),语法上像访问普通属性。
61. 类的私有属性和私有方法如何声明?
ES2022(ES13)正式引入了类的私有成员(属性和方法),通过井号(#) 前缀声明,只能在类内部访问。
私有属性声明
在属性名前加#
,只能在类的构造函数或方法中访问。
示例:
javascript
class BankAccount {
#balance; // 私有属性(余额)
constructor(initialAmount) {
this.#balance = initialAmount; // 类内部可访问
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount; // 类内部修改
}
}
getBalance() {
return this.#balance; // 类内部读取,对外提供接口
}
}
const account = new BankAccount(1000);
console.log(account.getBalance()); // 输出:1000
// 外部无法直接访问私有属性
console.log(account.#balance); // 报错:Private field '#balance' must be declared in an enclosing class
私有方法声明
在方法名前加#
,只能在类内部调用。
示例:
javascript
class Calculator {
#validateNumber(num) { // 私有方法(验证数字合法性)
return typeof num === "number" && !isNaN(num);
}
add(a, b) {
if (!this.#validateNumber(a) || !this.#validateNumber(b)) {
throw new Error("参数必须是数字");
}
return a + b;
}
}
const calc = new Calculator();
console.log(calc.add(2, 3)); // 输出:5
// 外部无法调用私有方法
calc.#validateNumber(5); // 报错:Private method '#validateNumber' must be declared in an enclosing class
特性
1.** 严格私有 :外部(包括子类)无法访问,只能在当前类内部使用。
2. 语法约束 :私有成员名必须以#
开头,且不能与公共成员同名。
3. 无继承 **:子类无法继承父类的私有成员。
示例(子类无法访问父类私有成员):
javascript
class Parent {
#privateField = "父类私有属性";
getParentPrivate() {
return this.#privateField;
}
}
class Child extends Parent {
getChildPrivate() {
return this.#privateField; // 报错:父类私有属性在子类中不可见
}
}
通过私有成员可实现真正的封装,避免外部修改类的内部状态。