Late object initialization in Target class

This commit is contained in:
Michał Zielański
2020-06-15 17:33:51 +02:00
parent 0e8f0034ab
commit 517c9e6b52
2 changed files with 29 additions and 29 deletions
+27 -24
View File
@@ -39,22 +39,22 @@ class Target extends Disposable {
this.eventTarget_ = opt_target; this.eventTarget_ = opt_target;
/** /**
* @name pendingRemovals_
* @private * @private
* @type {!Object<string, number>} * @type {!Object<string, number>}
*/ */
this.pendingRemovals_ = {};
/** /**
* @name dispatching_
* @private * @private
* @type {!Object<string, number>} * @type {!Object<string, number>}
*/ */
this.dispatching_ = {};
/** /**
* @name listeners_
* @private * @private
* @type {!Object<string, Array<import("../events.js").Listener>>} * @type {!Object<string, Array<import("../events.js").Listener>>}
*/ */
this.listeners_ = {};
} }
/** /**
@@ -65,11 +65,8 @@ class Target extends Disposable {
if (!type || !listener) { if (!type || !listener) {
return; return;
} }
let listeners = this.listeners_[type]; let listeners = this.listeners_ || (this.listeners_ = {});
if (!listeners) { listeners = listeners[type] || (listeners[type] = []);
listeners = [];
this.listeners_[type] = listeners;
}
if (listeners.indexOf(listener) === -1) { if (listeners.indexOf(listener) === -1) {
listeners.push(listener); listeners.push(listener);
} }
@@ -92,14 +89,17 @@ class Target extends Disposable {
if (!evt.target) { if (!evt.target) {
evt.target = this.eventTarget_ || this; evt.target = this.eventTarget_ || this;
} }
const listeners = this.listeners_[type]; const listeners = this.listeners_ && this.listeners_[type];
let propagate; let propagate;
if (listeners) { if (listeners) {
if (!(type in this.dispatching_)) { const dispatching = this.dispatching_ || (this.dispatching_ = {});
this.dispatching_[type] = 0; const pendingRemovals =
this.pendingRemovals_[type] = 0; this.pendingRemovals_ || (this.pendingRemovals_ = {});
if (!(type in dispatching)) {
dispatching[type] = 0;
pendingRemovals[type] = 0;
} }
++this.dispatching_[type]; ++dispatching[type];
for (let i = 0, ii = listeners.length; i < ii; ++i) { for (let i = 0, ii = listeners.length; i < ii; ++i) {
if ('handleEvent' in listeners[i]) { if ('handleEvent' in listeners[i]) {
propagate = /** @type {import("../events.js").ListenerObject} */ (listeners[ propagate = /** @type {import("../events.js").ListenerObject} */ (listeners[
@@ -115,14 +115,14 @@ class Target extends Disposable {
break; break;
} }
} }
--this.dispatching_[type]; --dispatching[type];
if (this.dispatching_[type] === 0) { if (dispatching[type] === 0) {
let pendingRemovals = this.pendingRemovals_[type]; let pr = pendingRemovals[type];
delete this.pendingRemovals_[type]; delete pendingRemovals[type];
while (pendingRemovals--) { while (pr--) {
this.removeEventListener(type, VOID); this.removeEventListener(type, VOID);
} }
delete this.dispatching_[type]; delete dispatching[type];
} }
return propagate; return propagate;
} }
@@ -132,7 +132,7 @@ class Target extends Disposable {
* Clean up. * Clean up.
*/ */
disposeInternal() { disposeInternal() {
clear(this.listeners_); this.listeners_ && clear(this.listeners_);
} }
/** /**
@@ -140,10 +140,10 @@ class Target extends Disposable {
* order that they will be called in. * order that they will be called in.
* *
* @param {string} type Type. * @param {string} type Type.
* @return {Array<import("../events.js").Listener>} Listeners. * @return {Array<import("../events.js").Listener>|undefined} Listeners.
*/ */
getListeners(type) { getListeners(type) {
return this.listeners_[type]; return this.listeners_ && this.listeners_[type];
} }
/** /**
@@ -152,6 +152,9 @@ class Target extends Disposable {
* @return {boolean} Has listeners. * @return {boolean} Has listeners.
*/ */
hasListener(opt_type) { hasListener(opt_type) {
if (!this.listeners_) {
return false;
}
return opt_type return opt_type
? opt_type in this.listeners_ ? opt_type in this.listeners_
: Object.keys(this.listeners_).length > 0; : Object.keys(this.listeners_).length > 0;
@@ -162,11 +165,11 @@ class Target extends Disposable {
* @param {import("../events.js").Listener} listener Listener. * @param {import("../events.js").Listener} listener Listener.
*/ */
removeEventListener(type, listener) { removeEventListener(type, listener) {
const listeners = this.listeners_[type]; const listeners = this.listeners_ && this.listeners_[type];
if (listeners) { if (listeners) {
const index = listeners.indexOf(listener); const index = listeners.indexOf(listener);
if (index !== -1) { if (index !== -1) {
if (type in this.pendingRemovals_) { if (this.pendingRemovals_ && type in this.pendingRemovals_) {
// make listener a no-op, and remove later in #dispatchEvent() // make listener a no-op, and remove later in #dispatchEvent()
listeners[index] = VOID; listeners[index] = VOID;
++this.pendingRemovals_[type]; ++this.pendingRemovals_[type];
+2 -5
View File
@@ -24,9 +24,6 @@ describe('ol.events.EventTarget', function () {
expect(eventTarget).to.be.a(EventTarget); expect(eventTarget).to.be.a(EventTarget);
expect(eventTarget).to.be.a(Disposable); expect(eventTarget).to.be.a(Disposable);
}); });
it('creates an empty listeners_ object', function () {
expect(Object.keys(eventTarget.listeners_)).to.have.length(0);
});
it('accepts a default target', function (done) { it('accepts a default target', function (done) {
const defaultTarget = {}; const defaultTarget = {};
const target = new EventTarget(defaultTarget); const target = new EventTarget(defaultTarget);
@@ -41,11 +38,11 @@ describe('ol.events.EventTarget', function () {
describe('#hasListener', function () { describe('#hasListener', function () {
it('reports any listeners when called without argument', function () { it('reports any listeners when called without argument', function () {
expect(eventTarget.hasListener()).to.be(false); expect(eventTarget.hasListener()).to.be(false);
eventTarget.listeners_['foo'] = [function () {}]; eventTarget.addEventListener('foo', function () {});
expect(eventTarget.hasListener()).to.be(true); expect(eventTarget.hasListener()).to.be(true);
}); });
it('reports listeners for the type passed as argument', function () { it('reports listeners for the type passed as argument', function () {
eventTarget.listeners_['foo'] = [function () {}]; eventTarget.addEventListener('foo', function () {});
expect(eventTarget.hasListener('foo')).to.be(true); expect(eventTarget.hasListener('foo')).to.be(true);
expect(eventTarget.hasListener('bar')).to.be(false); expect(eventTarget.hasListener('bar')).to.be(false);
}); });