Skip to content

Commit 6320fef

Browse files
committed
Add scopes section
1 parent dd2f117 commit 6320fef

File tree

2 files changed

+181
-204
lines changed

2 files changed

+181
-204
lines changed

doc/zh/function/scopes.md

Lines changed: 92 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,96 @@
1-
## Scopes and Namespaces
1+
## 作用域与命名空间(Scopes and namespaces)
22

3-
Although JavaScript deals fine with the syntax of two matching curly
4-
braces for blocks, it does **not** support block scope; hence, all that is left
5-
is in the language is *function scope*.
3+
尽管 JavaScript 支持一对花括号创建的代码段,但是并不支持块级作用域;
4+
而仅仅支持 *函数作用域*
65

7-
function test() { // a scope
8-
for(var i = 0; i < 10; i++) { // not a scope
6+
function test() { // 一个作用域
7+
for(var i = 0; i < 10; i++) { // 不是一个作用域
98
// count
109
}
1110
console.log(i); // 10
1211
}
1312

14-
> **Note:** When not used in an assignment, return statement or as a function
15-
> argument, the `{...}` notation will get interpreted as a block statement and
16-
> **not** as an object literal. This, in conjunction with
17-
> [automatic insertion of semicolons](#core.semicolon), can lead to subtle errors.
13+
> **注意:** 如果不是在赋值语句中,而是在 return 表达式或者函数参数中,`{...}` 将会作为代码段解析,
14+
> 而不是作为对象的字面语法解析。如果考虑到 [自动分号插入](#semicolon),这可能会导致一些不易察觉的错误。
1815
19-
There are also no distinct namespaces in JavaScript, that means that everything
20-
gets defined in one *globally shared* namespace.
16+
译者注:如果 return 对象的左括号和 return 不在一行上就会出错。
17+
18+
// 译者注:下面输出 undefined
19+
function add(a, b) {
20+
return
21+
a + b;
22+
}
23+
console.log(add(1, 2));
2124

22-
Each time a variable is referenced, JavaScript will traverse upwards through all
23-
the scopes until it finds it. In the case that it reaches the global scope and
24-
still has not found the requested name, it will raise a `ReferenceError`.
25+
JavaScript 中没有显式的命名空间定义,这就意味着所有对象都定义在一个*全局共享*的命名空间下面。
2526

26-
### The bane of global variables
27+
每次引用一个变量,JavaScript 会向上遍历整个作用域直到找到这个变量为止。
28+
如果到达全局作用域但是这个变量仍未找到,则会抛出 `ReferenceError` 异常。
29+
30+
### 隐式的全局变量(The bane of global variables)
2731

2832
// script A
2933
foo = '42';
3034

3135
// script B
3236
var foo = '42'
3337

34-
The above two scripts do **not** have the same effect. Script A defines a
35-
variable called `foo` in the *global* scope and script B defines a `foo` in the
36-
*current* scope.
38+
上面两段脚本效果**不同**。脚本 A 在*全局*作用域内定义了变量 `foo`,而脚本 B 在*当前*作用域内定义变量 `foo`
3739

38-
Again, that is **not** at all the *same effect*, not using `var` can have major
39-
implications.
40+
再次强调,上面的效果**完全不同**,不使用 `var` 声明变量将会导致隐式的全局变量产生。
4041

41-
// global scope
42+
// 全局作用域
4243
var foo = 42;
4344
function test() {
44-
// local scope
45+
// 局部作用域
4546
foo = 21;
4647
}
4748
test();
4849
foo; // 21
4950

50-
Leaving out the `var` statement inside the function `test` will override the
51-
value of `foo`. While this might not seem like a big deal at first, having
52-
thousands of lines of JavaScript and not using `var` will introduce horrible and
53-
hard to track down bugs.
51+
在函数 `test` 内不使用 `var` 关键字声明 `foo` 变量将会覆盖外部的同名变量。
52+
起初这看起来并不是大问题,但是当有成千上万行代码时,不使用 `var` 声明变量将会带来难以跟踪的 BUG。
5453

55-
// global scope
54+
// 全局作用域
5655
var items = [/* some list */];
5756
for(var i = 0; i < 10; i++) {
5857
subLoop();
5958
}
6059

6160
function subLoop() {
62-
// scope of subLoop
63-
for(i = 0; i < 10; i++) { // missing var statement
61+
// subLoop 函数作用域
62+
for(i = 0; i < 10; i++) { // 没有使用 var 声明变量
6463
// do amazing stuff!
6564
}
6665
}
67-
68-
The outer loop will terminate after the first call to `subLoop`, since `subLoop`
69-
overwrites the global value of `i`. Using a `var` for the second `for` loop would
70-
have easily avoided this error. The `var` statement should **never** be left out
71-
unless the *desired effect* is to affect the outer scope.
7266

73-
### Local variables
67+
外部循环在第一次调用 `subLoop` 之后就会终止,因为 `subLoop` 覆盖了全局变量 `i`
68+
在第二个 `for` 循环中使用 `var` 声明变量可以避免这种错误。
69+
声明变量时**绝对不要**遗漏 `var` 关键字,除非这就是*期望*的影响外部作用域的行为。
70+
71+
### 局部变量(Local variables)
7472

75-
The only source for local variables in JavaScript are
76-
[function](#function.general) parameters and variables that were declared via the
77-
`var` statement.
73+
JavaScript 中局部变量只可能通过两种方式声明,一个是作为[函数](#functions)参数,另一个是通过 `var` 关键字声明。
7874

79-
// global scope
75+
// 全局变量
8076
var foo = 1;
8177
var bar = 2;
8278
var i = 2;
8379

8480
function test(i) {
85-
// local scope of the function test
81+
// 函数 test 内的局部作用域
8682
i = 5;
8783

8884
var foo = 3;
8985
bar = 4;
9086
}
9187
test(10);
9288

93-
While `foo` and `i` are local variables inside the scope of the function `test`,
94-
the assignment of `bar` will override the global variable with the same name.
89+
`foo``i` 是函数 `test` 内的局部变量,而对 `bar` 的赋值将会覆盖全局作用域内的同名变量。
9590

96-
### Hoisting
91+
### 变量声明提升(Hoisting
9792

98-
JavaScript **hoists** declarations. This means that both `var` statements and
99-
`function` declarations will be moved to the top of their enclosing scope.
93+
JavaScript 会**提升**变量声明。这意味着 `var` 表达式和 `function` 声明都将会被提升到当前作用域的顶部。
10094

10195
bar();
10296
var bar = function() {};
@@ -115,16 +109,14 @@ JavaScript **hoists** declarations. This means that both `var` statements and
115109
}
116110
}
117111

118-
The above code gets transformed before any execution is started. JavaScript moves
119-
the `var` statements as well as the `function` declarations to the top of the
120-
nearest surrounding scope.
112+
上面代码在运行之前将会被转化。JavaScript 将会把 `var` 表达式和 `function` 声明提升到当前作用域的顶部。
121113

122-
// var statements got moved here
123-
var bar, someValue; // default to 'undefined'
114+
// var 表达式被移动到这里
115+
var bar, someValue; // 缺省值是 'undefined'
124116

125-
// the function declartion got moved up too
117+
// 函数声明也会提升
126118
function test(data) {
127-
var goo, i, e; // missing block scope moves these here
119+
var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部
128120
if (false) {
129121
goo = 1;
130122

@@ -136,96 +128,93 @@ nearest surrounding scope.
136128
}
137129
}
138130

139-
bar(); // fails with a TypeError since bar is still 'undefined'
140-
someValue = 42; // assignments are not affected by hoisting
131+
bar(); // 出错:TypeError,因为 bar 依然是 'undefined'
132+
someValue = 42; // 赋值语句不会被提升规则(hoisting)影响
141133
bar = function() {};
142134

143135
test();
144136

145-
Missing block scoping will not only move `var` statements out of loops and
146-
their bodies, it will also make the results of certain `if` constructs
147-
non-intuitive.
137+
没有块级作用域不仅导致 `var` 表达式被从循环内移到外部,而且使一些 `if` 表达式更难看懂。
148138

149-
In the original code the `if` statement seemed to modify the *global
150-
variable* `goo`, while actually it modifies the *local variable* - after hoisting
151-
has been applied.
139+
在原来代码中,`if` 表达式看起来修改了*全部变量* `goo`,实际上在提升规则(hoisting)被应用后,却是在修改*局部变量*
152140

153-
Without the knowledge about *hoisting*, below code might seem to raise a
154-
`ReferenceError`.
141+
如果没有提升规则(hoisting)的知识,下面的代码看起来会抛出异常 `ReferenceError`
155142

156-
// check whether SomeImportantThing has been initiliazed
143+
// 检查 SomeImportantThing 是否已经被初始化
157144
if (!SomeImportantThing) {
158145
var SomeImportantThing = {};
159146
}
160147

161-
But of course, the above works due to the fact that the `var` statement is being
162-
moved to the top of the *global scope*.
148+
实际上,上面的代码正常运行,因为 `var` 表达式会被提升到*全局作用域*的顶部。
163149

164150
var SomeImportantThing;
165151

166-
// other code might initiliaze SomeImportantThing here, or not
152+
// 其它一些代码,可能会初始化 SomeImportantThing,也可能不会
167153

168-
// make sure it's there
154+
// 检查是否已经被初始化
169155
if (!SomeImportantThing) {
170156
SomeImportantThing = {};
171157
}
172158

173-
### Name resolution order
159+
160+
译者注:在 Nettuts+ 网站有一篇介绍 hoisting 的[文章][1],其中的代码很有启发性。
174161

175-
All scopes in JavaScript, including the *global scope*, have the special name
176-
[`this`](#function.this) defined in them, which refers to the *current object*.
162+
// 译者注:来自 Nettuts+ 的一段代码,生动的阐述了 JavaScript 中变量声明提升规则
163+
var myvar = 'my value';
164+
165+
(function() {
166+
alert(myvar); // undefined
167+
var myvar = 'local value';
168+
})();
169+
170+
171+
### 名称解析顺序(Name resolution order)
177172

178-
Function scopes also have the name [`arguments`](#function.arguments) defined in
179-
them which contains the arguments that were passed to a function.
173+
JavaScript 中的所有作用域,包括*全局作用域*,都有一个特别的名称 [`this`](#this) 指向当前对象。
180174

181-
For example, when trying to access a variable named `foo` inside the scope of a
182-
function, JavaScript will lookup the name in the following order:
175+
函数作用域内也有默认的变量 [`arguments`](#arguments),其中包含了传递到函数中的参数。
183176

184-
1. In case there is a `var foo` statement in the current scope use that.
185-
2. If one of the function parameters is named `foo` use that.
186-
3. If the function itself is called `foo` use that.
187-
4. Go to the next outer scope and start with **#1** again.
177+
比如,当访问函数内的 `foo` 变量时,JavaScript 会按照下面顺序查找:
188178

189-
> **Note:** Having a parameter called `arguments` will **prevent** the creation
190-
> of the default `arguments` object.
179+
1. 当前作用域内是否有 `var foo` 的定义。
180+
2. 函数形式参数是否有使用 `foo` 名称的。
181+
3. 函数自身是否叫做 `foo`
182+
4. 回溯到上一级作用域,然后从 **#1** 重新开始。
191183

192-
### Namespaces
184+
> **注意:** 自定义 `arguments` 参数将会阻止原生的 `arguments` 对象的创建。
193185
194-
A common problem of having only one global namespace is the likeliness of running
195-
into problems where variable names clash. In JavaScript, this problem can
196-
easily be avoided with the help of *anonymous wrappers*.
186+
### 命名空间(Namespaces)
187+
188+
只有一个全局作用域导致的常见错误是命名冲突。在 JavaScript中,这可以通过 *匿名包装器* 轻松解决。
197189

198190
(function() {
199-
// a self contained "namespace"
191+
// 函数创建一个命名空间(译者注:也就是作用域)
200192
201193
window.foo = function() {
202-
// an exposed closure
194+
// 对外公开的函数,创建了闭包
203195
};
204196

205-
})(); // execute the function immediately
206-
197+
})(); // 立即执行此匿名函数
207198

208-
Unnamed functions are considered [expressions](#function.general); so in order to
209-
being callable, they must first be evaluated.
199+
匿名函数被认为是 [表达式](#functions);因此为了可调用性,它们首先会被执行(evaluated)。
210200

211-
( // evaluate the function inside the paranthesis
201+
( // 小括号内的函数首先被执行
212202
function() {}
213-
) // and return the function object
214-
() // call the result of the evaluation
203+
) // 并且返回函数对象
204+
() // 调用上面的执行结果,也就是函数对象
215205

216-
There are other ways for evaluating and calling the function expression; which,
217-
while different in syntax, do behave the exact same way.
206+
有一些其他的调用函数表达式的方法,比如下面的两种方式语法不同,但是效果一模一样。
218207

219-
// Two other ways
208+
// 另外两种方式
220209
+function(){}();
221210
(function(){}());
222211

223-
### In conclusion
212+
### 结论(In conclusion)
213+
214+
推荐使用*匿名包装器*(译者注:也就是自执行的匿名函数)来创建命名空间。这样不仅可以防止命名冲突,
215+
而且有利于程序的模块化。
224216

225-
It is recommended to always use an *anonymous wrapper* for encapsulating code in
226-
its own namespace. This does not only protect code against name clashes, it
227-
also allows for better modularization of programs.
217+
另外,使用全局变量被认为是**不好的习惯**。这样的代码倾向于产生错误和带来高的维护成本。
228218

229-
Additionally, the use of global variables is considered **bad practice**. **Any**
230-
use of them indicates badly written code that is prone to errors and hard to maintain.
231219

220+
[1]: http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/

0 commit comments

Comments
 (0)