具有自定义属性的JS布尔运算是否不好?


41

在JS中,您可以返回具有自定义属性的布尔值。例如。当Modernizr测试视频支持时,它返回truefalse但是返回的布尔值(布尔是JS中的第一类对象)具有指定支持哪种格式的属性。起初它使我感到有些惊讶,但后来我开始喜欢这个主意,并开始怀疑为什么它似乎很少使用?

它看起来像是一种优雅的方式来处理所有这些情况,在这些情况下,您基本上想知道某件事是对还是错,但是您可能对无需定义自定义返回对象或不准备使用回调函数就可以定义的一些其他信息感兴趣。接受更多参数。这样,您可以保留非常通用的功能签名,而不会影响返回更复杂数据的能力。

我可以想象有3种反对的说法:

  1. 当最好使任何界面清晰明了而不棘手时,这是不常见/意外的。
  2. 这可能是一个稻草人的论点,但由于它有点极端,我可以想象它在某些JS优化器,uglifier,VM中或在稍作清理语言规范更改后悄然适得其反。
  3. 有更好的方法-简洁,清晰和通用-完全相同。

所以我的问题是,有什么充分的理由要避免将布尔值与其他属性一起使用?他们是把戏还是款待?


绘制扭曲警告。

以上是最初的问题。正如Matthew Crumley和senevoldsen都指出,这是基于错误的(虚假的?)前提。按照优良的JS传统,Modernizr所做的只是一种语言技巧而又是一种肮脏的手段。归结为具有原始bool的JS,如果将其设置为false,即使在尝试添加道具后(它会默默失败),布尔对象仍将为false;而布尔对象可以具有自定义道具,但成为对象始终是真实的。Modernizr返回布尔布尔值false或真实布尔值对象。

我最初的问题是假设技巧不一样,因此最流行的答案涉及(完全有效的)编码标准方面。但是,我发现揭穿整个窍门的答案最有帮助(以及反对使用该方法的最终论点),因此我接受其中一个。感谢所有参与者!


35
扩展布尔类型是经典的wtf
hlovdal

7
请注意,在JS中,null如果不支持,它们可能只是返回了,如果是,则返回了一组格式。列表在JS中被认为null是真实的,并且是虚假的。
jpmc26


3
在回答这个问题之前:在javascript中,“布尔值”和“布尔值”之间有很大的区别。它们不是一回事,任何不大写布尔值的答案都是无效的。
Pieter B

2
对于那些你谁是惊讶地看到像这样在野外,在库一样受欢迎Modernizr的,这里是他们的GitHub上的相关代码:github.com/Modernizr/Modernizr/blob/...
克里斯·尼尔森

Answers:


38

除了一般的设计原则(如单一职责和最少的意外)外,还有一个特定于JavaScript的原因,它不是一个好主意:a booleanBooleanJavaScript 之间的巨大差异使它无法在一般情况下正常工作。

boolean是基本类型,不是对象,并且不能具有自定义属性。表达式true.toString()之所以像工作,是因为它在后台变成了(new Boolean(true)).toString()

Boolean(使用大写字母B)一个对象,但很少有很好的用途,而被用作a boolean绝对不是其中之一。这样做的原因是,无论其值是什么,每个Boolean都是“ true”,因为所有对象都true在布尔上下文中转换为。例如,尝试以下操作:

var answer = new Boolean(false);
if (answer) {
  console.log("That was unexpected.");
}

因此,通常来说,没有办法向JavaScript中的布尔值添加属性,而该属性仍然允许其以逻辑方式运行。Modernizr可以避免使用它,因为仅将属性添加到“ true”值,您可以期望这种工作方式(即,它们在if语句中起作用)。如果根本不支持视频,Modernizr.video则将是实际视频boolean(具有值false),并且不能为其添加属性。


18
考虑到仅具有属性的对象已经true在条件中求值,我发现Modernizr的方法很奇怪。为什么要明确使用Boolean
Arturo TorresSánchez17年

非常感谢您提出合理的技术论点。我的快速测试似乎有缺陷:jsbin.com/hurebi/3/edit?js,console。即使在向其添加自定义道具后,false严格来说都是“ false”和falsy(=====用作),但实际上您实际上无法向原始布尔添加道具。布尔和布尔之间的区别显然使我不知所措。
konrad

@ArturoTorresSánchez,因为它们执行返回值的方式名义上是相同类型的。
加里德·史密斯

1
@ArturoTorresSánchez,这就是为什么我“名义上”添加了限定词的原因:P
Jared Smith,

1
@konrad作为参考,默认情况下,JavaScript会假装它使您可以通过在尝试进行操作时不抱怨来向基元添加属性。使用严格模式将解决此问题,TypeError如果尝试添加属性,则抛出异常(请参见jsbin.com/yovasafibo/edit?js,console)。
马修·克鲁姆利

59

恭喜,您已找到对象。不这样做的原因被称为最小惊讶原则。对设计感到惊讶不是一件好事。

将这些信息捆绑在一起没有任何问题,但是为什么要将其隐藏在Bool中呢?将其放在您希望拥有所有这些信息的地方。包括布尔。


1
大声笑是的,我在我的问题中提到对象是显而易见的选择。尽管使用JS弱类型对象并不令人惊讶,但仍然令人困惑,并且无论如何您都需要检查文档,但最小惊讶原则是一个好主意。至于用法,Modernizr是一个很好的例子:您拥有大量具有一致的正确/错误结果的测试,并且直到现在,您才需要传递更多的信息-甚至以后都需要这些信息,因此在这样做时,您可以对整个库进行重大更改,从而在布尔值周围创建大部分多余的包装器,或者增强布尔值。海事组织不是那么愚蠢。
konrad

1
有关用法的更多信息。如果坚持返回布尔值,则可以轻松地将所有函数传递给列出诸如any(),all(),filter()之类的操作。它以有点非常规的方式规避了JS中缺乏强类型或正式接口的情况-到目前为止,这似乎是反对它的主要论点。
konrad

1
在我看来,“非常规”似乎不是一个强有力的论点。
罗伯特·哈维

我编辑了问题。这是最小惊讶的原则。:-)
konrad

16

我反对的主要论点是,单一责任原则,布尔型仅应说某物是truefalse,而不是原因,方式或其他任何东西。我坚信并实践应该使用其他对象来传达该信息或任何其他信息。


您是说javascript中的boolean还是Boolean(大写B)?
Pieter B

但是,如果您有一个定义此对象的对象以及其他一些东西,难道它不违反相同的原理吗?
Casey's

1
@Casey否,因为该对象的用途与原始布尔值不同。举例来说,它只负责传达交易的状态和原因。
J. Pichardo

1
@Casey问题不在于本身包含此信息是否违反了SRP。只有将布尔值已经具有的责任(代表对或错)组合在一起时,这才成为问题。Boolean尽管有JavaScript的恶作剧。
Jacob Raihle

10

由于将其称为布尔值的全部原因是事实是对还是错,所以我不喜欢这个主意,因为您几乎破坏了维基百科的整个目的

在计算机科学中,布尔数据类型是一种数据类型,具有两个值(通常表示为true和false),旨在表示逻辑和布尔代数的真值

(我的粗体)


1
正确,但必要性可能另有规定
svarog

8
@svarog我唯一能看到的就是代码的非熟练设计人员。如果需要返回布尔值其他内容,请将其设为类,元组或列表,或其他适合特定代码的内容。
MatthewRock

如果您返回的是
svarog

我认为问题在于布尔对象而不是布尔基元。对象不是值。
Pieter B

1
如果它可以采取除true或false以外的值,它并不是一个布尔值。顾名思义,这是愚蠢的。
没用

2

仅仅因为您不能意味着应该这样做,所以在JS中您几乎可以将属性附加到任何对象(包括布尔值)

那是怎么一件坏事?

一方面,您可以将更多不相关的数据附加到布尔值上(根据您的示例),这是其他开发人员不会期望的,因为为什么要在那里?布尔值仅代表真假。

一个针对点是附加一些相关的有用属性,这些属性可以帮助您处理布尔值(Java做到了)。

例如,您可以附加一个将布尔值转换为字符串的函数,一个dirty标志(如果该值被更改则变为true),观察器和事件回调(可在该值更改时触发)等。

但是返回的布尔值(布尔是JS中的一流对象)具有指定支持哪些格式的属性

听起来不应该将其存储在布尔值中,而应该使用一组布尔值或其中包含布尔值的一组属性。我认为更好的方法是返回具有所有格式和支持详细信息的对象。

{
    isSomethingSupported: true,
    isSomethingElseSupported: false,
    ....
}

1
您是指布尔型还是布尔型(大写B)?
Pieter B

1

您无法使用JavaScript中的自定义属性创建布尔值。以下失败(至少在FF中):

    var x = false;
    x.foo = "bar";
    console.log(x.foo);

您可以使用布尔值或从布尔值继承,但是正如Matthew Crumley所说的那样,它给出了不同的结果。Boolean类型 Object。当JS需要一个表达式的布尔值时,它使用规范函数进行转换,规范函数ToBoolean要求Object结果始终为true。因此,值new Boolean(false)计算为true!您可以在以下示例中对此进行验证:https : //jsfiddle.net/md7abx5z/3/

它对Modernizr起作用的唯一原因是偶然的。他们仅Boolean在条件为真时创建对象。当他们评估为假时,他们只是返回普通false。之所以如此,是因为它们只在结果为true 时才返回Boolean 对象,而在结果为false 时才返回对象


1

我了解上下文已更改,但是我想回答原始问题,我以JS为例来阅读,但不仅限于JS。

如果将属性添加到布尔值中,如果属性与true / false(而不是包含值的变量)有关,则不会出现问题。例如,添加toYesNoString方法很好,向hasChildren值添加numberOfChildren则不行,对Missed StudentPassed的问题也不会。除了各种字符串表示形式外,您没有什么可以添加到布尔值中的,我能想到的唯一有意义的属性就是originalExpression。但是在理论上添加它并不一定是一个坏主意。


0

如果我看一下代码,这不是真正地提供布尔自定义属性,而是关于具有带有不同签名的返回方法的方法。

如果为假,则表示原始错误,如果为真,则返回一个对象,根据定义,该对象在javascript中被解释为true。

因此,在我看来,您的问题不应该是提供布尔自定义属性是否是一个好主意,而是拥有具有多个返回签名的方法是否是一个好主意。


0

在给定的示例中,您是否不能仅返回所有受支持的视频格式的数组

  • 空数组表示“不支持视频格式 ”,依次表示“不支持视频 ”。
  • 否则,如果支持任何视频格式,则显然显然也支持视频

我至少可以说,使用数组比拥有“自定义布尔值”更令人惊讶。

在Javascript中,一个空数组甚至被认为是虚假的,而一个非空数组则是真实的,因此,幸运的是,您可以切换到数组,并且一切都会像 编辑 Nope 之前一样工作,愚蠢的我以为我记得真实性JavaScript中的对象数量:P


空数组在if语句中不算作false。如果([])console.log('not false'); 例如,在Chrome中显示“ not false”。typeof [] ==='object',因此没有一个空数组不是虚假的。请参阅developer.mozilla.org/en-US/docs/Glossary/Truthy以获取参考。
joshp

@joshp oops,您是对的,我不好。固定
daniero

虽然,我不确定类型的东西能证明什么。""具有typeof,"string"但实际上是虚假的
daniero

1
另一方面,[].length如果length为,则为false 0是没有更多的输入内容,而我认为这是一个更好的意图意图指示,if([])即使它可以工作也是如此。
IllusiveBrian

@daniero关于typeof [] ==='object'的一点是,任何 Object都是真实的,甚至是新的Boolean(false)。某些基本类型(例如,字符串“”和数字0)是虚假的,但就typeof而言,它们不是对象。这只是另一种记忆方式。这与证明任何事情无关。证明在规格或测试中,以您喜欢的为准。
joshp
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.