不能通过继承的访问器属性实现多轨微任务“联动”,因为访问器继承仅委托单次读写操作,不自动同步跨轨道状态;真正联动需播放器集中控制并显式分发,如 masterVolume setter 主动调用各轨 setVolume,并用 queueMicrotask 批量保障异步执行。

不能通过继承的访问器属性实现多轨微任务“联动”——因为联动是运行时协调行为,而访问器继承只解决属性读写委托,不自动触发跨轨道状态同步。
访问器继承的本质是原型委托,不是状态绑定
当你在父类中定义一个带 queueMicrotask 或 Promise.then 的 getter/setter,子类实例访问该属性时,确实会执行父类逻辑。但这仅发生在**对该属性的单次读写操作上**,例如:
-
有效场景:调用
player.volume = 0.7→ 触发 setter → 微任务中更新内部值 → 完成 - 无效假设:以为设一次 volume,所有音轨就自动同步音量 → 实际不会发生,除非你在 setter 里显式遍历并调用各轨的 setVolume
真正需要的是集中控制 + 显式分发
多轨联动的关键不在“继承”,而在播放器实例是否持有所有轨道引用,并在状态变更时统一调度:
- 维护一个中心化的
masterVolume属性(可带微任务包装),但它的 setter 必须主动调用track1.setVolume()、track2.setVolume()等 - 每条音轨暴露自己的
setVolume(level)方法,内部做实际设置(如audioEl.volume = level或mediaStreamTrack.enabled = level > 0) - 若需异步保障(如等待轨道 ready),可在分发前用
queueMicrotask包裹批量调用,确保所有更新在同一个微任务阶段执行
子类重写时务必复用而非覆盖
如果子类要扩展音量逻辑(比如加权限校验或日志),不能直接写同名 getter/setter,否则会遮蔽父类行为:
- ✅ 正确做法:父类把核心逻辑抽成受保护方法
_updateVolume(value),getter/setter 只负责调用它;子类重写_updateVolume并调用super._updateVolume() - ❌ 错误做法:子类写
set volume(v) { this._vol = v; }→ 微任务消失,联动断裂 - ⚠️ 注意:父类定义访问器时需设
configurable: true,否则子类无法用Object.defineProperty重定义
Web 标准限制决定你必须绕过“自动联动”幻想
浏览器没有提供“某属性变更即广播到所有相关轨道”的机制:
-
MediaStreamTrack.volume在规范中不存在,实际可用的是enabled和muted -
HTMLMediaElement不支持多音轨独立音量,只能靠多个元素分别控制 - 任何“监听 volume 变化→自动同步”的尝试,都需你自己实现观察者模式,而不是依赖属性描述符的继承特性











