"var FOO = FOO || {}"(为该变量分配一个变量或一个空对象)在Javascript中是什么意思?



查看在线源代码时,我在几个源文件的顶部发现了这一点。

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

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

我知道{}等于new Object(),我认为||表示"如果它已经存在,则使用其值,否则使用新对象。"

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

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

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

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

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

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

这两个文件共享同一个名称空间,那么两个文件的加载顺序并不重要,您仍然可以在MY_NAMESPACE对象中正确定义func1func2

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

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

var AEROTWIST = AEROTWIST || {};

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

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

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

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

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

希望能有所帮助。

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情况将变为活动状态并创建一个新对象,因此您可以为其分配函数

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

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

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') {
  // ...
}

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

||运算符取两个值:

a || b

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

伪值为nullundefined0""NaNfalse。真理的价值观就是一切。

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

对于||操作,JS将返回FIRST"truthy;它找到的值(从左到右读取):

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"

另一个技巧是使用&amp;(和)在访问之前确保某个东西存在。

对于&amp;操作,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

||和&amp;操作从左到右读取。。。因此,您可以使用通常可能会向右侧抛出错误的东西,因为一旦JS检测到truthy/false值,它就会停止从左到右的读取。

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

var AEROTWIST;
AEROTWIST = AEROTWIST || {};

最新更新