Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion 1-js/02-first-steps/01-hello-world/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ JavaScript 程序可以在 `<script>` 标签的帮助下插入到 HTML 文档的
`<script>` 标签有一些现在很少用到的特性(attribute),但是我们可以在老代码中找到它们:

`type` 特性:<code>&lt;script <u>type</u>=...&gt;</code>
: 在老的 HTML4 标准中,要求 script 标签有 `type` 特性。通常是 `type="text/javascript"`。这样的特性声明现在已经不再需要。而且,现代 HTML 标准已经完全改变了此特性的含义。现在,它可以用于 JavaScript 模块。但这是一个高级话题我们将在本教程的另一部分中探讨 JavaScript 模块。
: 在老的 HTML4 标准中,要求 script 标签有 `type` 特性。通常是 `type="text/javascript"`。这样的特性声明现在已经不再需要。而且,现代 HTML 标准已经完全改变了此特性的含义。现在,它可以用于 JavaScript 模块。但这是一个高级话题我们将在本教程的另一部分中探讨 JavaScript 模块。

`language` 特性:<code>&lt;script <u>language</u>=...&gt;</code>
: 这个特性是为了显示脚本使用的语言。这个特性现在已经没有任何意义,因为语言默认就是 JavaScript。不再需要使用它了。
Expand Down
2 changes: 1 addition & 1 deletion 1-js/02-first-steps/13-switch/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ switch (+a) {
比如,如果我们想让 `case 3` 和 `case 5` 执行同样的代码:

```js run no-beautify
let a = 2 + 2;
let a = 3;

switch (a) {
case 4:
Expand Down
11 changes: 5 additions & 6 deletions 1-js/05-data-types/02-number/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ let ms = 1e-6; // six zeroes to the left from 1

### 十六进制,二进制和八进制数字

[十六进制](https://en.wikipedia.org/wiki/Hexadecimal)数字在 JavaScript 中被广泛用于表示颜色,编码字符以及其他许多事物。所以很自然地,写一个更简短的方法:`0x` 然后是数字。
[十六进制](https://en.wikipedia.org/wiki/Hexadecimal) 数字在 JavaScript 中被广泛用于表示颜色,编码字符以及其他许多事物。所以很自然地,写一个更简短的方法:`0x` 然后是数字。

例如:

Expand Down Expand Up @@ -279,7 +279,6 @@ JavaScript 在这种事件中不会触发错误。它尽最大努力使数字符
```



## 测试:isFinite 和 isNaN

还记得这两个特殊的数值吗?
Expand Down Expand Up @@ -325,7 +324,7 @@ alert( isFinite(num) );

```smart header="与 Object.is 进行比较"

有一种特殊的内置方法 [Object.is](mdn:js/Object/is),它可以比较 `===` 等值,但对于两种边缘情况更可靠:
有一种特殊的内置方法 [`Object.is`](mdn:js/Object/is),它可以比较 `===` 等值,但对于两种边缘情况更可靠:

1. 它适用于 `NaN`: `Object.is(NaN,NaN)=== true`,这是件好事。
2. 值 `0` 和 `-0` 是不同的:`Object.is(0,-0)=== false`,它不是很重要,但这些值在技术上是不同的。
Expand Down Expand Up @@ -407,7 +406,7 @@ JavaScript 有一个内置的 [Math](https://developer.mozilla.org/en/docs/Web/J
alert( Math.pow(2, 10) ); // 2 的 10 次幂 = 1024
```

这里有 `Math` 对象中的更多函数和常量,包括三角函数,你可以在这里找到它 [docs for the Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math)。
这里有 `Math` 对象中的更多函数和常量,包括三角函数,你可以在 [Math 函数文档](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) 中找到这些内容

## 总结

Expand All @@ -428,9 +427,9 @@ JavaScript 有一个内置的 [Math](https://developer.mozilla.org/en/docs/Web/J

分数:

- 使用 `Math.floor``Math.ceil``Math.trunc``Math.round` 或 `num.toFixed(precision)` 截取。
- 使用 `Math.floor``Math.ceil``Math.trunc``Math.round` 或 `num.toFixed(precision)` 截取。
- 请记住,使用分数时会损失精度。

更多的数学函数:

- 需要时请参阅 [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) 对象,虽然这个文档非常小,但是它可以满足基础的要求。
- 需要时请参阅 [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) 对象虽然这个文档非常小但是它可以满足基础的要求。
45 changes: 45 additions & 0 deletions 1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,51 @@ alert( Array.from(str) ); // H,e,l,l,o
因此,对于将一些“东西”转换为数组的任务,`Array.from` 往往更通用。


## 获取一个 object/array 的副本

还记得我们 [之前讲过的](https://zh.javascript.info/object#fu-zhi-he-he-bing-objectassign) `Object.assign()` 吗?

使用 spread 操作符也可以做同样的事情。

```js run
let arr = [1, 2, 3];
let arrCopy = [...arr]; // 将数组 spread 到参数列表中
// 然后将结果放到一个新数组

// 两个数组中的内容相同吗?
alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true

// 两个数组相等吗?
alert(arr === arrCopy); // false(它们的引用是不同的)

// 修改我们初始的数组不会修改副本:
arr.push(4);
alert(arr); // 1, 2, 3, 4
alert(arrCopy); // 1, 2, 3
```

并且,也可以通过相同的方式来复制一个对象:

```js run
let obj = { a: 1, b: 2, c: 3 };
let objCopy = { ...obj }; // 将对象 spread 到参数列表中
// 然后将结果返回到一个新对象

// 两个对象中的内容相同吗?
alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true

// 两个对象相等吗?
alert(obj === objCopy); // false (not same reference)

// 修改我们初始的对象不会修改副本:
obj.d = 4;
alert(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4}
alert(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}
```

这种方式比使用 `let arrCopy = Object.assign([], arr);` 来复制数组,或使用 `let objCopy = Object.assign({}, obj);` 来复制对象写起来要短得多。因此,只要情况允许,我们更喜欢使用它。


## 总结

当我们在代码中看到 `"..."` 时,它要么是 rest 参数,要么就是 spread 语法。
Expand Down
2 changes: 1 addition & 1 deletion 1-js/06-advanced-functions/03-closure/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ alert( counter() ); // 2
右侧的矩形演示了执行过程中全局词法环境的变化:

1. 当脚本开始运行,词法环境预先填充了所有声明的变量。
- 最初,它们处于“未初始化(Uninitialized)”状态。这是一种特殊的内部状态,这意味着引擎知道变量,但是不允许在 `let` 之前使用它。几乎就像变量不存在一样。
- 最初,它们处于“未初始化(Uninitialized)”状态。这是一种特殊的内部状态,这意味着引擎知道变量,但是在用 `let` 声明前,不能引用它。几乎就像变量不存在一样。
2. 然后 `let phrase` 定义出现了。它尚未被赋值,因此它的值为 `undefined`。从这一刻起,我们就可以使用变量了。
3. `phrase` 被赋予了一个值。
4. `phrase` 的值被修改。
Expand Down
91 changes: 87 additions & 4 deletions 1-js/09-classes/01-class/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,13 +298,17 @@ class User {
new User().sayHi();
```

## Class 属性
## Class 字段

```warn header="旧的浏览器可能需要 polyfill"
类级别的属性是最近才添加到语言中的
类字段(field)是最近才添加到语言中的
```

在上面的例子中,`User` 只有方法。现在我们为其添加一个属性:
之前,类仅具有方法。

“类字段”是一种允许添加任何属性的语法。

例如,让我们在 `class User` 中添加一个 `name` 属性:

```js run
class User {
Expand All @@ -323,7 +327,86 @@ alert(User.prototype.sayHi); // 被放在 User.prototype 中
alert(User.prototype.name); // undefined,没有被放在 User.prototype 中
```

`name` 属性没有被放在 `User.prototype` 中。相反,它是在调用构造器之前通过 `new` 分创建的,它是对象自身的属性。
关于类字段的重要一点是,它们设置在单个对象上的,而不是设置在 `User.prototype` 上的。

从技术上讲,它们是在 constructor 完成工作后被处理的。

### 使用类字段制作绑定方法

正如 <info:bind> 一章中所讲的,JavaScript 中的函数具有动态的 `this`。它取决于调用上下文。

因此,如果一个对象方法被传递到某处,或者在另一个上下文中被调用,则 `this` 将不再是对其对象的引用。

例如,此代码将显示 `undefined`:

```js run
class Button {
constructor(value) {
this.value = value;
}

click() {
alert(this.value);
}
}

let button = new Button("hello");

*!*
setTimeout(button.click, 1000); // undefined
*/!*
```

这个问题被称为“丢失 `this`”。

我们在 <info:bind> 一章中讲过,有两种可以修复它的方式:

1. 传递一个包装函数,例如 `setTimeout(() => button.click(), 1000)`。
2. 将方法绑定到对象,例如在 constructor 中:

```js run
class Button {
constructor(value) {
this.value = value;
*!*
this.click = this.click.bind(this);
*/!*
}

click() {
alert(this.value);
}
}

let button = new Button("hello");

*!*
setTimeout(button.click, 1000); // hello
*/!*
```

类字段为后一种解决方案提供了更优雅的语法:

```js run
class Button {
constructor(value) {
this.value = value;
}
*!*
click = () => {
alert(this.value);
}
*/!*
}

let button = new Button("hello");

setTimeout(button.click, 1000); // hello
```

类字段 `click = () => {...}` 在每个 `Button` 对象上创建一个独立的函数,并将 `this` 绑定到该对象上。然后,我们可以将 `button.click` 传递到任何地方,并且它会被以正确的 `this` 进行调用。

这在浏览器环境中,当我们需要将一个方法设置为事件监听器时尤其有用。

## 总结

Expand Down
2 changes: 1 addition & 1 deletion 1-js/99-js-misc/03-currying-partials/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ alert( curriedSum(1)(2) ); // 3
正如你所看到的,实现非常简单:只有两个包装器(wrapper)。

- `curry(func)` 的结果就是一个包装器 `function(a)`。
- 当它被像 `sum(1)` 这样调用时,它的参数会被保存在词法环境中,然后返回一个新的包装器 `function(b)`。
- 当它被像 `curriedSum(1)` 这样调用时,它的参数会被保存在词法环境中,然后返回一个新的包装器 `function(b)`。
- 然后这个包装器被以 `2` 为参数调用,并且,它将该调用传递给原始的 `sum` 函数。

柯里化更高级的实现,例如 lodash 库的 [_.curry](https://lodash.com/docs#curry),会返回一个包装器,该包装器允许函数被正常调用或者以偏函数(partial)的方式调用:
Expand Down