Node.js:意外省略了var声明,通过全局对象、bug或特性暴露了所有变量



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

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

// 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

这让我思考,包含一个包含一堆函数的文件用于一般用途并不容易。例如,我有一些函数来验证字符串和数字以及所有其他不需要在命名空间或类中的东西。通常,要包含这样的函数,您必须为其指定导出,或者通过fs和eval()以一种巧妙的方式包含它——另请参阅此问题。

我尝试了以下方法:

代码:

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";中不起作用),但在这种情况下,它似乎非常方便,因为您不需要指定导出或使用一种巧妙的方式来包含它,并且这些函数可以全局访问,而无需命名空间或const/var require声明。

当您包含一个文件时,实际会发生什么?扫描NodeJ的核心常量、变量和函数以保持其私有性?这是合法的使用还是一个错误?A做还是不做,你觉得怎么样?

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

node.js模块系统鼓励:

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

Globals可能会导致各种问题:

  1. 全局命名空间中的意外命名冲突
  2. 隐式依赖关系(模块需要一些未声明的全局条件才能正常工作)
  3. 事情可能会被改写或黑客入侵,或者只是以作者不打算的方式进行处理

以正确的导出/导入方式进行操作的唯一缺点是在模块之间导入或导出接口时稍微多键入一些类型。

因此,以下是我对您的问题的建议:

  1. 不要在模块之间使用全局接口。只需习惯稍微多输入一点,就可以正确地导入和导出内容。从短期和长期来看都会有回报的
  2. 以严格模式运行代码,因此要求显式声明所有变量,并且不能有意外或隐式全局变量。这些都是等待发生的意外。避开他们。声明所有变量
  3. 使用letconst来指定/限制变量的范围,甚至不使用var

包含文件时实际会发生什么?扫描NodeJ的核心常量、变量和函数以保持其私有性?这是合法的使用还是一个错误?A做还是不做,你觉得怎么样?

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

在函数内部,所有var声明的变量都是在调用函数时创建的。这被称为"变量提升",是该语言的一个功能。当解释器编译函数时,它会记录函数中的所有var声明,以便在运行该函数时,每次函数开始运行时都可以预先创建它们。

CCD_ 9和CCD_。var是函数范围的,letconst是块范围的。与var不同,在包含其定义的代码行运行之前,不能在范围内引用letconst变量(这是严格模式的进一步安全性)。

相关内容

  • 没有找到相关文章

最新更新