【问题标题】:What does "var FOO = FOO || {}" (assign a variable or an empty object to that variable) mean in Javascript?“var FOO = FOO || {}”(将变量或空对象分配给该变量)在Javascript中是什么意思?
【发布时间】:2011-09-20 08:11:01
【问题描述】:

查看在线源代码,我在几个源文件的顶部遇到了这个。

var FOO = FOO || {};
FOO.Bar = …;

但我不知道|| {} 做了什么。

我知道{} 等于new Object(),我认为|| 是为了“如果它已经存在,则使用它的值,否则使用新对象。

为什么我会在源文件的顶部看到这个?

【问题讨论】:

  • 注意:对问题进行了编辑以反映这是一种常见于 Javascript 源文件顶部的代码模式。

标签: javascript namespaces variable-declaration or-operator


【解决方案1】:

您对|| {} 意图的猜测非常接近。

在文件顶部看到的这种特殊模式用于创建 命名空间,即一个命名对象,可以在该对象下创建函数和变量,而不会过度污染全局对象。

为什么使用它的原因是,如果您有两个(或更多)文件:

var MY_NAMESPACE = MY_NAMESPACE || {};
MY_NAMESPACE.func1 = {
}

var MY_NAMESPACE = MY_NAMESPACE || {};
MY_NAMESPACE.func2 = {
}

两者共享相同的命名空间,然后无论加载两个文件的顺序如何,您仍然可以在 MY_NAMESPACE 对象中正确定义 func1func2

加载的第一个文件将创建初始MY_NAMESPACE对象,随后加载的任何文件将扩充该对象。

有用的是,这还允许 异步 加载共享相同命名空间的脚本,这可以缩短页面加载时间。如果<script> 标签设置了defer 属性,您将无法知道它们将按什么顺序被解释,因此如上所述,这也解决了这个问题。

【讨论】:

  • 原来如此,有几个js文件开头的声明一模一样,多谢!
  • +1 用于阅读字里行间并解释这样做的原因。如果有人给出了用户真正想要的答案,而不仅仅是他要求的答案,这总是好的。 :)
  • 我想说这是 JavaScript 的 #ifndef/#define :)
  • || 在您想提供可选参数并在未提供时将其初始化为默认值时也非常有用:function foo(arg1, optarg1, optarg2) { optarg1 = optarg1 || 'default value 1'; optarg2 = optart2 || 'defalt value 2';}
  • @crazy2be 如果默认值为真则不起作用,但假值也是合法的,因为 || 运算符无法区分 undefinedfalsey
【解决方案2】:
var AEROTWIST = AEROTWIST || {};

基本上这一行是说将AEROTWIST 变量设置为AEROTWIST 变量的值,或者将其设置为一个空对象。

双管道||是一个OR语句,只有在第一部分返回false时才会执行OR的第二部分。

因此,如果AEROTWIST已经有一个值,它将保持为那个值,但如果它之前没有设置,那么它将被设置为一个空对象。

基本上和这样说是一样的:

if(!AEROTWIST) {var AEROTWIST={};}

希望对您有所帮助。

【讨论】:

  • 实际上,在您的上一个示例中,范围会很好,因为 JS 没有块范围
  • @Alnitak - 嗯,你是对的;最近我一直在处理闭包,我忘记了基础知识。我会编辑答案。
【解决方案3】:

var FOO = FOO || {}; 涵盖了两个主要部分。

#1 防止覆盖

假设您将代码拆分为多个文件,并且您的同事也在处理一个名为 FOO 的对象。然后它可能导致有人已经定义了FOO 并为其分配了功能(如skateboard 函数)。然后你会覆盖它,如果你不检查它是否已经存在。

问题案例:

// Definition of co-worker "Bart" in "bart.js"
var FOO = {};

FOO.skateboard = function() {
  alert('I like skateboarding!');
};

// Definition of co-worker "Homer" in "homer.js"
var FOO = {};

FOO.donut = function() {
  alert('I like donuts!');
};

在这种情况下,如果您在 HTML 中的 bart.js 之后加载 JavaScript 文件 homer.js,则 skateboard 函数将消失,因为 Homer 定义了一个新的 FOO 对象(从而覆盖了来自 Bart 的现有对象)所以它只知道donut 函数。

所以你需要使用var FOO = FOO || {};,这意味着“FOO 将被分配给 FOO(如果它已经存在)或一个新的空白对象(如果 FOO 不存在)。

解决方案:

var FOO = FOO || {};

// Definition of co-worker Bart in bart.js
FOO.skateboard = function() {
  alert('I like skateboarding!');
};

// Definition of co-worker Homer in homer.js
var FOO = FOO || {};

FOO.donut = function() {
  alert('I like donuts!');
};

因为 Bart 和 Homer 现在在定义其方法之前检查 FOO 是否存在,所以您可以按任意顺序加载 bart.jshomer.js 而不会覆盖彼此的方法(如果它们具有不同的名称)。所以你总是会得到一个FOO 对象,它有skateboarddonut 方法(耶!)。

#2 定义一个新对象

如果您已经阅读了第一个示例,那么您现在已经知道|| {} 的用途是什么。

因为如果没有现有的FOO 对象,那么 OR-case 将激活并创建一个新对象,因此您可以为其分配功能。喜欢:

var FOO = {};

FOO.skateboard = function() {
  alert('I like skateboarding!');
};

【讨论】:

    【解决方案4】:

    || 的另一个常见用法也是为未定义的函数参数设置默认值:

    function display(a) {
      a = a || 'default'; // here we set the default value of a to be 'default'
      console.log(a);
    }
    
    // we call display without providing a parameter
    display(); // this will log 'default'
    display('test'); // this will log 'test' to the console
    

    其他编程中的等价物通常是:

    function display(a = 'default') {
      // ...
    }
    

    【讨论】:

    • var前面不需要aa作为形参进入函数的执行上下文,因此它已经被声明了。
    【解决方案5】:

    如果 AEROTWIST 中没有值,或者它为 null 或未定义,则分配给新 AEROTWIST 的值将是 {}(一个空白对象)

    【讨论】:

      【解决方案6】:

      || 运算符有两个值:

      a || b
      

      如果 a 是 truthy,它将返回 a。否则,它将返回b

      虚假值为nullundefined0""NaNfalse。真实的价值观就是一切。

      所以如果没有设置a(是undefined),它将返回b

      【讨论】:

      • 我不确定 truthyfalsey 是否应该作为真实的词而永久存在。有趣,但不完全标准。 :-)
      • @Orbling 他们在 JS 中很常用来谈论这些值。
      • +1 用于正确描述运算符,因为它不是逻辑运算符。有时它被称为“默认运算符”。
      • @Tim JS(和 Perl)中的 || 与 C、C++ 和 Java 中的版本之间的唯一区别是 JS 不会将结果转换为布尔值。它仍然是一个逻辑运算符。
      • @Alnitak:可能是因为过去JS开发者的非专业背景。
      【解决方案7】:

      对于 ||操作,JS将返回它找到的FIRST“真实”值(从左到右读取):

      var bob = false || undefined ||  0  ||  null || "hi"
      //          ^          ^         ^      ^        ^
      //          nope       nope      nope   nope     yip
      //
      // => bob = "hi"
      
      // --------------
      // breaking
      // --------------
      var bob = false || "hi" ||  0  ||  null || undefined
      //          ^       ^
      //          nope    yip <-- stops here
      //                          the rest are ignored
      //
      // => bob = "hi"
      

      另一个技巧是在访问之前使用 && (and) 来确保某些内容存在。

      对于 && 操作,JS 将返回它找到的 LAST "truthy" 值(从左到右读取)。

      例如,如果您尝试从多级对象中读取属性。

      var obj = {
              foo : {
                  bar : "hi"
              }
          }
      
      var bob = obj && obj.foo && obj.foo.bar;
      //          ^        ^              ^
      //          yip      yip            use this
      //
      // => bob = "hi"
      
      // --------------
      // breaking:
      // --------------
      var bob = obj && obj.foo && obj.foo.sally && obj.foo.bar;
      //        ^          ^              ^
      //        yip        yip            nope  <-- stops here, 
      //                   ^                        and returns the last "yip"
      //                   |                        the rest are ignored   |
      //                   '-----------------------------------------------'
      //
      // => bob = obj.foo
      

      两者||和 && 操作是从左到右读取的......所以你可以拥有通常可能会向右侧抛出错误的东西,因为一旦 JS 检测到真​​/假值,它就会停止从左到右读取。

      【讨论】:

        【解决方案8】:

        请注意,在某些版本的 IE 中,此代码不会按预期工作。因为var,变量被重新定义,所以——如果我没记错的话——你最终会得到一个新对象。这应该可以解决问题:

        var AEROTWIST;
        AEROTWIST = AEROTWIST || {};
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-01-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-06
          • 1970-01-01
          相关资源
          最近更新 更多