(翻译) 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的公布,会有很多其它的公司採用新版本号. 之前好久就想写 ...
随机推荐
- IDEA光标跟随原因是jdk载入的问题BUG 修正 需要I安装最新版本1.8JDK 1.9之后的不清楚 谨慎
解决方法是 选择jdk本地版本 重启就好了 https://blog.csdn.net/Utopia_Zq/article/details/81190300?utm_source=blogxgwz2 ...
- NORDIC ble RSSI
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) { ret_code_t err_code; sw ...
- Linux服务器TIME_WAIT进程的解决与原因
linux服务器上tcp有大量time_wait状态的解决方法和原因解释 毫无疑问,TCP中有关网络编程最不容易理解的是它的TIME_WAIT状态,TIME_WAIT状态存在于主动关闭socket连接 ...
- idou老师教你学Istio 25:如何用istio实现监控和日志采集
大家都知道istio可以帮助我们实现灰度发布.流量监控.流量治理等功能.每一个功能都帮助我们在不同场景中实现不同的业务.那Istio是如何帮助我们实现监控和日志采集的呢? 这里我们依然以Bookinf ...
- Window脚本学习笔记之BAT文件处理
BAT文件处理 列出盘中特定文件名的文件: @echo offdir C:\*.jpg /b/s>.\CDatejpg.txt dir C:\*.png /b/s>.\CDatepng.t ...
- 部署WCF Lib到IIS
打开VS2013,新建项目,选择WCF|WCF服务库,取名WCFWithIIS 2. 我们用演示一个计算加法的服务.简单起见,直接在IService接口中添加加法接口 3. 实现这个加法 4. 生成项 ...
- Linux 误卸载自带python后的解决办法
1:卸载python(以免有些同学没有卸载干净) rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps #强制删除已安装程序及其关联 wher ...
- tp5.1下redis配置和使用
//1.config目录下新建redis.php <?php /** * Created by PhpStorm. * User: Administrator * Date: 2019/12/1 ...
- JS客户端类型的判断
**第一种:通过判断浏览器的userAgent,用正则来判断是否是ios和Android客户端.代码如下:** <script type="text/javascript"& ...
- Educational Codeforces Round 40 (Rated for Div. 2) 954G G. Castle Defense
题 OvO http://codeforces.com/contest/954/problem/G 解 二分答案, 对于每个二分的答案值 ANS,判断这个答案是否可行. 记 s 数组为题目中描述的 a ...