1
- ## Scopes and Namespaces
1
+ ## 作用域与命名空间( Scopes and namespaces)
2
2
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
+ 而仅仅支持 * 函数作用域* 。
6
5
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++) { // 不是一个作用域
9
8
// count
10
9
}
11
10
console.log(i); // 10
12
11
}
13
12
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 ) ,这可能会导致一些不易察觉的错误。
18
15
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));
21
24
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 中没有显式的命名空间定义,这就意味着所有对象都定义在一个* 全局共享* 的命名空间下面。
25
26
26
- ### The bane of global variables
27
+ 每次引用一个变量,JavaScript 会向上遍历整个作用域直到找到这个变量为止。
28
+ 如果到达全局作用域但是这个变量仍未找到,则会抛出 ` ReferenceError ` 异常。
29
+
30
+ ### 隐式的全局变量(The bane of global variables)
27
31
28
32
// script A
29
33
foo = '42';
30
34
31
35
// script B
32
36
var foo = '42'
33
37
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 ` 。
37
39
38
- Again, that is ** not** at all the * same effect* , not using ` var ` can have major
39
- implications.
40
+ 再次强调,上面的效果** 完全不同** ,不使用 ` var ` 声明变量将会导致隐式的全局变量产生。
40
41
41
- // global scope
42
+ // 全局作用域
42
43
var foo = 42;
43
44
function test() {
44
- // local scope
45
+ // 局部作用域
45
46
foo = 21;
46
47
}
47
48
test();
48
49
foo; // 21
49
50
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。
54
53
55
- // global scope
54
+ // 全局作用域
56
55
var items = [ /* some list * /] ;
57
56
for(var i = 0; i < 10; i++) {
58
57
subLoop();
59
58
}
60
59
61
60
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 声明变量
64
63
// do amazing stuff!
65
64
}
66
65
}
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.
72
66
73
- ### Local variables
67
+ 外部循环在第一次调用 ` subLoop ` 之后就会终止,因为 ` subLoop ` 覆盖了全局变量 ` i ` 。
68
+ 在第二个 ` for ` 循环中使用 ` var ` 声明变量可以避免这种错误。
69
+ 声明变量时** 绝对不要** 遗漏 ` var ` 关键字,除非这就是* 期望* 的影响外部作用域的行为。
70
+
71
+ ### 局部变量(Local variables)
74
72
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 ` 关键字声明。
78
74
79
- // global scope
75
+ // 全局变量
80
76
var foo = 1;
81
77
var bar = 2;
82
78
var i = 2;
83
79
84
80
function test(i) {
85
- // local scope of the function test
81
+ // 函数 test 内的局部作用域
86
82
i = 5;
87
83
88
84
var foo = 3;
89
85
bar = 4;
90
86
}
91
87
test(10);
92
88
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 ` 的赋值将会覆盖全局作用域内的同名变量。
95
90
96
- ### Hoisting
91
+ ### 变量声明提升( Hoisting)
97
92
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 ` 声明都将会被提升到当前作用域的顶部。
100
94
101
95
bar();
102
96
var bar = function() {};
@@ -115,16 +109,14 @@ JavaScript **hoists** declarations. This means that both `var` statements and
115
109
}
116
110
}
117
111
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 ` 声明提升到当前作用域的顶部。
121
113
122
- // var statements got moved here
123
- var bar, someValue; // default to 'undefined'
114
+ // var 表达式被移动到这里
115
+ var bar, someValue; // 缺省值是 'undefined'
124
116
125
- // the function declartion got moved up too
117
+ // 函数声明也会提升
126
118
function test(data) {
127
- var goo, i, e; // missing block scope moves these here
119
+ var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部
128
120
if (false) {
129
121
goo = 1;
130
122
@@ -136,96 +128,93 @@ nearest surrounding scope.
136
128
}
137
129
}
138
130
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)影响
141
133
bar = function() {};
142
134
143
135
test();
144
136
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 ` 表达式更难看懂。
148
138
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)被应用后,却是在修改* 局部变量* 。
152
140
153
- Without the knowledge about * hoisting* , below code might seem to raise a
154
- ` ReferenceError ` .
141
+ 如果没有提升规则(hoisting)的知识,下面的代码看起来会抛出异常 ` ReferenceError ` 。
155
142
156
- // check whether SomeImportantThing has been initiliazed
143
+ // 检查 SomeImportantThing 是否已经被初始化
157
144
if (!SomeImportantThing) {
158
145
var SomeImportantThing = {};
159
146
}
160
147
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 ` 表达式会被提升到* 全局作用域* 的顶部。
163
149
164
150
var SomeImportantThing;
165
151
166
- // other code might initiliaze SomeImportantThing here, or not
152
+ // 其它一些代码,可能会初始化 SomeImportantThing,也可能不会
167
153
168
- // make sure it's there
154
+ // 检查是否已经被初始化
169
155
if (!SomeImportantThing) {
170
156
SomeImportantThing = {};
171
157
}
172
158
173
- ### Name resolution order
159
+
160
+ 译者注:在 Nettuts+ 网站有一篇介绍 hoisting 的[ 文章] [ 1 ] ,其中的代码很有启发性。
174
161
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)
177
172
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 ) 指向当前对象。
180
174
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 ) ,其中包含了传递到函数中的参数。
183
176
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 会按照下面顺序查找:
188
178
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 ** 重新开始。
191
183
192
- ### Namespaces
184
+ > ** 注意: ** 自定义 ` arguments ` 参数将会阻止原生的 ` arguments ` 对象的创建。
193
185
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中,这可以通过 * 匿名包装器 * 轻松解决。
197
189
198
190
(function() {
199
- // a self contained "namespace"
191
+ // 函数创建一个命名空间(译者注:也就是作用域)
200
192
201
193
window.foo = function() {
202
- // an exposed closure
194
+ // 对外公开的函数,创建了闭包
203
195
};
204
196
205
- })(); // execute the function immediately
206
-
197
+ })(); // 立即执行此匿名函数
207
198
208
- Unnamed functions are considered [ expressions] ( #function.general ) ; so in order to
209
- being callable, they must first be evaluated.
199
+ 匿名函数被认为是 [ 表达式] ( #functions ) ;因此为了可调用性,它们首先会被执行(evaluated)。
210
200
211
- ( // evaluate the function inside the paranthesis
201
+ ( // 小括号内的函数首先被执行
212
202
function() {}
213
- ) // and return the function object
214
- () // call the result of the evaluation
203
+ ) // 并且返回函数对象
204
+ () // 调用上面的执行结果,也就是函数对象
215
205
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
+ 有一些其他的调用函数表达式的方法,比如下面的两种方式语法不同,但是效果一模一样。
218
207
219
- // Two other ways
208
+ // 另外两种方式
220
209
+function(){}();
221
210
(function(){}());
222
211
223
- ### In conclusion
212
+ ### 结论(In conclusion)
213
+
214
+ 推荐使用* 匿名包装器* (译者注:也就是自执行的匿名函数)来创建命名空间。这样不仅可以防止命名冲突,
215
+ 而且有利于程序的模块化。
224
216
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
+ 另外,使用全局变量被认为是** 不好的习惯** 。这样的代码倾向于产生错误和带来高的维护成本。
228
218
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.
231
219
220
+ [ 1 ] : http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/
0 commit comments