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/04-object-basics/01-object/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ alert( a == b ); // true,两个变量指向同一个对象
alert( a === b ); // true
```

如果是两个独立的对象,则它们不相等,即使它们都是空的:
以下两个独立的对象不相等,即使都是空对象。

```js run
let a = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ importance: 5

# 创建 new Calculator

创建一个构造函数使用3种方法创建对象的 `Calculator`:
创建一个构造函数 `Calculator`,它创建的对象中有三个方法

- `read()` 使用 `prompt` 请求两个值并在对象属性中记住它们。
- `sum()` 返回这些属性的总和。
Expand Down
2 changes: 1 addition & 1 deletion 1-js/04-object-basics/06-constructor-new/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,5 @@ JavaScript 为许多内置的对象提供了构造函数:比如日期 Date,
```smart header="Objects, we'll be back!"
在本章中,我们只介绍关于对象和构造函数的基础知识。它们对于在以后章节中更多地了解数据类型和函数非常重要。

在我们学习了那些之后,我们将回到对象,在<info:prototypes><info:classes>章节中深入介绍它们。
在我们学习了那些之后,我们将回到对象,在 <info:prototypes><info:classes> 章节中深入介绍它们。
```
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ str.test = 5; // (*)
alert(str.test);
```

这里有两种结果
取决于你是否启用严格模式(`use strict`),结果可能是

1. `undefined`
2. 报错。
1. `undefined`(非严格模式)
2. 报错。(严格模式)

在 `(*)` 的那一行到底发生了什么呢:

Expand Down
2 changes: 1 addition & 1 deletion 1-js/05-data-types/01-primitives-methods/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ if (zero) { // zero is true, because it's an object
}
```

另一方面,不使用 `new` 的 `String/Number/Boolean` 是一个明智的选择。它们将一个值转换为相应的类型:转成 string,number,或 boolean(原始类型)。
另一方面,调用不带 `new`(关键字)的 `String/Number/Boolean` 函数是完全理智和有用的。它们将一个值转换为相应的类型:转成字符串、数字或布尔值(原始类型)。

例如,下面完全是有效的:
```js
Expand Down
7 changes: 4 additions & 3 deletions 1-js/05-data-types/02-number/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ alert( 0.1 + 0.2 ); // 0.30000000000000004

所以,按这种用 `10` 划分可以保证在十进制系统中运行良好,但用 `3` 划分不是。出于同样的原因,在二进制数字系统中,`2` 的幂的分割保证工作,但 `1/10` 变成一个无限的二进制小数。

使用二进制系统只能存储 *0.1* 或 *0.2*,就像没有办法将三分之一存储为小数部分一样
使用二进制系统无法*精确*存储 *0.1* 或 *0.2*,就像没有办法将三分之一存储为十进制小数一样

数字格式 IEEE-754 通过四舍五入到最接近的可能数字来解决此问题。这些舍入规则通常不允许我们看到 `极小的精确度损失`,因此数字显示为 `0.3`。但要小心,损失依然存在。

Expand Down Expand Up @@ -250,6 +250,7 @@ PHP, Java, C, Perl, Ruby 给出完全相同的结果,因为它们基于相同

```js run
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001
```

这是有效的,因为当我们做 `0.1 * 10 = 1` 和 `0.2 * 10 = 2` 时,那么这两个数字就变成了整数,并且没有精度损失。
Expand Down Expand Up @@ -349,7 +350,7 @@ alert( +"100px" ); // NaN

这就是 `parseInt` 和 `parseFloat` 的作用。

他们从字符串中“读出”一个数字,直到他们可以。如果发生错误,则返回收集的数字。函数 `parseInt` 返回一个整数,而 `parseFloat` 将返回一个浮点数:
它们从字符串中“读出”一个数字,直到无法读取为止。如果发生错误,则返回收集的数字。函数 `parseInt` 返回一个整数,而 `parseFloat` 将返回一个浮点数:

```js run
alert( parseInt('100px') ); // 100
Expand Down Expand Up @@ -427,7 +428,7 @@ 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)` 截取
- 请记住,使用分数时会损失精度。

更多的数学函数:
Expand Down
98 changes: 49 additions & 49 deletions 1-js/05-data-types/07-map-set/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@

它的方法和属性如下:

- `new Map()` -- 创建一个空集合。
- `map.set(key, value)` -- 存储含有值的键。
- `map.get(key)` -- 根据键来返回值, 如果 `key` 不在 `map`里将会返回 `undefined`。
- `map.has(key)` -- 如果 `key` 存在则返回 `true`, 否则返回 `false`。
- `map.delete(key)` -- 根据键来删除值。
- `map.clear()` -- 清空集合。
- `map.size` -- 返回当前全部元素的数量。
- `new Map()` - 创建一个空集合。
- `map.set(key, value)` - 存储含有值的键。
- `map.get(key)` - 根据键来返回值, 如果 `key` 不在 `map` 里将会返回 `undefined`。
- `map.has(key)` - 如果 `key` 存在则返回 `true`, 否则返回 `false`。
- `map.delete(key)` - 根据键来删除值。
- `map.clear()` - 清空集合。
- `map.size` - 返回当前全部元素的数量。

举个例子:

Expand All @@ -39,7 +39,7 @@ alert( map.get('1') ); // 'str1'
alert( map.size ); // 3
```

正如我们看到的那样,`Map` 的键可以被转化为字符串而不是像普通对象那样不能转化, 任何类型的键都是可能的.
如我们所见,与对象不同,键(key)不会转换为字符串。键可以是任何类型。

**Map 还可以使用对象作为键**

Expand All @@ -57,8 +57,8 @@ visitsCountMap.set(john, 123);
alert( visitsCountMap.get(john) ); // 123
```

使用对象作为键是 `Map` 最出名也是最重要的特点. 对于字符键, `Object` (普通对象)能正常使用, 但是使用键就会产生意料之外的效果.

使用对象作为键是 `Map` 最值得注意和重要的功能之一。对于字符串键,`Object`(普通对象)能正常使用,但对于对象键则不能。
我们来尝试一下:

```js run
Expand Down Expand Up @@ -100,9 +100,9 @@ map.set('1', 'str1')

如果要在 `map` 里使用循环, 可以使用以下三个方法:

- `map.keys()` -- returns an iterable for keys,
- `map.values()` -- returns an iterable for values,
- `map.entries()` -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`.
- `map.keys()` - 返回键名的遍历器,
- `map.values()` - 返回键值的遍历器,
- `map.entries()` - 返回实体 `[key, value]` 的遍历器,默认在 `for..of` 中使用。

例如:

Expand All @@ -113,7 +113,7 @@ let recipeMap = new Map([
['onion', 50]
]);

// 迭代键(vegetables)
// 迭代键vegetables
for (let vegetable of recipeMap.keys()) {
alert(vegetable); // cucumber, tomatoes, onion
}
Expand All @@ -131,7 +131,7 @@ for (let entry of recipeMap) { // 效果跟 recipeMap.entries() 相同

```smart header="按顺序插入"

迭代的顺序与插入键的顺序相同。 `Map`会保持相同的顺序,不像普通 `Object` 不保证顺序.
迭代的顺序与插入键的顺序相同。 `Map` 会保持相同的顺序,不像普通 `Object` 不保证顺序.
```

除此之外, `Map` 有个内建 `forEach` 方法, 跟 `Array` 一样:
Expand All @@ -158,7 +158,7 @@ let map = new Map([
alert( map.get('1') ); // str1
```

如果我们有个纯对象, 并且想利用这个纯对象来创建 `Map` , 可以使用内建方法[Object.entries(obj)](mdn:js/Object/entries) ,它返回一个具有相同格式的并且带有键值对的数组对象。
如果我们有个纯对象, 并且想利用这个纯对象来创建 `Map`, 可以使用内建方法 [Object.entries(obj)](mdn:js/Object/entries),它返回一个具有相同格式的并且带有键值对的数组对象。

所以可以像下面这样利用一个对象来创建 `map`

Expand All @@ -175,14 +175,14 @@ let map = new Map(Object.entries(obj));
alert( map.get('name') ); // John
```

这里, `Object.entries` 返回一个含有键值对的数组: `[ ["name","John"], ["age", 30] ]`. 这就是 `Map` 所需要的参数格式.
这里`Object.entries` 返回一个含有键值对的数组`[ ["name","John"], ["age", 30] ]`这就是 `Map` 所需要的参数格式


## Object.fromEntries: 把 `map` 转化为对象
## Object.fromEntries把 `map` 转化为对象

我们刚刚已经利用 `Object.entries(obj)` 把一个纯对象转化成 `Map`

`Object.fromEntries` 方法的作用是相反的: 给定一个具有 `[key, value]` 对的数组, 它会根据给定数组转化为 `Map`:
`Object.fromEntries` 方法的作用是相反的: 给定一个具有 `[key, value]` 对的数组, 它会根据给定数组生成对象:

```js run
let prices = Object.fromEntries([
Expand All @@ -191,7 +191,7 @@ let prices = Object.fromEntries([
['meat', 4]
]);

// now prices = { banana: 1, orange: 2, meat: 4 }
// 现在 prices = { banana: 1, orange: 2, meat: 4 }

alert(prices.orange); // 2
```
Expand Down Expand Up @@ -234,12 +234,12 @@ let obj = Object.fromEntries(map); // omit .entries()

它的主要方法如下:

- `new Set(iterable)` -- 创建一个 `set`, 如果提供一个 `iterable` 对象 (通常是数组), 将会从数组里面复制值到 `set` 里面去。
- `set.add(value)` -- 添加一个值,返回 set 本身
- `set.delete(value)` -- 删除值, 如果 `value` 在调用的时候值存在则返回 `true` ,否则返回 `false`。
- `set.has(value)` -- 如果 `value`存在 set 里面则返回 `true`, 否则返回 `false`。
- `set.clear()` -- 移除 set 里面的所有成员。
- `set.size` -- 返回元素数量。
- `new Set(iterable)` - 创建一个 `set`, 如果提供一个 `iterable` 对象通常是数组),将会从数组里面复制值到 `set` 里面去。
- `set.add(value)` - 添加一个值,返回 set 本身
- `set.delete(value)` - 删除值, 如果 `value` 在调用的时候值存在则返回 `true` ,否则返回 `false`。
- `set.has(value)` - 如果 `value` 存在 set 里面则返回 `true`, 否则返回 `false`。
- `set.clear()` - 移除 set 里面的所有成员。
- `set.size` - 返回元素数量。

它的主要特点是重复使用同一个值调用 `set.add(value)` 并不会发生什么改变。 这就是 `Set` 里面的每一个值只出现一次的原因。

Expand Down Expand Up @@ -269,11 +269,11 @@ for (let user of set) {
}
```

使用 `Set` 的场景可以是一个用户数组, 并且每次插入的时候检查重复的的代码也可以使用 [arr.find](mdn:js/Array/find). 但是这样会是性能变的更差,因为这个方法会遍历整个数组来检查每个元素。 `Set` 有更好的内部优化 - 独一无二的检查.
使用 `Set` 的场景可以是一个用户数组, 并且每次插入的时候检查重复的的代码也可以使用 [arr.find](mdn:js/Array/find)但是这样会是性能变的更差,因为这个方法会遍历整个数组来检查每个元素。 `Set` 有更好的内部优化 - 独一无二的检查.

## Set 迭代

我们可以在 `Set` 中使用 `for..of`和 `forEach` 它们两者之一来循环 :
我们可以在 `Set` 中使用 `for..of`和 `forEach` 它们两者之一来循环 :

```js run
let set = new Set(["oranges", "apples", "bananas"]);
Expand All @@ -286,43 +286,43 @@ set.forEach((value, valueAgain, set) => {
});
```

注意到一件有趣的事情. `forEach` 的回调函数有三个参数: 一个 `value`, 然后是 *相同值* `valueAgain`, 最后才是目标对象本身, 的确,相同的值在参数里出现了两次
注意到一件有趣的事情`forEach` 的回调函数有三个参数一个 `value`然后是 *相同值* `valueAgain`最后才是目标对象本身,的确,相同的值在参数里出现了两次

那是为了兼容 `Map` 在回调里传入 `forEach` 函数后有三个参数。 当然这看起来有点奇怪。但是这对在特定情况下比如使用 `Set`代替 `Map`的时候有帮助,反之亦然。
那是为了兼容 `Map` 在回调里传入 `forEach` 函数后有三个参数。 当然这看起来有点奇怪。但是这对在特定情况下比如使用 `Set` 代替 `Map`的时候有帮助,反之亦然。

类似于 `Map`,在 `Set`里用于迭代的方法也被支持:
- `set.keys()` -- 返回一个包含值的可迭代对象,
- `set.values()` -- 跟 `set.keys()` 作用相同, 为了兼容 `Map`,
- `set.entries()` -- 返回一个包含 `[value, value]` 对的可迭代对象 , 它的存在也是为了兼容 `Map`.
- `set.keys()` - 返回一个包含值的可迭代对象,
- `set.values()` - 跟 `set.keys()` 作用相同, 为了兼容 `Map`,
- `set.entries()` - 返回一个包含 `[value, value]` 对的可迭代对象 , 它的存在也是为了兼容 `Map`.

## 总结

`Map` -- 是一个键值集合.
`Map` - 是一个键值集合.

方法和属性如下:

- `new Map([iterable])` -- 创建空的 map, 可选的带有 `[key,value]` 对的`iterable` (例如数组) 对象来进行初始化 。
- `map.set(key, value)` -- 存储对应的键值。
- `map.get(key)` -- 根据键来返回值, 如果键不存在 map 里就返回 `undefined`。
- `map.has(key)` -- 如果 `key` 存在则返回 `true` , 否则返回`false`。
- `map.delete(key)` -- 删除指定键值。
- `map.clear()` -- 清空 map 。
- `map.size` -- 返回当前全部元素的数量。
- `new Map([iterable])` - 创建空的 map, 可选的带有 `[key,value]` 对的`iterable` (例如数组) 对象来进行初始化 。
- `map.set(key, value)` - 存储对应的键值。
- `map.get(key)` - 根据键来返回值, 如果键不存在 map 里就返回 `undefined`。
- `map.has(key)` - 如果 `key` 存在则返回 `true` , 否则返回 `false`。
- `map.delete(key)` - 删除指定键值。
- `map.clear()` - 清空 map 。
- `map.size` - 返回当前全部元素的数量。

跟普通对象 `Object` 最大的不同点是:

- 任何键,对象都可以被用作它的键,
- 有额外的方法, 和 `size` 属性。

`Set` -- 是一个独一无二的值的集合.
`Set` - 是一个独一无二的值的集合.

方法和属性:

- `new Set([iterable])` -- 创建空的 set , 可选的带有 `iterable` (例如数组) 对象来进行初始化。
- `set.add(value)` -- 添加一个 value(如果存在则什么也不做), 返回 set 本身。
- `set.delete(value)` -- 删除 value , 如果在调用的时候存在则返回 `true`, 否则返回 `false`。
- `set.has(value)` -- 如果则返回 `true`, 否则返回 `false`。
- `set.clear()` -- 清空 set。
- `set.size` -- 返回当前全部元素的数量。
- `new Set([iterable])` - 创建空的 set , 可选的带有 `iterable` (例如数组) 对象来进行初始化。
- `set.add(value)` - 添加一个 value(如果存在则什么也不做), 返回 set 本身。
- `set.delete(value)` - 删除 value , 如果在调用的时候存在则返回 `true`, 否则返回 `false`。
- `set.has(value)` - 如果则返回 `true`, 否则返回 `false`。
- `set.clear()` - 清空 set。
- `set.size` - 返回当前全部元素的数量。

在 `Map` 和 `Set` 里迭代总是按照插入的顺序来执行的,所以我们不能说这些集合是无序的,也不可以通过它的数量来记录元素或者直接获取一个元素
在 `Map` 和 `Set` 里迭代总是按照插入的顺序来执行的,所以我们不能说这些集合是无序的,但是我们不能对元素进行重新排序,也不能直接按其顺序来获取元素
8 changes: 4 additions & 4 deletions 1-js/05-data-types/08-weakmap-weakset/article.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# WeakMap and WeakSet(弱映射和弱集合)

我们从前面的[垃圾回收](<info:garbage-collection>)章节中知道,JavaScript 引擎在内存充足的情况下(或者可能被使用完)存储一个值
我们从前面的[垃圾回收](<info:garbage-collection>)章节中知道, JavaScript 引擎在值可访问(并可能被使用)时将其存储在内存中。

例如:
```js
Expand Down Expand Up @@ -74,7 +74,7 @@ weakMap.set("test", "Whoops"); // 错误, 因为 "test" 不是一个对象
*/!*
```

现在, 如果我们在 weakMap 里使用对象作为键,并且当这个对象没有其它引用 -- 该对象将会从内存中被自动清除 ( map 也类似)
现在, 如果我们在 weakMap 里使用对象作为键,并且当这个对象没有其它引用 -- 该对象将会从内存(和map)中被自动清除

```js
let john = { name: "John" };
Expand All @@ -89,7 +89,7 @@ john = null; // 覆盖引用

与上面的常规 `Map` 例子比起来。 现在如果 `john` 仅仅是作为 `WeakMap` 的键而存在时 -- 它将会从 map (从内存中)自动删除。

`WeakMap` 不支持迭代和`keys()`, `values()`, `entries()`方法, 所以没法从它里面获取键或者值
`WeakMap` 不支持迭代和`keys()`, `values()`, `entries()`方法, 所以没法从它里面获取所有键或值

`WeakMap` 只有以下方法:

Expand Down Expand Up @@ -273,7 +273,7 @@ john = null;
// visitedSet 将被自动清理
```

`WeakMap` 和 `WeakSet` 最出名的限制是不能迭代,获取多有的当前内容。那样可能会造成不便,但是依旧不能阻止 `WeakMap/WeakSet` 做很重要的事情 -- 成为在其它地方管理或者存储的对象 “额外的” 存储数据
`WeakMap` 和 `WeakSet` 最出名的限制是不能迭代,并且无法获取所有当前内容。那样可能会造成不便,但是依旧不能阻止 `WeakMap/WeakSet` 完成其主要工作 -- 成为在其它地方管理或者存储的对象的 “额外的” 数据存储

## 总结

Expand Down