查看在线源代码时,我在几个源文件的顶部发现了这一点。
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
对象中正确定义func1
和func2
。
加载的第一个文件将创建初始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.js
和homer.js
,而无需覆盖彼此的方法(如果它们有不同的名称)。因此,您将始终获得一个FOO
对象,该对象具有方法skateboard
和donut
(耶!)。
#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
。
伪值为null
、undefined
、0
、""
、NaN
和false
。真理的价值观就是一切。
因此,如果尚未设置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"
另一个技巧是使用&;(和)在访问之前确保某个东西存在。
对于&;操作,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检测到truthy/false值,它就会停止从左到右的读取。
请注意,在某些版本的IE中,此代码无法按预期工作。因为var
,变量被重新定义并被分配,所以——如果我没有记错这个问题——你最终总是会有一个新对象。这应该可以解决问题:
var AEROTWIST;
AEROTWIST = AEROTWIST || {};