Node.js: 不小心省略了 var 声明通过全局对象、错误或功能暴露所有变量?

Node.js: accidentally omitted var declaration expose all variables via global object, bug or feature?

对 NodeJs 相当陌生(但对 Javascript 来说不是),我认为它很棒,但不是在所有方面,但这不是问题的主题。

偶然发现这个'feature',实际上这正是我想要的,但不知道它是合法的还是错误。我在包含文件中做了什么:

// var <- var is now a comment
 ksNone         = 0,
 ksAltKey       = 1, 
 ksCtrlKey      = 2,
 ksShiftKey     = 4; 
 ......
 .......

在主文件中遍历全局对象时,代码如下...

代码:

require( './lib/mycode.js' );

for( var p in global )
{ console.log( p ); }

.....你终于会看到:

输出:

........ <- many other vars
 ........
 ........
ksNone
ksAltKey
ksCtrlKey
ksShiftKey

让我思考,包含一个具有一堆通用功能的文件并不容易。例如,我有一些函数来验证字符串和数字以及不需要在命名空间或 class 中的所有其他类型的东西。通常,要包含此类函数,您必须为其指定导出或通过 fs 和 eval() 以一种怪异的方式包含它 - 另请参阅此 question.

我尝试了以下方法:

代码:

 ksNone         = 0,
 ksAltKey       = 1, 
 ksCtrlKey      = 2,
 ksShiftKey     = 4,
 isNumber = function( i ) 
 {
   return typeof i === 'number' && isFinite(i) && !isNaN(i);
 },
 isValidNumber = function( i, iMin, iMax )
 {
  if( !isNumber( i ) )
   { return false; }

  if( isNumber( iMin ) && i < iMin ) 
   { return false; }

  if( isNumber( iMax ) && i > iMax ) 
   { return false; }

  return true;  
 }, 
isString = function( a ) 
 {
   return ( typeof a === 'string' || ( a instanceof String ));
 }, 
 isValidString = function( s, iMinLen, iMaxLen )
 {
   if( isString( s ) )
   {
     var iLen   = s.length,
         bIsMin = ( isNumber( iMinLen ) && iMinLen >= 0 )?(iLen >= iMinLen):(iLen > 0),
         bIsMax = ( isNumber( iMaxLen ) && iMaxLen >= 0 )?(iLen <= iMaxLen):(iLen > 0);

     return ( bIsMin && bIsMax );    
   }

   return false;
 };

再次遍历将输出:

输出:

 ........ <- many other vars
 ........
 ........
ksNone
ksAltKey
ksCtrlKey
ksShiftKey
isNumber
isValidNumber
isString
isValidString

一旦包含,因为它现在在全局范围内,我可以在任何地方这样做:

代码:

var test = "yes"

if( isValidString( test ) ) // call the global function
 { console.log( "String is valid" ); }

输出:

String is valid

问题:

通常情况下,遗漏诸如 var 之类的声明内容并不是一个好主意(它在严格模式下不起作用 - "use strict"; )但是在这种情况下它似乎非常方便因为您不需要指定导出或使用 hacky 方式来包含它,并且这些函数无需命名空间或 const/var 需要声明即可全局访问。

包含文件时实际发生了什么?扫描 NodeJs 核心常量、变量、函数以保持其私有?使用合法还是错误?做与不做,你怎么看?

Normally it is not a good idea to left out declaration stuff such as var (it doesn't work in strict mode - "use strict"; ) however in this case it seems to be very handy because you don't need to specify exports or use a hacky way to include it and those functions are globally accessable without a namespace or const/var require declaration.

node.js模块系统鼓励:

  1. 增强了重用或共享模块的能力
  2. 定义良好的模块间接口,每个人和每个模块都以相同的方式完成
  3. 增强模块的可测试性
  4. 没有全局符号冲突
  5. 模块范围内的代码隐私(更难破解或无意中弄乱东西)
  6. 模块之间的显式依赖关系

全局变量会导致各种问题:

  1. 全局命名空间中的意外命名冲突
  2. 隐式依赖(模块需要一些未声明的全局条件才能正常工作)
  3. 内容可能会被覆盖或被黑客入侵,或者只是通常以作者不希望的方式被搞乱

以正确的方式 export/import 进行操作的唯一缺点是在模块之间导入或导出接口时需要输入更多的代码。

所以,这是我针对您的问题提出的建议:

  1. 不要将全局变量用于模块之间的接口。只需习惯稍微多一点输入即可正确导入和导出内容。它将在短期和长期得到回报 运行.
  2. 运行 您的代码处于严格模式,因此要求显式声明所有变量,并且不能有意外或隐式全局变量。这些都是等待发生的事故。避开他们。声明所有变量。
  3. 使用 letconst 到 specify/limit 变量的范围,甚至 var.

What actually happen when you include a file? Scans the NodeJs core consts, vars, functions to keep it private? Is it legit to use or is it a bug? A do or don't, what do you think?

隐式全局变量在执行第一个分配给它们的代码行之前不会被创建。没有高级扫描。它们是按需创建的。但是,不要使用它——不要依赖它。这不是错误。这是一个遗留的 Javascript 设计决策(大多数人会认为这是一个糟糕的设计决策)是故意的。但是,避免它。不要故意那样编程并使用 strict 模式,这样解释器会指出您忘记声明的任何意外变量。

在函数内部,所有 var 声明的变量都是在调用函数时创建的。这称为变量提升”,是该语言的一个特性。当解释器编译该函数时,它会记录函数内的所有 var 声明,以便当它 运行 是该函数时,它可以在每次函数启动时预先创建它们 运行ning.

letconst 变量仅在它们创建的块范围内可用。 var 是函数作用域,letconst 是块作用域。与 var 不同,您不能在范围内引用 letconst 变量,直到包含其定义的代码行具有 运行(比严格模式更安全)。