Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/429.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript事件系统是否违反LSP?_Javascript_Dom Events_Liskov Substitution Principle - Fatal编程技术网

JavaScript事件系统是否违反LSP?

JavaScript事件系统是否违反LSP?,javascript,dom-events,liskov-substitution-principle,Javascript,Dom Events,Liskov Substitution Principle,我问这个问题更多的是出于好奇,而不是真正关心它,但我一直想知道JavaScript事件系统是否违反了规则 通过调用,我们可以分派任意类型的,可能由注册的 如果我正确理解了LSP,这意味着anyEventListener.handleEvent(anyEvent)不应该失败。但是,通常情况并非如此,因为事件侦听器通常会使用专门的事件子类型的属性 在不支持泛型的类型化语言中,这种设计基本上需要将事件对象向下转换为事件监听器中的预期子类型 根据我的理解,上述设计可能被视为违反LSP。我是对的,还是在通

我问这个问题更多的是出于好奇,而不是真正关心它,但我一直想知道JavaScript事件系统是否违反了规则

通过调用,我们可以分派任意类型的,可能由注册的

如果我正确理解了LSP,这意味着
anyEventListener.handleEvent(anyEvent)
不应该失败。但是,通常情况并非如此,因为事件侦听器通常会使用专门的
事件
子类型的属性

在不支持泛型的类型化语言中,这种设计基本上需要将
事件
对象向下转换为
事件监听器
中的预期子类型

根据我的理解,上述设计可能被视为违反LSP。我是对的,还是在通过注册侦听器时必须提供
类型的简单事实可以防止LSP冲突

编辑:

虽然每个人似乎都在关注
Event
子类没有违反LSP的事实,但实际上我担心
EventListener
实现者会通过强化
EventListener
接口的先决条件来违反LSP。
void handleEvent(在evt事件中)
合同中没有任何内容告诉您,传递错误的
事件
子类型可能会导致故障

在具有泛型的强类型语言中,该接口可以表示为
EventListener
,以便实现者可以使契约显式化,例如
SomeHandler实现EventListener

在JS中,显然没有实际的接口,但是事件处理程序仍然需要符合规范,并且该规范中没有任何内容允许处理程序判断它是否可以处理特定类型的事件

这不是一个真正的问题,因为监听器不需要自己调用,而是由注册了监听器并与特定类型关联的
EventTarget
调用

我只是想知道根据该理论是否违反了LSP。我想知道,为了避免违反(如果从理论上考虑是这样的话),该合同是否需要类似于以下内容(尽管从实用主义角度看,它可能弊大于利):


不,JavaScript事件系统没有违反Liskov替换原则(LSP)

简单地说,LSP施加了以下约束“程序中的对象应可替换为其子类型的实例,而不改变该程序的正确性”

在JavaScript事件系统的特定示例中,
EventListener
接口有一个函数签名,该签名需要一个
事件
类型。实际上,这将通过子类型调用,例如
KeyboardEvent
。这些子类型遵循LSP,因此,如果您提供在
事件
接口上运行的
handleEvent
实现,如果它被传递一个
键盘事件
实例,它也将工作(即程序将是正确的)

然而,这完全是学术性的,因为在实践中,事件处理程序通常希望使用子类型上定义的属性或方法,例如
KeyboardEvent.code
。在“强类型(*)语言(如C#)中,您可以在
handleEvent
函数中从
Event
强制转换为
KeyboardEvent
。因为LSP定义了用子类型替换超级类型时所需的行为,所以从超级类型转换到子类型超出了LSP定义的行为范围

使用JavaScript时,您不需要为了使用
KeyboardEvent
接口而强制转换,但是基本的基本原则适用

简言之,事件系统遵守LSP,但实际上您的
handleEvent
实现将访问超类型方法,因此将超出LSP定义的范围


*
我在这里使用“强类型”这个词的意思非常松散

LSP的含义非常简单:子类型的行为不能违反其超类型行为。“超类型”行为是基于设计定义的,但一般来说,它只是意味着可以继续使用该对象,就像它是项目中任何位置的超类型一样

因此,在您的情况下,它应遵守以下规定:

(1)
键盘事件
可用于预期发生
事件
的任何代码位置

(2) 对于
Event
中的任何函数
Event.func()
,相应的
KeyboardEvent.func()
接受
Event.func()的参数类型或其超类型,返回
Event.func()的类型或其子类型,并仅抛出
Event.func()
抛出的或其子类型

(3) 调用
KeyboardEvent.func()
不会以
Event.func()
无法发生的方式更改
KeyboardEvent
事件部分(数据成员)(历史规则)

LSP不需要的是关于
KeyboardEvent
实现
func()
的任何限制,只要它在概念上符合
Event.func()
的要求。因此,它可以使用
事件
未使用的函数和对象,在您的情况下,包括
事件
超类型无法识别的自身对象的函数和对象

编辑问题:

替换原则要求子类型的行为(概念上)与它的超类型在任何需要超类型的地方的行为相同。 你的名字
interface EventListener {
  void handleEvent(in Event evt);
}
interface EventListener {
  bool handleEvent(in Event evt); //returns wheter or not the event could be handled
}