← 返回题目列表

ES6 class 的本质是什么?和原型有什么关系?

高频 中等 第 11 / 28 题 更新于 2026/07/27
ES6class原型继承

简化版

ES6 class 本质上仍然基于原型,是构造函数和原型继承的语法糖。类方法定义在 prototype 上,extends 建立子类和父类之间的原型关系,super 用来调用父类构造函数或方法。

详细版

示例:

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

say 实际在 Person.prototype 上,而不是每个实例一份。

继承:

class Student extends Person {
  constructor(name, grade) {
    super(name);
    this.grade = grade;
  }
}

子类构造函数里必须先调用 super() 才能使用 this。class 不会变量提升,类体默认严格模式。

完整版教学

一、class 改善的是写法

ES5 写构造函数和原型方法比较分散:

function Person(name) {
  this.name = name;
}
Person.prototype.say = function () {};

class 把构造函数、实例方法、静态方法集中起来,可读性更好,但底层对象模型仍是原型。

二、实例方法和静态方法

类体中普通方法放在原型上,实例共享:

class A {
  foo() {}
}

静态方法属于类本身:

class A {
  static create() {}
}

实例不能直接访问静态方法。

三、extends 做了什么

extends 建立两条关系:子类实例能访问父类原型方法;子类构造函数也能继承父类静态方法。

super() 在构造函数里调用父类构造器;super.method() 在方法里调用父类原型方法。派生构造器的 thissuper() 完成前尚未初始化,因此提前读取或返回默认的 this 都会失败。

四、class 字段和箭头方法

现代 JS 支持类字段:

class Counter {
  count = 0;
  inc = () => {
    this.count++;
  };
}

箭头方法能绑定实例 this,但每个实例都会创建一份函数,不像原型方法共享。要按场景选择。

五、面试追问与工程落地

class 常见追问是“类声明有没有提升”。类声明存在类似提升的绑定,但在初始化前处于暂时性死区,不能像函数声明一样在声明前安全调用。这一点和 let/const 的行为更接近。

还会追问私有字段。现代 JS 支持 #field 私有字段,它是语言层面的私有,不是 TypeScript 的 private 那种编译期限制。#count 只能在类内部访问,外部无法通过普通属性名读取。

工程里要注意 class 字段箭头函数和原型方法的取舍。箭头字段自动绑定 this,但每个实例一份;原型方法共享,但传给回调时可能丢 this。写组件、SDK、工具类时要按实例数量和回调场景选择。

六、从原型链还原 class 的真实语义

class 仍使用原型链组织继承:实例方法位于 Ctor.prototype,静态方法位于构造器对象,实例通过 [[Prototype]] 找到共享方法。但它不是普通构造函数的逐字符替换:类体默认严格模式,类声明存在暂时性死区,类方法默认不可枚举,类构造器也不能脱离 new 直接调用。

class User {
  login() {}
  static create() { return new User() }
}
const user = new User()
console.log(Object.getPrototypeOf(user) === User.prototype) // true
console.log(Object.hasOwn(user, 'login'))                    // false
console.log(Object.hasOwn(User, 'create'))                   // true
成员写法存放位置1000 个实例通常有几份函数
login() {}User.prototype1
static create() {}User1
login = () => {}每个实例1000

派生类构造器在使用 this 前必须调用 super(),因为基类构造过程负责创建并初始化本次实例。私有字段 #name 由语言在运行时做品牌检查,不等同于 _name 命名约定,也不能通过普通字符串属性访问。

面试回答“class 是语法糖”后必须补充严格模式、不可直接调用、方法不可枚举和私有字段等额外语义,否则容易被追问击穿。

七、常见误区与追问

  • 误区:class 创建了不同于原型链的新继承模型。 它提供类式语法,底层实例查找仍依靠原型链。
  • 误区:类里的所有方法都在实例上。 普通实例方法共享在原型上,只有实例字段和字段箭头函数等会落到实例自身。
  • 误区:static 方法能直接访问实例字段。 静态方法的接收者是类构造器,没有某个实例的状态,除非显式接收实例。
  • 追问:为什么派生类必须先调用 super? 在派生构造器中,this 要等基类构造完成后才被初始化,提前访问会抛出 ReferenceError
  • 追问:类方法被解构后为什么可能丢失 this? 调用位置不再提供实例接收者;可在调用处绑定,或有意识地使用实例箭头字段。
  • 追问:私有字段和下划线字段有什么区别? #field 有语言级封装和品牌检查,_field 只是团队约定,外部仍可读写。
  • 追问:继承静态成员和继承实例成员是同一条链吗? 不是;构造器之间和各自的 prototype 对象之间形成两条相关的原型链。

八、加强记忆

class 是“原型继承穿西装”。语法像传统面向对象,底层仍靠原型链;普通方法在 prototype,静态方法在类本身,子类用 super 连接父类逻辑。

最终要能从实例成员、原型成员和静态成员三处定位属性,才能真正解释方法共享、继承与 this