JavaScript OR(||)变量赋值说明

JavaScript OR (||) variable assignment explanation

鉴于这段javascript…

1
2
3
4
5
6
7
8
9
var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f = a || b || c || d || e;

alert(f); // 4

有人能给我解释一下这个技巧叫什么吗(我的最佳猜测是在这个问题的标题中!)?它是如何/为什么工作的?

我的理解是变量f将被分配给第一个变量的最接近值(从左到右),这个变量的值既不是空的也不是未定义的,但是我没有找到关于这个技术的很多参考资料,并且已经看到它使用了很多。

另外,这种技术是专门针对javascript的吗?我知道在PHP中做类似的事情会导致f有一个真正的布尔值,而不是d本身的值。


说明见短路评估。这是实现这些操作符的一种常见方法;它不是Javascript独有的。


这样做是为了指定一个默认值,在这种情况下,如果x变量不稳定,则指定y的值。

javascript中的布尔运算符可以返回一个操作数,而不像其他语言那样总是一个布尔结果。

逻辑或运算符(||返回第二个操作数的值,如果第一个操作数不正确,则返回第一个操作数的值。

例如:

1
2
"foo" ||"bar"; // returns"foo"
false ||"bar"; // returns"bar"

错误值是在布尔上下文中使用时强制使用false的值,它们是0nullundefined、空字符串、NaN,当然还有false


JavaScript对逻辑运算符||&&使用短路评估。但是,它不同于其他语言,因为它返回停止执行的最后一个值的结果,而不是truefalse值。

以下值在JavaScript中被认为是错误的。

  • 无效的
  • ""(空字符串)
  • 未定义

忽略了运算符优先规则,并保持简单,下面的示例显示哪个值使计算停止,并作为结果返回。

1
false || null ||"" || 0 || NaN ||"Hello" || undefined //"Hello"

NaN的前5个值是不稳定的,因此它们都是从左到右进行计算的,直到满足第一个真实值"Hello",这使得整个表达式为真,因此任何进一步向上的值都不会进行计算,并且"Hello"作为表达式的结果返回。同样,在这种情况下:

1
1 && [] && {} && true &&"World" && null && 2010 // null

前5个值都是真实的,并且被评估,直到它满足第一个使表达式为假的错误值(null,所以2010不再被评估,null作为表达式的结果返回。

您给出的示例是使用javascript的这个属性来执行分配。它可以用于任何需要在一组值中获得第一个真实或不稳定值的地方。下面的代码将把值"Hello"分配给b,因为这样可以更容易地分配默认值,而不是执行if-else检查。

1
2
var a = false;
var b = a ||"Hello";

您可以将下面的示例称为对该特性的利用,我相信它会使代码更难阅读。

1
2
3
4
var messages = 0;
var newMessagesText ="You have" + messages +" messages.";
var noNewMessagesText ="Sorry, you have no new messages.";
alert((messages && newMessagesText) || noNewMessagesText);

在警报中,我们检查messages是否错误,如果错误,则评估并返回noNewMessagesText,否则评估并返回newMessagesText。因为在这个例子中它是不稳定的,所以我们停在非消息文本处,并警告"Sorry, you have no new messages."


javascript变量不是类型化的,因此可以为f分配一个整数值,即使它是通过布尔运算符分配的。

F被指定为不等于假的最接近值。所以0、false、null、undefined都被传递:

1
alert(null || undefined || false || '' || 0 || 4 || 'bar'); // alerts '4'


它没有任何魔力。像a || b || c || d这样的布尔表达式的计算比较缓慢。interpeter查找a的值,它是未定义的,所以它是假的,所以它继续前进,然后它看到b是空的,它仍然给出错误的结果,所以它继续前进,然后它看到c是同一个故事。最后,它看到d并说"哈,它不是空的,所以我得到了我的结果",它将它赋给最终的变量。

这种技巧在所有动态语言中都有效,这些语言对布尔表达式进行延迟的短路评估。在静态语言中,它不会编译(类型错误)。在渴望评估布尔表达式的语言中,它将返回逻辑值(在本例中为真)。


这个问题已经得到了好几个答案。

总之,这种技术利用了语言编译的一个特性。也就是说,javascript"短路"布尔运算符的计算,并返回与第一个非假变量值或最后一个变量包含的任何内容相关联的值。请参阅Anurag对这些值的解释,这些值将被评估为false。

然而,由于几个原因,使用这种技术并不是很好的实践。

  • 代码可读性:这是使用布尔运算符,如果不理解这种编译方式的行为,则预期结果将是布尔值。
  • 稳定性:这使用了一个编译语言的特性,该特性在多个语言中不一致,因此,它可能是未来变化的目标。
  • 有文档记录的特性:有一个现有的替代方案可以满足这个需求,并且跨更多语言保持一致。这将是三元运算符:

    ()值1:值2。

  • 使用三元运算符确实需要更多的类型,但它清楚地区分了正在计算的布尔表达式和正在分配的值。此外,还可以链接它,因此可以重新创建上面执行的默认分配类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var a;
    var b = null;
    var c = undefined;
    var d = 4;
    var e = 'five';

    var f =  ( a ) ? a :
                    ( b ) ? b :
                           ( c ) ? c :
                                  ( d ) ? d :
                                          e;

    alert(f); // 4


    返回输出第一个真值。

    如果全部为假,则返回最后一个假值。

    例子:

    1
      null || undefined || false || 0 || 'apple'  // Return apple

    它将新变量(z设置为x的值,如果它是"truthy"(非零,有效的对象/数组/函数/不管它是什么)或y的话。这是在不存在x的情况下提供默认值的相对常见的方法。

    例如,如果您有一个接受可选回调参数的函数,则可以提供一个不做任何事情的默认回调:

    4


    它被称为短路操作器。

    短路计算表示,只有当第一个参数不足以确定表达式的值时,才执行或计算第二个参数。当or()函数的第一个参数的计算结果为true时,整体值必须为true。

    它还可以用于设置函数参数的默认值。`

    1
    2
    3
    4
    5
    6
    function theSameOldFoo(name){
      name = name || 'Bar' ;
      console.log("My best friend's name is" + name);
    }
    theSameOldFoo();  // My best friend's name is Bar
    theSameOldFoo('Bhaskar');  // My best friend's name is Bhaskar`

    即设置x时,z的值为x,否则设置y时,其值为z的值。

    它和

    1
    2
    3
    4
    if(x)
      z = x;
    else
      z = y;

    这是可能的,因为javascript中的逻辑运算符不返回布尔值,而是完成操作所需的最后一个元素的值(在OR语句中,它将是第一个非假值,在AND语句中,它将是最后一个)。如果操作失败,则返回false


    根据BillHiggins的博客文章:javascript逻辑或分配习语(2007年2月),这种行为在v1.2版时是正确的(至少如此)

    他还建议另一种用途:"跨浏览器差异的轻型规范化"

    4


    它将计算x,如果x不为空、空字符串或0(逻辑错误),则将其分配给z。如果x为空、空字符串或0(逻辑错误),则将y分配给z。

    1
    2
    3
    4
    var x = '';
    var y = 'bob';
    var z = x || y;
    alert(z);

    将输出"bob";