(翻译) Poor misunderstood 'var'
It seems most programmers coming to JavaScript from C, C++, Java, and the like equate the var statement with variable declaration statements in the languages they come from and use it the same way. And at some casual level that's reasonable; but it can lead you down a misleading path...
很多JS的程序员来自C,C++,Java,他们喜欢将var statement和他们语言中的变量声明语句等同起来,有时候好像没问题,但其实这种做法有时会给你带来坑…
Consider this code:
function foo()
{
var ar;
// ...do some stuff, create an array
in 'ar'...
for (var index = 0; index <
ar.length; ++index)
{
doSomethingWith(ar[index]);
}
}
This is a common idiom, but a misleading one. You
might think that index is only defined
within the for loop (that's certainly the impression we're
giving in the code). But it's not true: In fact, index is defined throughout the function -- within the loop, outside
the loop, above the loop, and below the loop. The var statement defines a variable within the current scope (all of it,
not just "from here on"), and unlike some other languages, in
JavaScript blocks don't have any effect on scope; only functions introduce a
new scope.
这段代码中,你可能认为index只是定义在for 循环里了,但并不是这样,实际上,index被定义在整个函数里了,在loop内,在loop外,在loop上,在loop下… var statement在当前的scope内声明了一个变量, 和其他语言不一样,Javascript中 blocks
对scope没有什么影响,只有函数会创建新的scope
Consequently, the above function can be
written as it is above, but also with the index declaration...
所以,上面的函数可以写成下面这样..
function foo()
{
var ar;
var index;
// ...do some stuff, create an array
in 'ar'...
for (index = 0; index < ar.length;
++index)
{
doSomethingWith(ar[index]);
}
}
...at the bottom:
function foo()
{
var ar;
// ...do some stuff, create an array
in 'ar'...
for (index = 0; index < ar.length;
++index)
{
doSomethingWith(ar[index]);
}
var index;
}
...anywhere in the middle:
function foo()
{
var ar;
// ...do some stuff, create an array
in 'ar'...
for (index = 0; index < ar.length;
++index)
{
var index;
doSomethingWith(ar[index]);
}
}
...or even all of them!
function foo()
{
var ar;
var index;
// ...do some stuff, create an array
in 'ar'...
for (var index = 0; index <
ar.length; ++index)
{
doSomethingWith(ar[index]);
}
var index;
}
We can get away with that last one because a var
statement
defining a variable that already exists in the current scope does not replace
the variable (this is what keeps you from accidentally masking your function's
arguments, or even the arguments
array that's
provided for you).
最后一个的操作很骚,但这段代码却没有问题,因为var statement来声明一个已经存在的变量,在当前的对象中,不会取代变量.(这还可以防止你意外将你的函数参数或者arguments数组给覆盖没了)
This seems like an odd way to define the var
statement
until you get into the plumbing of JavaScript and how it sets up calls to
functions. You can get into some of that by reading my earlier post, Closures are not complicated, but the net
effect of the plumbing is that all var
statements
are treated as though they were at the top of the function (if they have
initializers, those become assignments and stay where they are).
这种定义 var statement的方式看起来很奇怪 直到你明白了js怎么处理函数的调用(call),你可以看一下我之前的那篇文章.
最后的直接结果就是所有的var statement会被处理好像他们都在函数的开头一样(如果他们被赋值初始化了,这些值会停留在他们被赋值的地方)
So does that mean that the common idiom of declaring an
indexer within the loop statement is "wrong"? Well, that's a matter
of perspective, and the older I get the more experience I accumulate, the less I think in
terms of absolutes like right and wrong. The language spec allows it, so in
that sense it's not "wrong". In some ways, it's sort of a shorthand
way of telling the next person reading the code that you're going to use it for
the loop (and only for the loop, right?), so in that sense perhaps it's not "wrong".
所以,这种在循环体中定义 indexer的方法是错的吗? 语言标准允许了这种情况,所以好像其实不是”wrong”的 在某种程度上来说 这是一种简写的方式,在告诉下一个读代码的人 你将要用这个变量来在loop中使用,所以..emmm这个好像也不是错的
But the further your code gets from expressing what's really
happening, the easier it is for someone reading the code later (perhaps you!)
to get the wrong end of the stick and introduce a problem. For example, suppose
you have a 30-some-odd-line function and the loop appears in within the body of
a conditional about two-thirds of the way down:
但是这样做其实很容易搞出问题,举例:
function foo(someArray)
{
var thingy;
var otherThingy;
// ...20 lines of code...
if (thingy > otherThingy)
{
for (var index = 0; index <
someArray.length; ++index)
{
doSomethingWith(someArray[index]);
}
}
// ...10 more lines of code...
}
Six months after you write this, Mike edits the
function and needs to remember the index of something at the top so he can do
something with it at the bottom; he declares an "index" variable,
sets index at the top, and then uses it at the bottom, having missed the loop:
你写完这段代码的6个月后,mike编辑了这段函数 并且 需要拿上面一些东西的index , 他声明了index变量,然后在下面使用它,
function foo(someArray)
{
var thingy;
var otherThingy;
var index;
index = findSomething(someArray);
// ...20 lines of code...
if (thingy > otherThingy)
{
for (var index = 0; index < someArray.length; ++index)
{
doSomethingWith(someArray[index]);
}
}
// ...10 more lines of code...
restoreSomething(someArray, index);
}
Mike's introduced a bug, an irritating, intermittent bug. Sometimes the restoreSomething
call at the end fails for some reason; not always, mind, but sometimes. (Because index
gets set by the loop, but only when thingy > otherThingy
.)
Obviously, this bug could have been avoided if Mike had read
through the entire function carefully before making his mods. Or if you'd
chosen a different name for your index variable (in hopes of reducing the odds
of Mike using it). Or it could have been caught by thorough unit tests that
explore all conditions (and then Mike would have to go back and fix it).
But let's throw Mike a bone, eh? If we declare the variable
in the text in the same place it's defined by the interpreter at runtime, we
help him avoid making the mistake in the first place. And we like Mike, we
don't want to trip him up...right?
Regardless of your decision about how to write your code,
though, understanding what var
is really
doing can help you get that code doing what you want it to do.
然后就出现bug了,真坑啊
(翻译) Poor misunderstood 'var'的更多相关文章
- Javascript——概述 && 继承 && 复用 && 私有成员 && 构造函数
原文链接:A re-introduction to JavaScript (JS tutorial) Why a re-introduction? Because JavaScript is noto ...
- (翻译) How variables are allocated memory in Javascript? | scope chain | lexicial scope
总结: 阅读下面文章需要15分钟 提问者的问题是JavaScript中内存是怎么分配的,在介绍的过程作者涉及计到了JS中 Scope Chain和调用函数call生成lexicial environm ...
- 【uwp】浅谈China Daily 中划词翻译的实现
学习uwp开发也有一段时间了,最近上架了一个小应用(China Daily),现在准备将开发中所学到的一些东西拿出来跟大家分享交流一下. 先给出应用的下载链接:China Daily , 感兴趣的童鞋 ...
- 2018-08-29 浏览器插件实现GitHub代码翻译原型演示
此原型源自此想法: 中文化源码. 考虑到IDE插件工作量较大, 且与IDE绑定. 在代码转换工具的各种实现中, 综合考虑实用+易用+长远改进潜力, 浏览器插件似乎较有优势. 于是用最快捷的方式实现这一 ...
- Go语言使用百度翻译api
Go语言使用百度翻译api 之前做过一个使用百度翻译api的工具,这个工具用于用户的自动翻译功能,是使用C#调用百度翻译api接口,既然在学习Go语言,那必然也是要使用Go来玩耍一番.这里我是这么安排 ...
- ENGLISH抠脚童鞋的福利--GitHub汉化插件
今天在某前端群看到一个插件,激动万分啊!我就把插件使用实现的步骤分享一下! 打开chrome浏览器输入地址:chrome://extensions/ : 跳转到其他页面,点击左上角--扩展程序: 将T ...
- VB CreateObject转C#
C#调用方法.函数获取属性大致流程如下: System.Type oType = System.Type.GetTypeFromProgID("SomeClass"); objec ...
- A Swift Tour(4) - Objects and Classes
Objects and Classes(对象和类) 用 class 关键字后面跟一个类名来创建一个class,在一个类中声明 常亮或变量,他存在于当前类的上下文,函数的方法是同样的 var numbe ...
- 【PHP】PHP5.4.0版本号ChangeLog具体解释(上)
前言 随着大量的框架使用composer和namespace,渐渐的线上环境也从之前的5.3变成了5.4或者5.5甚至5.6,随着7月份PHP7的公布,会有很多其它的公司採用新版本号. 之前好久就想写 ...
随机推荐
- 《OAuth2.0协议安全形式化分析-》----论文摘抄整理
---恢复内容开始--- 本篇论文发表在计算机工程与设计,感觉写的还是很有水准的.实验部分交代的比较清楚 本篇论文的创新点: 使用Scyther工具 主要是在 DY模型下面 形式化分析了 OAuth2 ...
- CA、证书及openssl用法
CA和证书 摘要:涉及到网络安全这一块,想必大家都听过CA吧.像百度.淘宝.京东等这些知名网站,每年都要花费一笔money来买CA证书.但其实简单的企业内的CA认证,我们自己就可以实现,今天我就讲解一 ...
- PAT Advanced 1022 Digital Library (30 分)
A Digital Library contains millions of books, stored according to their titles, authors, key words o ...
- Maven 发布项目到Jetty服务器———5
官网: http://www.eclipse.org/jetty/documentation/current/jetty-maven-plugin.html 1.安装配置插件 2. 运行 命令: je ...
- 将字符串s='ab34aa243dd78eww89' 处理为 '**34**243**78***89',然后对数字求和,结果为'**7**9**15***17'
s='ab34aa243dd78eww89'#s='ab34aa000dd78eww89' #方法1: result='' for i in s: if i.isalpha(): result+='* ...
- ADO.Net数据库连接字符串、DbProviderFactory
一.ADO.Net数据库连接字符串 1.OdbcConnection(System.Data.Odbc) (1)SQL Sever 标准安全:" Driver={SQL Server}; S ...
- C语言实现的文件交互
计算机与外部设备的交互依靠文件完成 文件是记录在外部介质上的数据的集合:例如1.c 是源码 1.exe可执行的文件 文件的分类 按组织结构: 记录文件:有一定结构的文件,可以解析成字段值的文件: 流式 ...
- 在 Linux 下使用 scp 命令
将文件或文件夹从网络上的一个主机拷贝到另一个主机当中去. here:在 Linux 下使用 scp 命令 摘要: scp 是安全拷贝协议(Secure Copy Protocol)的缩写, scp 是 ...
- django post请求 403错误解决方法
--摘 第一次用Django做项目,遇到了很多问题. 今天遇到的问题是Django在处理post请求时多次出现403错误. 我先描述一下问题出现的环境:我用Django写了一个web服务端,姑且称它为 ...
- KETTLE 更新表的两种方式-更新控件和sql更新 2种方式的实现比较
在实际工作中,我们有可能遇见只更新不插入的情况,可以由以下2种方式去实现: 1.更新控件 如下图所示,根据id字段,更新name和cjsj时间字段 该控件不足的地方是,用来查询关键值得字段不够灵活,一 ...