严格模式下安全管理自定义事件对象的核心是创建、扩展、使用三环节杜绝非法操作;推荐创建时用Object.defineProperty设属性描述符,按需选用preventExtensions、seal或freeze,避免后期补丁式保护。

在严格模式下安全管理自定义事件对象,核心不是“加锁”或“拦截”,而是从创建、扩展、使用三个环节杜绝非法操作——尤其避免对只读/不可配置属性赋值、删除或重复定义。只要对象结构清晰、保护时机得当,就不会触发 TypeError 或 SyntaxError。
明确事件对象的用途,再决定保护级别
不是所有事件对象都需要冻结。根据使用场景选择最轻量级的保护方式:
-
只读配置 + 后续可能添加字段 → 用
Object.preventExtensions()(允许改值、删属性) -
固定结构,禁止增删但允许更新状态 → 用
Object.seal()(如事件类型、时间戳不变,但 payload 可变) -
完全不可变(如序列化后分发的快照) → 用
Object.freeze()(推荐用于最终发布的事件实例)
创建时就设好属性描述符,避免后期补丁式保护
直接用 Object.defineProperty 或 Object.defineProperties 显式声明关键字段的 writable、configurable 和 enumerable,比事后调用 freeze 更可控、更早暴露问题:
"use strict";
const createEvent = (type, detail) => {
return Object.defineProperties(
{},
{
type: { value: type, writable: false, configurable: false },
timestamp: { value: Date.now(), writable: false, configurable: false },
detail: { value: detail, writable: true, configurable: false } // 允许后续更新 detail
}
);
};
const evt = createEvent("user-login", { id: 123 });
evt.detail = { id: 456 }; // ✅ 允许
evt.type = "hack"; // ❌ TypeError: Cannot assign to read only property
避免在事件对象上挂载函数或动态属性
严格模式下,给事件对象添加方法(如 evt.preventDefault)若未正确设置 configurable: true,后续尝试重写或删除极易报错。更安全的做法是:
- 把行为逻辑抽离到独立工具函数,例如
preventDefault(evt),而非依赖evt.preventDefault() - 如需链式调用,用工厂函数返回新对象,不修改原事件:
withMeta(evt, { source: "ui" }) - 禁用
with语句和eval—— 它们会模糊作用域,让事件对象意外被污染
模块环境下默认严格,但要检查第三方事件库兼容性
现代项目多为 ES 模块(.mjs 或含 import/export),已自动启用严格模式。此时需确认所用事件库(如 mitt、tiny-emitter)是否会在内部创建并修改事件对象。若其返回的对象未做保护,建议封装一层:
import mitt from 'mitt';
const emitter = mitt();
emitter.on('data', (payload) => {
const safeEvent = Object.freeze({
type: 'data',
timestamp: Date.now(),
payload: { ...payload } // 浅拷贝防意外修改
});
handleSafeEvent(safeEvent);
});










