function printPrototypeChain(domObject) {
let proto = Object.getPrototypeOf(domObject);
while (proto !== null) {
console.log(proto);
proto = Object.getPrototypeOf(proto);
}
}
printPrototypeChain(document.body);
对象 | 描述 |
---|---|
HTMLBodyElement |
这是 HTML 的 <body> 元素,继承自 HTMLElement 。包含了与 <body> 元素相关的属性和方法,如 background 、bgColor 等。 |
HTMLElement |
HTMLElement 接口表示所有的 HTML 元素。几乎所有的 HTML 元素都是继承自 HTMLElement ,该接口包括了一些常用的属性和方法,如 click() 、focus() 、blur() 、innerText 、innerHTML 、outerHTML 等。 |
Element |
Element 是所有 DOM 元素的基本接口,包括 HTML 元素(通过 HTMLElement 继承)和 SVG 元素。Element 提供了一些常用的方法和属性,如 getAttribute() 、setAttribute() 、removeAttribute() 、hasAttribute() 、querySelector() 、querySelectorAll() 等。 |
Node |
Node 接口是 DOM 中的一个主要接口,它是一个树结构中的一个节点,可以是元素节点、文本节点、注释节点等等。许多接口都从 Node 接口继承,包括 Element 。Node 包括了一些关于节点本身的属性和方法,如 childNodes 、parentNode 、nextSibling 、previousSibling 、appendChild() 、insertBefore() 、removeChild() 、replaceChild() 等。 |
EventTarget |
EventTarget 是一个接口,实现这个接口的对象可以接收事件,并且可以创建监听器(listener)来处理这些事件。Node 接口继承了 EventTarget ,所以 DOM 中的所有节点都实现了这个接口。主要的方法有 addEventListener() 、removeEventListener() 和 dispatchEvent() 。 |
Object |
在 JavaScript 中,几乎所有的对象都是 Object 的实例,从 Object.prototype 继承了方法和属性。这包括数组、函数、日期、正则表达式等。所有的对象都会从 Object 继承一些基本的方法,比如 toString() 、valueOf() 等。 |
观察者模式是一种行为设计模式,它允许你定义一种订阅机制,可以在对象事件发生时通知多个“观察”该对象的其他对象。
在JavaScript中,你可以使用类和回调函数来实现观察者模式。以下是一个简单的示例:
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received data: ${data}`);
}
}
// 使用示例
let subject = new Subject();
let observer1 = new Observer('Observer 1');
let observer2 = new Observer('Observer 2');
let observer3 = new Observer('Observer 3');
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.subscribe(observer3);
subject.notify('Hello, observers!');
在这个示例中,Subject
类有一个observers
数组,用于存储所有的观察者。subscribe
方法用于添加观察者,unsubscribe
方法用于移除观察者,notify
方法用于通知所有的观察者。
Observer
类有一个update
方法,当Subject
通知观察者时,会调用每个观察者的update
方法。
下面是观察者模式的流程图:
在这个图中:
在观察者模式中,观察者和主题之间存在直接关系,观察者直接订阅主题的事件。而在发布订阅模式中,发布者和订阅者之间通常通过事件总线进行通信,它们之间不存在直接关系。
// 定义事件总线
class EventBus {
constructor() {
// 存储事件和监听器的映射
this.events = this.events || new Map();
}
// 监听事件
addListener(type, fn) {
// 如果该事件已经被监听,则直接在对应的数组中添加方法
// 如果该事件没有被监听,则设置对应的数组并添加方法
let callbacks = this.events.get(type)||[];
callbacks.push(fn);
this.events.set(type, callbacks);
}
// 触发事件
emit(type) {
// 获取该事件对应的监听函数队列
let handle = this.events.get(type);
// 执行每一个监听函数
handle.forEach((ele) => {
ele.apply(this);
})
}
}
// 定义发布者
class Publisher {
constructor(eventBus) {
this.eventBus = eventBus;
}
// 发布事件
publish(type) {
this.eventBus.emit(type);
}
}
// 定义订阅者
class Subscriber {
constructor(eventBus, type) {
// 订阅感兴趣的事件
eventBus.addListener(type, this.update);
}
// 当事件发生时,会调用这个方法
update() {
console.log('Subscriber received event');
}
}
// 使用示例
let eventBus = new EventBus();
let publisher = new Publisher(eventBus);
let subscriber1 = new Subscriber(eventBus, 'event1');
let subscriber2 = new Subscriber(eventBus, 'event1');
// 发布者发布事件
publisher.publish('event1');
这个代码示例展示了一个简单的发布订阅模式的实现。在这个例子中,我们定义了一个事件总线EventBus
,它负责管理事件和监听器的映射。发布者Publisher
可以发布事件,订阅者Subscriber
可以订阅事件。当发布者发布一个事件时,所有订阅了这个事件的订阅者都会收到通知。
EventTarget
是一个 DOM 接口,被实现在能够触发事件的对象,或者说,能够创建和触发事件监听器的对象上。在 DOM 中,许多类型的对象,例如 Document
,HTMLElement
,和 XMLHttpRequest
等都实现了 EventTarget
接口,使得它们能够注册、触发和接收事件。
EventTarget
主要提供了以下三个方法:
addEventListener(type, listener)
: 注册一个事件监听器到 EventTarget
上。这个事件监听器在特定类型的事件发生时被触发。
type
: 一个字符串,代表监听器要接收的事件的类型,如 'click', 'keydown' 等。listener
: 当事件发生时被调用的函数或者是一个实现了 EventListener
接口的对象。该函数接收一个参数,这个参数是一个 Event
对象。removeEventListener(type, listener)
: 移除已经注册到 EventTarget
的特定的事件监听器。
addEventListener
相同。dispatchEvent(event)
: 发送一个事件到 EventTarget
,使得 EventTarget
上的监听器能够接收这个事件
event
: 一个 Event
对象,或者是继承自 Event
的对象。以下是一个简单的 EventTarget
使用示例:
<body>
<button>click</button>
<script>
let btn = document.querySelector("button");
const handleClick = function (event) {
console.log("Button is clicked!");
}
btn.addEventListener("click", handleClick);
let clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
</script>
</body>
// 定义一个名为EventTarget的类
class EventTarget {
// 构造函数
constructor() {
// 初始化一个空对象,用于存储事件和对应的回调函数
this.listeners = {};
}
// 添加事件监听的方法
addEventListener(type, callback) {
// 如果事件类型在listeners对象中不存在,则在listeners对象中创建一个该类型的数组
if (!(type in this.listeners)) {
this.listeners[type] = [];
}
// 将回调函数添加到对应事件的数组中
this.listeners[type].push(callback);
}
// 移除事件监听的方法
removeEventListener(type, callback) {
// 如果事件类型在listeners对象中不存在,则直接返回
if (!(type in this.listeners)) {
return;
}
// 获取对应事件类型的回调函数栈
let stack = this.listeners[type];
// 遍历回调函数栈,如果找到要移除的回调函数,则移除
for (let i = 0, l = stack.length; i < l; i++) {
if (stack[i] === callback) {
stack.splice(i, 1);
return;
}
}
}
// 触发事件的方法
dispatchEvent(event) {
// 如果事件类型在listeners对象中不存在,则直接返回true
if (!(event.type in this.listeners)) {
return true;
}
// 获取对应事件类型的回调函数栈
let stack = this.listeners[event.type];
// 遍历回调函数栈,依次执行每个回调函数
for (let i = 0, l = stack.length; i < l; i++) {
stack[i].call(this, event);
}
}
}