Skip to content

Commit d3d993e

Browse files
committed
Merge branch 'zh-translation'
2 parents c097ee8 + b9e1869 commit d3d993e

31 files changed

Lines changed: 5454 additions & 3 deletions

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,3 @@ Stack Overflow chat.
3838
[8]: https://github.com/caio
3939
[9]: https://github.com/blixt
4040
[10]: http://chat.stackoverflow.com/rooms/17/javascript
41-

doc/language.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"default": "en",
3-
"listed": ["en", "ru"]
3+
"listed": ["en", "ru", "zh"]
44
}
55

doc/zh/array/constructor.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
##`Array` 构造函数
2+
3+
由于 `Array` 的构造函数在如何处理参数时有点模棱两可,因此总是推荐使用数组的字面语法 - `[]` - 来创建数组。
4+
5+
[1, 2, 3]; // 结果: [1, 2, 3]
6+
new Array(1, 2, 3); // 结果: [1, 2, 3]
7+
8+
[3]; // 结果: [3]
9+
new Array(3); // 结果: []
10+
new Array('3') // 结果: ['3']
11+
12+
// 译者注:因此下面的代码将会使人很迷惑
13+
new Array(3, 4, 5); // 结果: [3, 4, 5]
14+
new Array(3) // 结果: [],此数组长度为 3
15+
16+
> **译者注:**这里的模棱两可指的是数组的[两种构造函数语法][1]
17+
18+
由于只有一个参数传递到构造函数中(译者注:指的是 `new Array(3);` 这种调用方式),并且这个参数是数字,构造函数会返回一个 `length` 属性被设置为此参数的空数组。
19+
需要特别注意的是,此时只有 `length` 属性被设置,真正的数组并没有生成。
20+
21+
> **译者注:**在 Firebug 中,你会看到 `[undefined, undefined, undefined]`,这其实是不对的。在上一节有详细的分析。
22+
23+
var arr = new Array(3);
24+
arr[1]; // undefined
25+
1 in arr; // false, 数组还没有生成
26+
27+
这种优先于设置数组长度属性的做法只在少数几种情况下有用,比如需要循环字符串,可以避免 `for` 循环的麻烦。
28+
29+
new Array(count + 1).join(stringToRepeat);
30+
31+
> **译者注:** `new Array(3).join('#')` 将会返回 `##`
32+
33+
###结论
34+
35+
应该尽量避免使用数组构造函数创建新数组。推荐使用数组的字面语法。它们更加短小和简洁,因此增加了代码的可读性。
36+
37+
[1]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
38+

doc/zh/array/general.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
##数组遍历与属性
2+
3+
虽然在 JavaScript 中数组是是对象,但是没有好的理由去使用 [`for in` 循环](#object.forinloop) 遍历数组。
4+
相反,有一些好的理由**不去**使用 `for in` 遍历数组。
5+
6+
> **注意:** JavaScript 中数组**不是** *关联数组*
7+
> JavaScript 中只有[对象](#object.general) 来管理键值的对应关系。但是关联数组是**保持**顺序的,而对象**不是**
8+
9+
由于 `for in` 循环会枚举原型链上的所有属性,唯一过滤这些属性的方式是使用 [`hasOwnProperty`](#object.hasownproperty) 函数,
10+
因此会比普通的 `for` 循环慢上好多倍。
11+
12+
###遍历
13+
14+
为了达到遍历数组的最佳性能,推荐使用经典的 `for` 循环。
15+
16+
var list = [1, 2, 3, 4, 5, ...... 100000000];
17+
for(var i = 0, l = list.length; i < l; i++) {
18+
console.log(list[i]);
19+
}
20+
21+
上面代码有一个处理,就是通过 `l = list.length` 来缓存数组的长度。
22+
23+
虽然 `length` 是数组的一个属性,但是在每次循环中访问它还是有性能开销。
24+
**可能**最新的 JavaScript 引擎在这点上做了优化,但是我们没法保证自己的代码是否运行在这些最近的引擎之上。
25+
26+
实际上,不使用缓存数组长度的方式比缓存版本要慢很多。
27+
28+
###`length` 属性
29+
30+
`length` 属性的 *getter* 方式会简单的返回数组的长度,而 *setter* 方式会**截断**数组。
31+
32+
var foo = [1, 2, 3, 4, 5, 6];
33+
foo.length = 3;
34+
foo; // [1, 2, 3]
35+
36+
foo.length = 6;
37+
foo; // [1, 2, 3]
38+
39+
**译者注:**
40+
在 Firebug 中查看此时 `foo` 的值是: `[1, 2, 3, undefined, undefined, undefined]`
41+
但是这个结果并不准确,如果你在 Chrome 的控制台查看 `foo` 的结果,你会发现是这样的: `[1, 2, 3]`
42+
因为在 JavaScript 中 `undefined` 是一个变量,注意是变量不是关键字,因此上面两个结果的意义是完全不相同的。
43+
44+
// 译者注:为了验证,我们来执行下面代码,看序号 5 是否存在于 foo 中。
45+
5 in foo; // 不管在 Firebug 或者 Chrome 都返回 false
46+
foo[5] = undefined;
47+
5 in foo; // 不管在 Firebug 或者 Chrome 都返回 true
48+
49+
`length` 设置一个更小的值会截断数组,但是增大 `length` 属性值不会对数组产生影响。
50+
51+
###结论
52+
53+
为了更好的性能,推荐使用普通的 `for` 循环并缓存数组的 `length` 属性。
54+
使用 `for in` 遍历数组被认为是不好的代码习惯并倾向于产生错误和导致性能问题。
55+

doc/zh/core/eval.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
##为什么不要使用 `eval`
2+
3+
`eval` 函数会在当前作用域中执行一段 JavaScript 代码字符串。
4+
5+
var foo = 1;
6+
function test() {
7+
var foo = 2;
8+
eval('foo = 3');
9+
return foo;
10+
}
11+
test(); // 3
12+
foo; // 1
13+
14+
但是 `eval` 只在被**直接**调用并且调用函数就是 `eval` 本身时,才在当前作用域中执行。
15+
16+
var foo = 1;
17+
function test() {
18+
var foo = 2;
19+
var bar = eval;
20+
bar('foo = 3');
21+
return foo;
22+
}
23+
test(); // 2
24+
foo; // 3
25+
26+
**[译者注][30]**上面的代码等价于在全局作用域中调用 `eval`,和下面两种写法效果一样:
27+
28+
// 写法一:直接调用全局作用域下的 foo 变量
29+
var foo = 1;
30+
function test() {
31+
var foo = 2;
32+
window.foo = 3;
33+
return foo;
34+
}
35+
test(); // 2
36+
foo; // 3
37+
38+
// 写法二:使用 call 函数修改 eval 执行的上下文为全局作用域
39+
var foo = 1;
40+
function test() {
41+
var foo = 2;
42+
eval.call(window, 'foo = 3');
43+
return foo;
44+
}
45+
test(); // 2
46+
foo; // 3
47+
48+
**任何情况下**我们都应该避免使用 `eval` 函数。99.9% 使用 `eval` 的场景都有**不使用** `eval` 的解决方案。
49+
50+
###伪装的 `eval`
51+
52+
[定时函数](#other.timeouts) `setTimeout``setInterval` 都可以接受字符串作为它们的第一个参数。
53+
这个字符串**总是**在全局作用域中执行,因此 `eval` 在这种情况下没有被直接调用。
54+
55+
56+
###安全问题
57+
58+
`eval` 也存在安全问题,因为它会执行**任意**传给它的代码,
59+
在代码字符串未知或者是来自一个不信任的源时,绝对不要使用 `eval` 函数。
60+
61+
###结论
62+
63+
绝对不要使用 `eval`,任何使用它的代码都会在它的工作方式,性能和安全性方面受到质疑。
64+
如果一些情况必须使用到 `eval` 才能正常工作,首先它的设计会受到质疑,这**不应该**是首选的解决方案,
65+
一个更好的不使用 `eval` 的解决方案应该得到充分考虑并优先采用。
66+
67+
[30]: http://cnblogs.com/sanshi/

doc/zh/core/semicolon.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
##自动分号插入
2+
3+
尽管 JavaScript 有 C 的代码风格,但是它****强制要求在代码中使用分号,实际上可以省略它们。
4+
5+
JavaScript 不是一个没有分号的语言,恰恰相反上它需要分号来就解析源代码。
6+
因此 JavaScript 解析器在遇到由于缺少分号导致的解析错误时,会**自动**在源代码中插入分号。
7+
8+
var foo = function() {
9+
} // 解析错误,分号丢失
10+
test()
11+
12+
自动插入分号,解析器重新解析。
13+
14+
var foo = function() {
15+
}; // 没有错误,解析继续
16+
test()
17+
18+
自动的分号插入被认为是 JavaScript 语言**最大**的设计缺陷之一,因为它**改变代码的行为。
19+
20+
### 工作原理
21+
22+
下面的代码没有分号,因此解析器需要自己判断需要在哪些地方插入分号。
23+
24+
(function(window, undefined) {
25+
function test(options) {
26+
log('testing!')
27+
28+
(options.list || []).forEach(function(i) {
29+
30+
})
31+
32+
options.value.test(
33+
'long string to pass here',
34+
'and another long string to pass'
35+
)
36+
37+
return
38+
{
39+
foo: function() {}
40+
}
41+
}
42+
window.test = test
43+
44+
})(window)
45+
46+
(function(window) {
47+
window.someLibrary = {}
48+
})(window)
49+
50+
下面是解析器"猜测"的结果。
51+
52+
(function(window, undefined) {
53+
function test(options) {
54+
55+
// 没有插入分号,两行被合并为一行
56+
log('testing!')(options.list || []).forEach(function(i) {
57+
58+
}); // <- 插入分号
59+
60+
options.value.test(
61+
'long string to pass here',
62+
'and another long string to pass'
63+
); // <- 插入分号
64+
65+
return; // <- 插入分号, 改变了 return 表达式的行为
66+
{ // 作为一个代码段处理
67+
foo: function() {}
68+
}; // <- 插入分号
69+
}
70+
window.test = test; // <- 插入分号
71+
72+
// 两行又被合并了
73+
})(window)(function(window) {
74+
window.someLibrary = {}; // <- 插入分号
75+
})(window); //<- 插入分号
76+
77+
> **注意:** JavaScript 不能正确的处理 `return` 表达式紧跟换行符的情况,
78+
> 虽然这不能算是自动分号插入的错误,但这确实是一种不希望的副作用。
79+
80+
解析器显著改变了上面代码的行为,在另外一些情况下也会做出**错误的处理**
81+
82+
###前置括号
83+
84+
在前置括号的情况下,解析器**不会**自动插入分号。
85+
86+
log('testing!')
87+
(options.list || []).forEach(function(i) {})
88+
89+
上面代码被解析器转换为一行。
90+
91+
log('testing!')(options.list || []).forEach(function(i) {})
92+
93+
`log` 函数的执行结果**极大**可能**不是**函数;这种情况下就会出现 `TypeError` 的错误,详细错误信息可能是 `undefined is not a function`
94+
95+
###结论
96+
97+
建议**绝对**不要省略分号,同时也提倡将花括号和相应的表达式放在一行,
98+
对于只有一行代码的 `if` 或者 `else` 表达式,也不应该省略花括号。
99+
这些良好的编程习惯不仅可以提到代码的一致性,而且可以防止解析器改变代码行为的错误处理。
100+

doc/zh/core/undefined.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
##`undefined``null`
2+
3+
JavaScript 有两个表示‘空’的值,其中比较有用的是 `undefined`
4+
5+
###`undefined` 的值
6+
7+
`undefined` 是一个值为 `undefined` 的类型。
8+
9+
这个语言也定义了一个全局变量,它的值是 `undefined`,这个变量也被称为 `undefined`
10+
但是这个变量**不是**一个常量,也不是一个关键字。这意味着它的**可以轻易被覆盖。
11+
12+
> **ES5 提示:** 在 ECMAScript 5 的严格模式下,`undefined` **不再是** *可写*的了。
13+
> 但是它的名称仍然可以被隐藏,比如定义一个函数名为 `undefined`
14+
15+
下面的情况会返回 `undefined` 值:
16+
17+
- 访问未修改的全局变量 `undefined`
18+
- 由于没有定义 `return` 表达式的函数隐式返回。
19+
- `return` 表达式没有显式的返回任何内容。
20+
- 访问不存在的属性。
21+
- 函数参数没有被显式的传递值。
22+
- 任何被设置为 `undefined` 值的变量。
23+
24+
###处理 `undefined` 值的改变
25+
26+
由于全局变量 `undefined` 只是保存了 `undefined` 类型实际**的副本,
27+
因此对它赋新值**不会**改变类型 `undefined` 的值。
28+
29+
然而,为了方便其它变量和 `undefined` 做比较,我们需要事先获取类型 `undefined` 的值。
30+
31+
为了避免可能对 `undefined` 值的改变,一个常用的技巧是使用一个传递到[匿名包装器](#function.scopes)的额外参数。
32+
在调用时,这个参数不会获取任何值。
33+
34+
var undefined = 123;
35+
(function(something, foo, undefined) {
36+
// 局部作用域里的 undefined 变量重新获得了 `undefined` 值
37+
38+
})('Hello World', 42);
39+
40+
另外一种达到相同目的方法是在函数内使用变量声明。
41+
42+
var undefined = 123;
43+
(function(something, foo) {
44+
var undefined;
45+
...
46+
47+
})('Hello World', 42);
48+
49+
这里唯一的区别是,在压缩后并且函数内没有其它需要使用 `var` 声明变量的情况下,这个版本的代码会多出 4 个字节的代码。
50+
51+
> **[译者注][30]**这里有点绕口,其实很简单。如果此函数内没有其它需要声明的变量,那么 `var` 总共 4 个字符(包含一个空白字符)
52+
就是专门为 `undefined` 变量准备的,相比上个例子多出了 4 个字节。
53+
54+
###`null` 的用处
55+
56+
JavaScript 中的 `undefined` 的使用场景类似于其它语言中的 *null*,实际上 JavaScript 中的 `null` 是另外一种数据类型。
57+
58+
它在 JavaScript 内部有一些使用场景(比如声明原型链的终结 `Foo.prototype = null`),但是大多数情况下都可以使用 `undefined` 来代替。
59+
60+
[30]: http://cnblogs.com/sanshi/

0 commit comments

Comments
 (0)