var app = app || {}

看 TODOMVC 源代码的时候,看到如下一段代码:

var app = app || {};

https://github.com/tastejs/todomvc/blob/master/examples/backbone/js/models/todo.js#L2

很多次看到过类似的代码,也大概明白这是怎么回事,可是,为啥要这么写,这么写是怎么起作用的呢?

在 StackOverflow 上,也有带着类似困惑的小伙伴问了类似的问题,这里:
http://stackoverflow.com/questions/6439579/what-does-var-foo-foo-assign-a-variable-or-an-empty-object-to-that-va
“标准答案”是这么解释的:

Your guess as to the intent of || {} is pretty close.

This particular pattern when seen at the top of files is used to create a namespace, i.e. a named object under which functions and variables can be created without unduly polluting the global object.

The reason why it's used is so that if you have two (or more) files:

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

and

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

both of which share the same namespace it then doesn't matter in which order the two files are loaded, you still get func1 and func2 correctly defined within the MY_NAMESPACE object correctly.

The first file loaded will create the initial MY_NAMESPACE object, and any subsequently loaded file willaugment the object.

Usefully, this also allows asynchronous loading of scripts that share the same namespace which can improve page loading times. If the <script> tags have the defer attribute set you can't know in which order they'll be interpreted, so as described above this fixes that problem too.

不过这个答案给出的是为啥要这么用,至于这么写起作用的原理没有介绍很多。

单纯看一处代码:

var app = app || {};

这里涉及到变量的声明和赋值。而变量的声明涉及到“变量声明提前”的问题,比如在一个函数中,无论变量是不是在函数的最开始声明的,变量都可以使用,例如:

function foo() {
  x = 'ok';
  console.log(x);
  var x; 
}

当然,如果没有最后的 var x; 声明语句,变量 x 就成了全局变量了。
并且,在一个作用域下,多次声明同一变量,由于“变量声明提前”的缘故,其实仍然是同一个变量。
这一部分的具体介绍见:《JavaScript 权威指南》(第6版) 5.3.1 var。

回过头来琢磨最开始的问题,之所以 var app = app || {} 能够有效,应该是由于这些在不同文件中的语句,最终是在同一作用域下执行的。最终在该作用域(也就是全局作用域)下,只有一个app变量。而||的作用,就是在app变量已有值的情况下,直接返回已有的值,没有值的情况下返回右侧的空对象,从而确保app始终是非空的对象。
关于||的这种用法的具体介绍,请看:《JavaScript 权威指南》(第6版)4.10.2 逻辑或(||)。

那么,如果这些语句不在同一作用域下执行的话,会怎样呢?例如:

var app = app || {};
app.foo = 'foo';

(function () {
  var app = app || {};
  app.bar = 'bar';
})()

试验一下,就会发现,上述代码执行完之后,app 对象还是没有属性 bar 的。

为什么呢?
简单来说,因为函数内的 app 是个内部变量,与外部的 app 互不影响。

再把上面的例子改写下:

var app = app || {};
app.foo = 'foo';

(function () {
  app.bar = 'bar';
  var app = app || {};
})()

这样的话又如何呢?这次是不是代码执行后外部的 app 有了属性 bar 了呢?

执行一下的话会发现,居然报错了!

Uncaught TypeError: Cannot set property 'bar' of undefined

仔细琢磨下....其实还是“变量声明提前”在搞鬼。函数内部的变量 app 的声明提前了,但是赋值语句不会提前。没有赋值的变量的值是什么呢?是 undefined 的。这里的错误说清楚了吧,因为此时的 app 是函数内部的私有变量,还没有赋值。为啥不是外面的 app 呢,因为函数内部声明了同名的 app,而通过“变量声明提前”,函数内的 app 都是指向内部的变量的。

小结

其实像这里分析的代码,在日常工作中会看到很多,大致是怎么回事是清楚的,可是真的要去详细解释为啥这么做,这么做又是为啥会起作用,可能就懵了。

编程这件事好像特别看重细节,毕竟无论多么 NB 的应用,也都是一行行代码构建起来的。细节上不清楚,很可能会出现一些习以为常到反而看不出来的小 bug,这样的东西多了,问题也就大了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容