Skip to content

Commit

Permalink
Chinese Transition Part-1 (#43)
Browse files Browse the repository at this point in the history
* init chinese file

* init translation of zh-CN

* delete

* init Simplified Chinese file

* update translation

* complete  part-1 variable declaration

* update TOC

* update TOC
  • Loading branch information
soyaine authored and mbeaudru committed Sep 29, 2017
1 parent 65851e0 commit 3b9fcd8
Showing 1 changed file with 201 additions and 1 deletion.
202 changes: 201 additions & 1 deletion translations/zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,204 @@

除此之外,我(作者:[Manuel Beaudru](https://github.com/mbeaudru))偶尔会写上一些我的小技巧,也会注意提示这只是我的个人提议。

> **注:** 这篇文档里提到的大多数概念来自于目前最新的 JavaScript(ES2015,即 ES6),你可以在[这里]http://es6-features.org)新增的特性,网站做得很棒。
> **注:** 这篇文档里提到的大多数概念来自于目前最新的 JavaScript(ES2015,即 ES6),你可以在[这里](http://es6-features.org)查看新增的特性,网站做得很棒。
### 参考材料

当你觉得有的概念不容易理解时,你可以在下面的链接里面寻找答案。

- [MDN (Mozilla Developer Network)](https://developer.mozilla.org/zh-CN/search?q=)
- [You don't know JS(书)](https://github.com/getify/You-Dont-Know-JS)
- [ES6 新特性和例子](http://es6-features.org)
- [WesBos 博客中 ES6 类别](http://wesbos.com/category/es6/)
- [Reddit (JavaScript)](https://www.reddit.com/r/javascript/)
- [Google](https://www.google.com/) 可直接查找特定的博客和资源
- [StackOverflow](https://stackoverflow.com/questions/tagged/javascript)

## 目录

- [Modern JavaScript Cheatsheet 简体中文版](#Modern-JavaScript-Cheatsheet-简体中文版)
* [简介](#简介)
+ [初心](#初心)
+ [参考材料](#参考材料)
* [目录](#目录)
* [正文](#正文)
+ [变量声明: var, const, let](#变量声明-var-const-let)
- [简述](#简述)
- [代码示例](#代码示例)
- [详述](#详述)
- [延伸资料](#延伸资料)
+ [箭头函数](#箭头函数)
- [简述](#简述)
- [详述](#详述)
* [简洁性](#简洁性)
* [*this* 关键字](#this-关键字)
- [延伸资料](#延伸资料)

## 正文

### 变量声明: var, const, let

在 JavaScript 中,声明变量时可以用三个不同的关键词,分别是 `var``let` 以及 `const` ,它们各有异同。

#### 简述

`const` 声明的变量,不能被重新赋值,而另两个 `var``let` 是可以的。

所以我建议默认情况下你都用 `const` 来声明变量,在你需要 *改变* 或是声明之后再重新指派它的时候,才用 `let` 来声明变量。


| - | 作用域 | 是否可重新赋值 | 是否可变 | [暂存死区](#tdz_sample) |
| ----- | ---- | ------- | -------------------------- | ------------------- |
| const | 块级 | × | [](#const_mutable_sample) ||
| let | 块级 ||||
| var | 函数 ||| × |

#### 代码示例

```javascript
const person = "Nick";
person = "John" // 因为 person 不能被重新赋值,所以会报错
```

```javascript
let person = "Nick";
person = "John";
console.log(person) // "John", 使用 let 声明的变量可以重新赋值
```

#### 详述

简单来讲,变量的作用域([*scope*](#scope_def))是指“在这部分代码中可以访问到此变量”。

##### var

使用 `var` 定义的变量,其作用域是定义它的函数内部(*function scoped*),也就是说在函数内部创建一个 `var` 变量的时候,在此函数内部可以任意访问这个变量,但在函数之外,这样的局部变量是无法被访问的。

我建议你这样理解,如果一个变量是 *X 作用域(scoped)* 类型的,那就是说这个变量是 X 的属性之一。(译注:X 有 function 和 block 两类,代表函数作用域和块级作用域。)

```javascript
function myFunction() {
var myVar = "Nick";
console.log(myVar); // "Nick" - 在这个函数中 myVar 可被访问到
}
console.log(myVar); // 抛出错误 ReferenceError, 在函数之外 myVar 则无法访问
```

继续来看变量的作用域,下面有更多精妙的例子:

```javascript
function myFunction() {
var myVar = "Nick";
if (true) {
var myVar = "John";
console.log(myVar); // "John"
// 实际上 myVar 是函数级作用域变量,重新声明的时候,相当于用 "John" 抹去了 myVar 之前的值 "Nick"
}
console.log(myVar); // "John" - 可见 if 块中的代码会如何影响变量
}
console.log(myVar); // 抛出错误 ReferenceError, 在函数之外 myVar 则无法访问
```

另外,*var* 声明的变量在执行的时候,就像会被移动到作用域的开始,这就是我们所说的[变量声明提升(var hoisting)](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/**var)

所以看下面这段代码:

```javascript
console.log(myVar) // undefined -- 没有提示错误
var myVar = 2;
```

之所以没有发生错误,是因为它执行时会被解释为这样:

```javascript
var myVar;
console.log(myVar) // undefined -- 没有提示错误
myVar = 2;
```

##### let

`var``let` 几乎是一样的,但是用 `let` 声明的变量有如下特性:

- *块级作用域*( block scoped )
- 在被赋值之前,是**无法**访问使用的
- 在同一个作用域之下,不能被重新声明

我们来看看之前例子中提到的块级作用域( block scoping )的效果:

```javascript
function myFunction() {
let myVar = "Nick";
if (true) {
let myVar = "John";
console.log(myVar); // "John"
// 实际上 myVar 是块级作用域的变量,在 if 块中,我们相当于是创建了一个新变量,
// 这个变量在此块之外是无法被访问的,而且它完全区别于我们创建的第一个 myVar 变量!
}
console.log(myVar); // "Nick", 可见 if 块中的代码,并没有影响到这个变量的值
}
console.log(myVar); // 抛出错误 ReferenceError,在函数外部无法访问到 myVar。
```

<a name="tdz_sample"></a>现在,来看看 *let*(和 *const* )声明的变量在赋值前无法访问是什么意思:

```javascript
console.log(myVar) // 提示错误 ReferenceError !
let myVar = 2;
```

这就是它们和 *var* 变量的区别,如果你在还未赋值给 *let* 或者 *const* 变量之前,就想读写它,是会提示错误的。这种情况常被称作暂存死区([*Temporal dead zone*](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let#let_的暂存死区与错误))或者 *TDZ*

> **注意:** 从技术上讲,*let**const* 变量声明时也存在提升,但并不代表它们的赋值也会被提升。但由于它被设计成了赋值之前无法使用,所以我们直观感觉上它没有被提升,但其实是存在提升的。如果想了解更多细节,请看[这篇文章](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified)

另外,在同一作用域内你不能重新声明一个 *let* 变量。

```js
let myVar = 2;
let myVar = 3; // 提示语法错误 SyntaxError
```

##### const

`const` 声明的变量很像 `let`,但它不能被重新赋值。

总结一下 `const` 变量的特点如下:

- *块级作用域*
- 赋值之前无法使用
- 在同一个作用域内部,你不能重新声明一个变量
- 不能被重新指派

```Javascript
const myVar = "Nick";
myVar = "John" // 提示错误,不允许重新赋值 const 变量
```

<a name="const_mutable_sample"></a>但这里有一个小细节:`const` 变量并非完全[不可变](#mutation_def),如果这个变量是 `object``array` 类型的值,那它的值是**可以改变**的。assign

对于对象类型来说:

```js
const person = {
name: 'Nick'
};
person.name = 'John' // 这会生效的!person 并非完全重新指派( reassigned ),只是值变化了( mutated )
console.log(person.name) // "John"
person = "Sandra" // 提示错误,因为用 const 声明的变量不能被重新指派
```

对于数组类型来说:

```js
const person = [];
person.push('John'); // 这也会生效!person 并非完全重新指派( reassigned ),只是值变化了( mutated )
console.log(person[0]) // "John"
person = ["Nick"] // 提示错误,因为用 const 声明的变量不能被重新指派
```

#### 延伸资料

- [How let and const are scoped in JavaScript - WesBos](http://wesbos.com/javascript-scoping/)
- [Temporal Dead Zone (TDZ) Demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified)

0 comments on commit 3b9fcd8

Please sign in to comment.