ES6 面试题及详细答案 80题 (55-61)-- 类与继承

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括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() {}),自动挂载到原型 需手动挂载到prototypeA.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)的作用
  1. 初始化实例属性 :在实例创建时,为实例绑定属性(如this.name = name)。
  2. 返回实例对象 :默认返回this(即新创建的实例),也可手动返回其他对象(但通常不建议)。
  3. 处理实例创建逻辑:如参数验证、默认值设置等。

注意:

  • 一个类只能有一个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关键字的作用
  1. 在子类构造函数中super(参数)用于调用父类的构造函数,必须在访问this之前调用。

    javascript 复制代码
    class Dog extends Animal {
      constructor(name, age) {
        super(name); // 调用父类constructor(name)
        this.age = age; // 必须在super之后访问this
      }
    }
  2. 在子类方法中super.method()用于调用父类的同名方法。

    javascript 复制代码
    class Dog extends Animal {
      eat() {
        super.eat(); // 调用父类的eat()
        console.log(`${this.name}爱吃骨头`);
      }
    }
    const dog = new Dog("旺财");
    dog.eat(); 
    // 输出:
    // 旺财在吃东西
    // 旺财爱吃骨头

注意:

  • 子类若显式定义constructor,必须先调用super(),否则报错。
  • 若子类未定义constructor,会默认生成包含super(...arguments)的构造函数。

59. 子类如何重写父类的方法?

子类重写父类方法是指在子类中定义与父类同名的方法,覆盖父类的实现,实现多态特性。

重写规则
  1. 子类方法名与父类完全一致。
  2. 可通过super.方法名()调用父类的原方法。
  3. 重写后,实例调用该方法时会执行子类的实现。

示例:

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方法有什么作用?如何定义?

gettersetter是类中用于控制属性访问的特殊方法,分别用于获取和设置属性值。

作用

1.** 封装属性访问 :隐藏属性的实际存储方式,对外提供统一的访问接口。
2.
数据验证 :在setter中验证输入值的合法性。
3.
计算属性 **:getter可返回动态计算的结果(如基于其他属性的值)。

定义方式

通过getset关键字定义,语法如下:

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; // 报错:父类私有属性在子类中不可见
  }
}

通过私有成员可实现真正的封装,避免外部修改类的内部状态。

二、80道ES6 面试题目录列表

文章序号 ES6 80道
1 ES6面试题及详细答案80道(01-05)
2 ES6面试题及详细答案80道(06-12)
3 ES6面试题及详细答案80道(13-21)
4 ES6面试题及详细答案80道(22-32)
5 ES6面试题及详细答案80道(33-40)
6 ES6面试题及详细答案80道(41-54)
7 ES6面试题及详细答案80道(55-61)
8 ES6面试题及详细答案80道(62-80)
相关推荐
还是大剑师兰特6 小时前
ES6基础入门教程(80问答)
es6·大剑师·es6基础·es6教程
yangzhi_emo21 小时前
ES6笔记5
前端·笔记·es6
局i1 天前
ES6 类与继承:现代 JavaScript 面向对象编程
前端·javascript·es6
还是大剑师兰特1 天前
Spark面试题及详细答案100道(91-100)-- 编程实践与问题排查
大剑师·spark面试题
上单带刀不带妹2 天前
在 ES6 中如何提取深度嵌套的对象中的指定属性
前端·ecmascript·es6
十八朵郁金香2 天前
深入解析:ES6 中 class 与普通构造器的区别
前端·ecmascript·es6
索迪迈科技2 天前
CommonJS与ES6模块的区别
前端·ecmascript·es6
yangzhi_emo2 天前
ES6笔记4
前端·笔记·es6
蓝天星空2 天前
ES6-Promise用法
前端·javascript·es6