102

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

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

但我不知道是什么|| {}

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

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

4

8 回答 8

155

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

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

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

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

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

两者都共享相同的命名空间,然后加载两个文件的顺序无关紧要,您仍然可以在对象中正确获得func1func2正确定义。MY_NAMESPACE

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

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

于 2011-06-22T12:15:47.570 回答
25
var AEROTWIST = AEROTWIST || {};

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

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

因此,如果AEROTWIST已经有一个值,则将其保留为该值,但如果之前未设置,则将其设置为空对象。

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

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

希望有帮助。

于 2011-06-22T12:15:09.380 回答
10

有两个主要部分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之后skateboard加载 JavaScript 文件,该函数将消失,因为 Homer 定义了一个新对象(因此覆盖了 Bart 的现有对象),因此它只知道该函数。homer.jsbart.jsFOOdonut

所以你需要使用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!');
};
于 2015-08-21T15:14:18.527 回答
7

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

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') {
  // ...
}
于 2011-11-18T16:57:08.157 回答
3

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

于 2011-06-22T12:13:07.207 回答
1

运算符有||两个值:

a || b

如果 a 是真的,它会返回a。否则,它将返回b

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

因此,如果a尚未设置(是它undefined)它将返回b

于 2011-06-22T12:15:00.690 回答
0

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

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 将返回它找到的最后一个“真实”值(从左到右读取)。

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

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 检测到真​​/假值,它就会停止从左到右读取。

于 2021-10-26T08:14:13.313 回答
-1

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

var AEROTWIST;
AEROTWIST = AEROTWIST || {};
于 2012-03-14T12:21:19.720 回答