Javascript 中的 var
MelonCard发布了一篇文章——”how one missing var ruined our launch“(”少写了一个var毁了我的网站”),这篇文章是说MelonCard用Node.js做后台,因为出了一个小高峰——有50-100人注册,结果整个网站都不响应了,而且还出现了很多奇怪的问题。当他们调查到问题的要源的时候,他们发现下面的代码少写了一个var。
[javascript]app.all(‘/apps/:user_id/status’, function(req, res, next) {
// …
initial = extractVariables(req.body);
});[/javascript]
为什么inital少写一个var会引发这个问题呢?因为如果你不写var,这个局部的变量会被javascript当成全局变量,而这个变量又是一个函数,所以,当多用户并发的时候,这个本应该在不同用户下互不干扰的变量,成了各个用户共享的东西。试想,用户A的数据被用户B覆盖了,用户A和B的数据还没处理完,结果被新的C给搞乱了,程序的逻辑自然出现了问题。
在stackoverflow.com上有这么一个贴子说明了“有var”和“无var”的差别:
// These are both globals var foo = 1; bar = 2; function test() { var foo = 1; // Local bar = 2; // Global // Execute an anonymous function (function() { var wibble = 1; // Local foo = 2; // Inherits from scope above (creating a closure) moo = 3; // Global }()) }
上面这个示例告诉我们,如果你不用var,那么这个js引擎会一层一层地向上找父作用域中的变量,如果找到了,就用,如果找不到了,就会帮你定义一个全局的变量。上面这个例子充分说明了这一点。所以,如果你想在当前的作用域用声明变量,你一定要用var。这对于一些乱写javascript代码的程序员要注意了。这里再给大家介绍一个工具——
JSLint( http://www.jslint.com/ ),一个JS代码质量的分析工具,我们把上述stackoverflow的代码copy到JSLint这个在线工具中,我们可以看到下面的报告:
这个报告说明了源码中的那些变量的情况。
(全文完)
(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)
《Javascript 中的 var》的相关评论
MelonCard那里哥儿们都没用过JavaScript吧
【这对于一些乱写javascript代码的程序员要注意了】
设计语言的时候,为什么不尽量让人想乱写都无法乱写呢?
据我所知coffeescript没有var,这应该是一种改进吧。
失误一个很小的地方就导致大错了。还是严谨好啊。
@haitao
十来天设计的语言……
而且作者是研究函数式的,为了闭包总得找得到变量定义的地方,不写 var 就当成 local 的话就没闭包的事了。
@enz
coffee 没有var是个更大的问题。这样你程序本来是对的,某天碰巧在前面定义了一个全局变量,结果后面就自动错了,都没法指定成local的
关于这些东西,可以看《javascript语言精粹》这本书,大牛里面都说了这些东西的
Hi,《少写一个`var`是如何毁掉我们网站的》有中文译文哦 http://blog.jobbole.com/10348/
这个貌似一般讲javascript语法的书中都提到要注意全局变量和局部变量,不过实际写的时候确实会偶尔犯这样的错误。
其实只是有木有注意的问题。。。
此外我有一点想吐槽楼主 – 也是整个 coolshell.cn 如果没记错 – 你们为神马要一个 IE=EmulateIE7? 在 IE 9/10 标准模式下效果更好哦。。。:)
@t
历史原因这有什么好吐槽的
JavaScript坑爹的地方挺多,诘诎聱牙起来甚至有点像C++的语法了…所以现在做Node开发,开始流行用CoffeeScript来编写代码,再transcompile成JavaScript了…
类似的情况还有this关键字,写Java的时候习惯不用this获取成员变量,Javascript不用this获取的完全是不同的东西
刚好在看var变量的部分,以后要注意一下
严格点,应该:global声明的变量,是全局变量;var声明的是局部变量;没声明的语法报错。
语言设计,真正是:严是爱,宽是害
让Javascript这个苦逼的语言自然死亡把 缝缝补补又一年解决不了问题了
这是javascript的设计缺陷。
应该设计成这样:默认变量是局部的,全局变量必须加上类似于global关键字的前缀。
一直没有遇到过这种问题,看来俺写代码的习惯还是不错的。由此可以看出良好的编码习惯是多么的重要啊!
或者干脆学ruby那样,不同作用域的名称的命名方法有显式的区别…
@YY
JavaScript就这样,咱们得学会适应
还有一种定义会比较坑爹。
var a,
b,
c;
d,
e;
这时候d和e就..
其实不加var也可以呀
主要不要共享此函数就好了
initial = clone(extractVariables(req.body));
足以,复制一个就行,保证不同,不共享,clone自写。。。复制一个对象
习惯问题,搞过JS的一般都不会写错的
耗哥现在对JavaScript很感兴趣了呀,嗨,两年前我用js写的扫雷游戏就中了var的招了,在递归地扫描某个格子周围非地雷格子的函数中:
function search_empty_square( square ) // first invoked with square.value == 0
{
// var sr ;
if( square.value >=0 && square.locked == false ) {
click_square( square ) ;
if( square.value == 0 ) {
if( square.x>0 && square.y>0 && !( sr=document.getElementById((square.x-1)*row+(square.y-1)) ).clicked )
search_empty_square( sr ) ;
if( square.x>0 && !( sr=document.getElementById((square.x-1)*row+square.y) ).clicked )
search_empty_square( sr ) ;
if( square.x>0 && square.y0 && !( sr=document.getElementById(square.x*row+(square.y-1)) ).clicked )
search_empty_square( sr ) ;
if( square.y<row-1 && !( sr=document.getElementById(square.x*row+(square.y+1)) ).clicked )
search_empty_square( sr ) ;
if( square.x0 && !( sr=document.getElementById((square.x+1)*row+(square.y-1)) ).clicked )
search_empty_square( sr ) ;
if( square.x<line-1 && !( sr=document.getElementById((square.x+1)*row+square.y) ).clicked )
search_empty_square( sr ) ;
if( square.x<line-1 && square.y<row-1 && !( sr=document.getElementById((square.x+1)*row+(square.y+1)) ).clicked )
search_empty_square( sr ) ;
}
}
}
上述代码没有对sr进行var声明,导致sr成为全局变量了,之前用C++写的扫雷扫描算法是OK,移植到JavaScript就出问题了,当时还以为JavaScript不支持递归呢,最后看了《精通JavaScript》后才知道不使用var进行声明的变量会成为全局变量,自做完扫雷游戏开始,在每次变量使用前我都会用var进行声明,教训呀,
node.js已经支持use strict了就是用来杜绝此问题的。
给你找个特性了你不去用,那怪谁啊
只要在文件头添加一行”use strict”;
任何未声明的变量都会报错
“use strict”;
app = 1;//报错
(function(){
var local = 2;
})();
其实,这是js语言的一大优点,jsvascript根本就与严格语言没什么关系。扔掉那些诸如Fortran的规范语言,和面向对象的java语言后,再来学它。
还有重要的一点,js本就不是为了生产而设计出来的语言。
@artair
不为了生产?软件大了就如泥潭,不严格就更早、更快就变成泥潭。。。。。。。
javascript代码在浏览器端执行, 怎么会并发用户互相影响 ??
这与运行时编译和运行前编译有关系,而且JavaScript也有他自己的故事,有兴趣可以看看道格拉思的写的那本书:JavaScript语言精粹。@haitao
在客户端虽然也有问题,但还不至于这么大。node js放在了客户端,确实把问题放大了……
打错了,应该是:“node js跑在服务端”
@aisee 文中提到的是NodeJS,运行在服务端
还是得单元测试啊……刚好写了篇文章讲Mocha的单元测试,会探测有没有Global Leak:
http://blog.zhaojie.me/2012/06/jscex-unit-tests-with-mocha-chai.html
不错的博文啊!
但有些看得不是很明白。
几个基本概念,呵呵
陈鹏个人博客
优秀的开源软件让生活更简单
个人认为jshint更好
谁让你们用javascript这种垃圾语言来做后台的,活该!
@jssucks
javascript为什么垃圾? 这样评价js有什么道理? 吐口水也得吐出内容呀
@resty
在本文的情况下,使用CoffeeScript会在function scope内自动生成var关键字声明,initial不可能被误设成全局变量。
刚刚碰到一个类似的问题,用 jQuery 生成 bootstrap alert,在 1.5 秒后自动消失。结果存在多个 alert 的时候,只有最近创建的那一个会正常消失。
偶然看到这篇文章解决了,原因也是声明局部变量的时候没有写 var。多谢!