“ var FOO = FOO ||是什么?{}”(将变量或空对象分配给该变量)在Javascript中是什么意思?


99

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

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

但是我不知道该怎么办|| {}

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

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


注意:已对问题进行编辑以反映出这是一种在Javascript源文件顶部常见的代码模式。
罗伯特·哈维

Answers:


153

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

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

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

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

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

这两个份额的同一个命名空间那么也没关系,其中责令这两个文件被加载,你仍然可以func1func2正确的中定义MY_NAMESPACE正确的对象。

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

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


2
确实是这样,开头有几个js文件,它们的声明完全相同,非常感谢!
里卡多·桑切斯

41
+1以在两行之间阅读并解释这样做的原因。当有人给出用户真正想要的答案而不仅仅是他所要求的答案时,总是很好。:)
Spudley 2011年

1
我想说这是#ifndef /#define for javascript :)
Darren Kopp

1
||当您想提供可选参数并将其初始化为默认值(如果未提供)时,它也非常有用:function foo(arg1, optarg1, optarg2) { optarg1 = optarg1 || 'default value 1'; optarg2 = optart2 || 'defalt value 2';}
crazy2be 2011年

1
@ crazy2be如果默认值为true则不起作用,但是false值也是合法的,因为||操作员无法undefined从识别falsey
Alnitak

23
var AEROTWIST = AEROTWIST || {};

基本上,这行代码是将AEROTWIST变量设置为变量的值AEROTWIST,或将其设置为空对象。

双管道||是OR语句,并且OR的第二部分仅在第一部分返回false时才执行。

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

基本上是这样说的:

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

希望能有所帮助。


1
实际上,在您的上一个示例中,该范围会很好,因为JS没有块范围
Alnitak

@Alnitak-嗯,你是对的;我最近一直在处理闭包,而我忘记了基础知识。我将编辑答案。
Spudley 2011年

6

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

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将函数的执行上下文作为形式参数输入,因此它已经声明。
法布里西奥磨砂

6

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!');
};

在这种情况下,skateboard如果在HTML中加载JavaScript文件homer.js之后该函数将消失,bart.js因为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对象,则“或”案例将变为活动状态并创建一个新对象,因此您可以为其分配功能。喜欢:

var FOO = {};

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

3

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


1

||操作需要两个值:

a || b

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

该falsy值nullundefined0""NaNfalse。真实的价值观是其他一切。

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


我不确定应否将真实错误作为真实的词语。有趣,但不完全是标准。:-)
Orbling 2011年

4
@Orbling它们非常常用来谈论JS中的此类值。
Alnitak

+1用于正确描述运算符,因为它不是逻辑运算符。有时称为“默认运算符”。
TimBüthe2011年

@Tim ||JS(和Per​​l)与C,C ++和Java中的版本之间的唯一区别是JS不会将结果转换为布尔值。它仍然是一个逻辑运算符。
Alnitak

@Alnitak:可能是由于过去JS开发人员的非专业背景。
2011年

-1

请注意,在某些版本的IE中,此代码无法按预期工作。由于var重新定义分配了变量因此-如果我没有记错的话-您最终将总是拥有一个新对象。那应该解决问题:

var AEROTWIST;
AEROTWIST = AEROTWIST || {};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.