class、实例与原型链

每点一个按钮,控制台会输出这次操作的表达式和真实结果。

[迷你控制台]

一、new 一个实例:constructor 与实例属性

class User {
  static population = 0                 // 静态字段:挂在类上,不在实例上
  constructor(name, age) {
    this.name = name                    // this 指向正在创建的实例
    this.age = age
    User.population++                   // 每 new 一次,总数 +1
  }
  greet() { return `你好,我是 ${this.name}` }   // 方法省略 function 关键字
  get profile() { return `${this.name}(${this.age} 岁)` }  // getter:像读属性一样调用
}

const alice = new User('阿蓝', 28)   // new:创建 → 绑定 this → 返回实例
已创建的实例:[]

二、方法在原型上,不在实例上

Object.keys(alice)                     // ['name', 'age']:实例只装自有数据
Object.getOwnPropertyNames(User.prototype)  // ['constructor', 'greet', 'profile']
alice.hasOwnProperty('greet')          // false:方法不在实例自己身上
'greet' in alice                       // true:顺着原型链找得到

三、私有字段 #count:闭包包的私有状态,语言原生版

第七章用闭包实现过「外部改不了的计数器」,class 的 # 字段是原生方案:类外部访问 counter.#count 是语法错误,counter.count 只是普通读属性,得到 undefined。

class Counter {
  #count = 0                      // # 开头:只有类内部能访问
  increment() { return ++this.#count }
}

const counter = new Counter()
counter.count        // undefined(外部读不到私有字段)
Object.keys(counter) // [](私有字段不参与枚举)

四、extends 继承:super 与 instanceof

class Admin extends User {
  constructor(name, age, level) {
    super(name, age)              // 先调用父类构造器(必须在使用 this 之前)
    this.level = level            // 再补自己的属性
  }
  greet() { return `${super.greet()},也是管理员` }  // 覆盖父类方法,还能调 super 版本
}

admin instanceof Admin   // true
admin instanceof User    // true —— 原型链把两代连在一起
alice instanceof Admin   // false

五、原型链一眼看全:class 只是语法糖

admin → Admin.prototype → User.prototype → Object.prototype → null
        (逐环找属性,找到就用,全链没有就是 undefined)