为啥 var x = x = x || 比 var x = x || 更彻底?

Posted

技术标签:

【中文标题】为啥 var x = x = x || 比 var x = x || 更彻底?【英文标题】:Why is var x = x = x || more thorough than var x = x || ?为什么 var x = x = x || 比 var x = x || 更彻底? 【发布时间】:2018-09-25 21:35:11 【问题描述】:

在我作为初学者编写干净的 javascript 代码的过程中,我最近在阅读 this article 关于 JavaScript 中的命名空间时偶然发现了这一段:

下一个示例顶部的代码演示了在定义变量(对象命名空间)之前检查变量(对象命名空间)是否已经存在的不同方法。您通常会看到开发人员使用选项 1,但选项 3 和 5 可能被认为更彻底,选项 4 被认为是一个很好的最佳实践。

// This doesn't check for existence of 'myApplication' in
// the global namespace. Bad practice as you can easily
// clobber an existing variable/namespace with the same name
var myApplication = ;

/*
The following options *do* check for variable/namespace existence.
If already defined, we use that instance, otherwise we assign a new
object literal to myApplication.

Option 1: var myApplication = myApplication || ;
Option 2  if(!MyApplication) MyApplication = ;
Option 3: var myApplication = myApplication = myApplication || 
Option 4: myApplication || (myApplication = );
Option 5: var myApplication = myApplication === undefined ?  : myApplication;

*/

选项1肯定是我见过用的最多的一个,我也很理解。

选项 2 很好,但似乎缺少 var myApplicationif(!window.myApplication) 否则如果 myApplication 不在全局范围内,则条件 if(!myApplication) 会抛出错误,不会不是吗?

选项 3 是我遇到的问题:我的理解是首先执行 myApplication = myApplicationmyApplication 在全局范围内(由于开头的 var )。我的问题是我想不出这个选项比选项 1 做更多的事情。

选项 4 在我看来最好写成 window.myApplication || (myApplication = ) 以避免在 myApplication 不在全局范围内时引发错误。

选项 5 排除了 undefined 以外的 false-y 值,但这是个好主意吗?如果myApplication 是一个空字符串,那么剩下的代码很可能会失败,不是吗?

是否有人能够阐明不同选项之间的差异,并特别解释为什么选项 3 被描述为更彻底?

【问题讨论】:

我想部分答案取决于'use strict' 的废弃。当你说选项 1 会抛出错误,因为中间声明没有 var,只有当你使用 'use strict' 时才会这样。 @trysis 选项 1 没问题,你的意思是选项 3?我不明白... @trysis:严格模式对列出的任何选项都没有影响。最接近的相关更改严格模式是分配给未声明的标识符成为错误,而不是我所说的the Horror of Implicit Globals。但以上所有内容要么声明标识符 (1, 3, 5),要么尝试在分配给它 (2, 4) 之前评估可能未声明的标识符,如果标识符将失败未声明,即使在松散模式下也是如此。 (如果使用typeof,选项 2 将与严格模式相关,但它没有。) 您为什么要这样做?如果我是你,我会完全放弃 var 和全局属性,我会转移到 let 和模块。 @m93a 关键是要了解我读到的内容,我知道模块是当今的发展方向,但学习语言的基础知识是我目前所处的位置:-) 【参考方案1】:

如果文章声称选项 3“更彻底”,那是不正确的。分配链的中间根本没有意义。

是否有人能够阐明不同选项之间的差异,并特别解释为什么选项 3 被描述为更彻底?

首先,请注意:在 2018 年,您可能不想使用其中任何一种。相反,使用适当的模块,或者通过各种模块定义语法(AMD、CommonJS、RequireJS)和相关工具,或者通过带有importexport 的 ES2015+ 模块(并且可能是相关的工具,例如 Babel,也许还有 Webpack 或 Browserify,尽管当前版本的 Chrome、Safari 和 Edge 原生支持模块,而 Firefox 目前也支持标志)。

为什么var x = x = x || var x = x || 更彻底?

不是。

选项 2 很好,但似乎事先缺少 var myApplicationif(!window.myApplication) 否则如果 myApplication 不在全局范围内,则条件 if(!myApplication) 会抛出错误,不会不是吗?

是的。 (假设生产发生在全局范围内。如果它不在全局范围内并且在当前范围链中的任何地方都有范围内的myApplication,它不会抛出,因为myApplication 不会是一个未解析的符号。)

选项 3 是我遇到的问题:我的理解是首先执行 myApplication = myApplicationmyApplication 在全局范围内(由于开头的 var )。我的问题是我想不出这个选项比选项 1 做更多的事情。

不,如果你有

var myApplication = myApplication = myApplication || 

这是事情发生的顺序:

    var myApplication 如果全局不存在则创建它,如果存在则保持不变 myApplication || 被评估并采用 myApplication 中的值(如果它是真的)或 (如果不是);让我们称之为value1 执行myApplication = value1(中间那个),结果是value1 myApplication = value1(左边那个)无缘无故又被执行了

选项 4 在我看来最好写成 window.myApplication || (myApplication = ) 以避免在 myApplication 不在全局范围内时引发错误。

确实。

选项 5 排除了 undefined 以外的 false-y 值,但这是个好主意吗?如果myApplication 是一个空字符串,那么剩下的代码很可能会失败,不是吗?

是的。

【讨论】:

感谢您全面了解所有这些选项(没有双关语)。这个答案很有启发性。 RequireJS 是下一步,但现在我正在尝试建立对该语言的完善知识。 我最好的猜测是原作者认为选项3的操作顺序是var myApp = ((myApp = myApp) || );(无论如何仍然没有意义) @JacquesGaudin 我看不到您评论中的双关语。请您解释一下好吗? @ijmacd 线索:仔细看看这条评论,你会发现。 @ijmacd "彻底"

以上是关于为啥 var x = x = x || 比 var x = x || 更彻底?的主要内容,如果未能解决你的问题,请参考以下文章

为啥shell脚本比较经常使用x$VAR = xyes?

为啥 SSE scalar sqrt(x) 比 rsqrt(x) * x 慢?

为啥在 C 中前缀递增 (++x) 比后缀递增 (x++) 快? [复制]

Visual Studio 2013 的亮点比 Visual Assist X 强

为啥 np.linalg.norm(x,2) 比直接求解慢?

为什么va_arg()会对x86_64和arm产生不同的影响?