Подтвердить что ты не робот

Как использовать JavaScript EventTarget?

Я хотел бы создать персонализированный эмитент событий в своих клиентских программах. Я ссылаюсь на эту (разреженную) документацию для EventTarget

Моя попытка реализации

var Emitter = function Emitter() {
  EventTarget.call(this);
};

Emitter.prototype = Object.create(EventTarget.prototype, {
  constructor: {
    value: Emitter
  }
});

Желаемое использование

var e = new Emitter();

e.addEventListener("hello", function() {
  console.log("hello there!");
});

e.dispatchEvent(new Event("hello"));
// "hello there!"

Где он терпит неудачу

var e = new Emitter();
// TypeError: Illegal constructor

Что я делаю неправильно?


Обновление

Возможно следующее, но это хак, который зависит от фиктивного DOMElement

var fake = document.createElement("phony");
fake.addEventListener("hello", function() { console.log("hello there!"); });
fake.dispatchEvent(new Event("hello"));
// "hello there!"

Я хотел бы знать, как это сделать, не используя фиктивный элемент

4b9b3361

Ответ 1

Я отказался от этого некоторое время назад, но в последнее время нуждался в нем снова. Вот что я в итоге использовал.

ES6

class Emitter {
  constructor() {
    var delegate = document.createDocumentFragment();
    [
      'addEventListener',
      'dispatchEvent',
      'removeEventListener'
    ].forEach(f =>
      this[f] = (...xs) => delegate[f](...xs)
    )
  }
}

// sample class to use Emitter
class Example extends Emitter {}

// run it
var e = new Example()
e.addEventListener('something', event => console.log(event))
e.dispatchEvent(new Event('something'))

Ответ 2

Берги был прав относительно части, что EventTarget - это просто интерфейс, а не конструктор.

В js есть несколько объектов, которые являются действительными целями событий. Как упоминалось там: Элемент, документ и окно являются наиболее распространенными целями событий, но есть и другие, например Websocket. В любом случае, все они даются.

Если вы сделаете короткий тест, вы можете заметить несколько вещей:

EventTarget.isPrototypeOf(WebSocket); // true

var div = document.createElement("div");

EventTarget.isPrototypeOf(div.constructor); // true

typeof EventTarget // function

EventTarget() // TypeError: Illegal constructor

EventTarget является прототипом этих конструкторов, который вы не можете установить для какого-либо другого конструктора (и даже если бы вы могли, он, вероятно, не работал). Также это функция, но не вызываемая.

Теперь настало время, когда вы спрашиваете: И что это за EventTarget хорошо и как я могу его использовать?

У нас есть 3 метода, которые необходимо реализовать каждому эмиттеру событий, и, вероятно, необходимо связать эти методы вместе, поэтому у нас есть интерфейс для них. Это означает, что вы не можете использовать EventTarget для целей вызова, но некоторые другие собственные функции могут. Это похоже на создание элементов, у нас есть метод document.createElement factory, и мы не можем (не можем) использовать new HTMLDivElement() для создания нового элемента, но мы можем сравнить конструкторы из двух элементов.

Заключение

Если вы хотите создать собственный эмиттер событий, вам всегда нужно создать какой-нибудь фиктивный объект или использовать уже существующий. С моей точки зрения, не имеет значения, какой именно объект будет.

Некоторые методы не подлежат вызову, но их можно сравнить как свойства объектов. Поэтому они видны. EventTarget является одним из них.

Ответ 3

Вот как это сделать, используя CustomEvent, кросс-браузер (fiddle):

// listen to event
window.addEventListener("say", function(e) { alert(e.detail.word); });

// create and dispatch the event
var event = document.createEvent("CustomEvent");
event.initCustomEvent('say', true, true, 
    { "word": "Hello!" });

window.dispatchEvent(event);

Вам нужно будет использовать window или document или любой другой существующий элемент DOM для регистрации listeneres и отправки события. EventTarget не является объектом, это интерфейс. Попробуйте открыть EventTarget в консоли JavaScript, и вы увидите это.

Ответ 4

EventTarget теперь указан как конструктивный в уровне жизни DOM. Он поддерживается в Chrome 64 (уже отключен) и Firefox 59 (ожидается 13 марта).

Ответ 5

Попробуйте простую реализацию ES6.

class DOMEventTarget {
  constructor() {
    this.listeners = new Map();
  }
  addEventListener(type, listener) {
    this.listeners.set(listener.bind(this), {
      type, listener
    });
  }
  removeEventListener(type, listener) {
    for(let [key, value] of this.listeners){
      if(value.type !== type || listener !== value.listener){
        continue;
      }
      this.listeners.delete(key);
    }
  }
  dispatchEvent(event) {
    Object.defineProperty(event, 'target',{value: this});
    this['on' + event.type] && this['on' + event.type](event);
    for (let [key, value] of this.listeners) {
      if (value.type !== event.type) {
        continue;
      }
      key(event);
    }
  }
}

let eventEmitter = new DOMEventTarget();
eventEmitter.addEventListener('test', e => {
  console.log('addEventListener works');
});
eventEmitter.ontest = e => console.log('ontype works');
eventEmitter.dispatchEvent(new Event('test'));

Ответ 6

Пример фрагмента кода для использования javascript EventTarget

// attach event var ev = EventTarget.prototype.addEventListener.call(null, 'alert', () => alert('ALERTED')) // dispatch event ev.dispatchEvent.call(null, new Event('alert'))