diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index 983e2671b7bb6e..02ea2b8f0fff48 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -42,32 +42,30 @@ function lazyNow() { return perf_hooks.performance.now(); } +// TODO(joyeecheung): V8 snapshot does not support instance member +// initializers for now: +// https://bugs.chromium.org/p/v8/issues/detail?id=10704 +const kType = Symbol('type'); +const kDefaultPrevented = Symbol('defaultPrevented'); +const kCancelable = Symbol('cancelable'); +const kTimestamp = Symbol('timestamp'); +const kBubbles = Symbol('bubbles'); +const kComposed = Symbol('composed'); +const kPropagationStopped = Symbol('propagationStopped'); class Event { - #type = undefined; - #defaultPrevented = false; - #cancelable = false; - #timestamp = lazyNow(); - - // None of these are currently used in the Node.js implementation - // of EventTarget because there is no concept of bubbling or - // composition. We preserve their values in Event but they are - // non-ops and do not carry any semantics in Node.js - #bubbles = false; - #composed = false; - #propagationStopped = false; - - constructor(type, options) { if (arguments.length === 0) throw new ERR_MISSING_ARGS('type'); if (options != null) validateObject(options, 'options'); const { cancelable, bubbles, composed } = { ...options }; - this.#cancelable = !!cancelable; - this.#bubbles = !!bubbles; - this.#composed = !!composed; - this.#type = `${type}`; - this.#propagationStopped = false; + this[kCancelable] = !!cancelable; + this[kBubbles] = !!bubbles; + this[kComposed] = !!composed; + this[kType] = `${type}`; + this[kDefaultPrevented] = false; + this[kTimestamp] = lazyNow(); + this[kPropagationStopped] = false; // isTrusted is special (LegacyUnforgeable) Object.defineProperty(this, 'isTrusted', { get() { return false; }, @@ -87,10 +85,10 @@ class Event { }); return `${name} ${inspect({ - type: this.#type, - defaultPrevented: this.#defaultPrevented, - cancelable: this.#cancelable, - timeStamp: this.#timestamp, + type: this[kType], + defaultPrevented: this[kDefaultPrevented], + cancelable: this[kCancelable], + timeStamp: this[kTimestamp], }, opts)}`; } @@ -99,20 +97,22 @@ class Event { } preventDefault() { - this.#defaultPrevented = true; + this[kDefaultPrevented] = true; } get target() { return this[kTarget]; } get currentTarget() { return this[kTarget]; } get srcElement() { return this[kTarget]; } - get type() { return this.#type; } + get type() { return this[kType]; } - get cancelable() { return this.#cancelable; } + get cancelable() { return this[kCancelable]; } - get defaultPrevented() { return this.#cancelable && this.#defaultPrevented; } + get defaultPrevented() { + return this[kCancelable] && this[kDefaultPrevented]; + } - get timeStamp() { return this.#timestamp; } + get timeStamp() { return this[kTimestamp]; } // The following are non-op and unused properties/methods from Web API Event. @@ -121,19 +121,19 @@ class Event { composedPath() { return this[kTarget] ? [this[kTarget]] : []; } get returnValue() { return !this.defaultPrevented; } - get bubbles() { return this.#bubbles; } - get composed() { return this.#composed; } + get bubbles() { return this[kBubbles]; } + get composed() { return this[kComposed]; } get eventPhase() { return this[kTarget] ? Event.AT_TARGET : Event.NONE; } - get cancelBubble() { return this.#propagationStopped; } + get cancelBubble() { return this[kPropagationStopped]; } set cancelBubble(value) { if (value) { this.stopPropagation(); } } stopPropagation() { - this.#propagationStopped = true; + this[kPropagationStopped] = true; } static NONE = 0; @@ -157,15 +157,8 @@ Object.defineProperty(Event.prototype, SymbolToStringTag, { // the linked list makes dispatching faster, even if adding/removing is // slower. class Listener { - next; - previous; - listener; - callback; - once; - capture; - passive; - constructor(previous, listener, once, capture, passive) { + this.next = undefined; if (previous !== undefined) previous.next = this; this.previous = previous; @@ -197,7 +190,9 @@ class EventTarget { // symbol as EventTarget may be used cross-realm. See discussion in #33661. static [kIsEventTarget] = true; - [kEvents] = new Map(); + constructor() { + this[kEvents] = new Map(); + } [kNewListener](size, type, listener, once, capture, passive) {} [kRemoveListener](size, type, listener, capture) {} @@ -355,17 +350,22 @@ Object.defineProperty(EventTarget.prototype, SymbolToStringTag, { value: 'EventTarget', }); +const kMaxListeners = Symbol('maxListeners'); +const kMaxListenersWarned = Symbol('maxListenersWarned'); class NodeEventTarget extends EventTarget { static defaultMaxListeners = 10; - #maxListeners = NodeEventTarget.defaultMaxListeners; - #maxListenersWarned = false; + constructor() { + super(); + this[kMaxListeners] = NodeEventTarget.defaultMaxListeners; + this[kMaxListenersWarned] = false; + } [kNewListener](size, type, listener, once, capture, passive) { - if (this.#maxListeners > 0 && - size > this.#maxListeners && - !this.#maxListenersWarned) { - this.#maxListenersWarned = true; + if (this[kMaxListeners] > 0 && + size > this[kMaxListeners] && + !this[kMaxListenersWarned]) { + this[kMaxListenersWarned] = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax const w = new Error('Possible EventTarget memory leak detected. ' + @@ -382,12 +382,12 @@ class NodeEventTarget extends EventTarget { setMaxListeners(n) { validateInteger(n, 'n', 0); - this.#maxListeners = n; + this[kMaxListeners] = n; return this; } getMaxListeners() { - return this.#maxListeners; + return this[kMaxListeners]; } eventNames() {