chore(learn): Applied MDX format to Chinese curriculum files (#40462)

This commit is contained in:
Randell Dawson
2020-12-16 00:37:30 -07:00
committed by GitHub
parent 873fce02a2
commit 9ce4a02a41
1665 changed files with 58741 additions and 88042 deletions

View File

@ -1,14 +1,16 @@
---
id: 587d7b87367417b2b2512b40
title: 比较 var 和 let 关键字的作用域
challengeType: 1
forumTopicId: 301195
title: 比较 var 和 let 关键字的作用域
---
## Description
<section id='description'>
当你使用<code>var</code>关键字来声明一个变量的时候,这个变量会被声明成全局变量,或是函数内的局部变量。
<code>let</code>关键字的作用类似,但会有一些额外的特性。如果你在代码块、语句或表达式中使用关键字<code>let</code>声明变量,这个变量的作用域就被限制在当前的代码块,语句或表达式之中。
# --description--
当你使用`var`关键字来声明一个变量的时候,这个变量会被声明成全局变量,或是函数内的局部变量。
`let`关键字的作用类似,但会有一些额外的特性。如果你在代码块、语句或表达式中使用关键字`let`声明变量,这个变量的作用域就被限制在当前的代码块,语句或表达式之中。
举个例子:
```js
@ -22,7 +24,7 @@ console.log(i);
// 返回 3
```
当使用<code>var</code>关键字的时候,<code>i</code>会被声明成全局变量。当<code>i++</code>执行的时候,它会改变全局变量的值。这段代码可以看做下面这样:
当使用`var`关键字的时候,`i`会被声明成全局变量。当`i++`执行的时候,它会改变全局变量的值。这段代码可以看做下面这样:
```js
var numArray = [];
@ -36,7 +38,7 @@ console.log(i);
// 返回 3
```
如果你在<code>for</code>循环中创建了使用<code>i</code>变量的函数,那么在后续调用函数的时候,上面提到的这种行为就会出现问题。这是因为函数存储的值会因为全局变量<code>i</code>的变化而不断的改变。
如果你在`for`循环中创建了使用`i`变量的函数,那么在后续调用函数的时候,上面提到的这种行为就会出现问题。这是因为函数存储的值会因为全局变量`i`的变化而不断的改变。
```js
var printNumTwo;
@ -51,7 +53,7 @@ console.log(printNumTwo());
// 返回 3
```
可以看到,<code>printNumTwo()</code>打印了 3 而不是 2。这是因为<code>i</code>发生了改变,并且函数<code>printNumTwo()</code>返回的是全局变量<code>i</code>的值,而不是<code>for</code>循环中创建函数时<code>i</code>的值。<code>let</code>关键字就不会有这种现象:
可以看到,`printNumTwo()`打印了 3 而不是 2。这是因为`i`发生了改变,并且函数`printNumTwo()`返回的是全局变量`i`的值,而不是`for`循环中创建函数时`i`的值。`let`关键字就不会有这种现象:
```js
'use strict';
@ -69,70 +71,36 @@ console.log(i);
// 返回 "i 未定义"
```
<code>i</code>在全局作用域中没有声明,所以它没有被定义,它的声明只会发生在<code>for</code>循环内。在循环执行的时候,<code>let</code>关键字创建了三个不同的<code>i</code>变量,他们的值分别为 0、1 和 2所以<code>printNumTwo()</code>返回了正确的值。
</section>
`i`在全局作用域中没有声明,所以它没有被定义,它的声明只会发生在`for`循环内。在循环执行的时候,`let`关键字创建了三个不同的`i`变量,他们的值分别为 0、1 和 2所以`printNumTwo()`返回了正确的值。
## Instructions
<section id='instructions'>
修改这段代码,使得在<code>if</code>语句中声明的<code>i</code>变量与在函数的第一行声明的<code>i</code>变量是彼此独立的。请注意不要在你的代码的任何地方使用<code>var</code>关键字。
这个练习说明了使用<code>var</code><code>let</code>关键字声明变量时,作用域之间的不同。当编写类似这个练习中的函数的时候,通常来说最好还是使用不同的变量名来避免误会。
</section>
# --instructions--
## Tests
<section id='tests'>
修改这段代码,使得在`if`语句中声明的`i`变量与在函数的第一行声明的`i`变量是彼此独立的。请注意不要在你的代码的任何地方使用`var`关键字。
```yml
tests:
- text: <code>var</code>不应该在代码中存在。
testString: getUserInput => assert(!getUserInput('index').match(/var/g));
- text: "在<code>if</code>语句中声明的<code>i</code>变量的值是 'block scope'。"
testString: getUserInput => assert(getUserInput('index').match(/(i\s*=\s*).*\s*.*\s*.*\1('|")block\s*scope\2/g));
- text: "<code>checkScope()</code>应当返回 'function scope'"
testString: assert(checkScope() === "function scope");
这个练习说明了使用`var``let`关键字声明变量时,作用域之间的不同。当编写类似这个练习中的函数的时候,通常来说最好还是使用不同的变量名来避免误会。
```
# --hints--
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`var`不应该在代码中存在。
```js
function checkScope() {
'use strict';
var i = 'function scope';
if (true) {
i = 'block scope';
console.log('Block scope i is: ', i);
}
console.log('Function scope i is: ', i);
return i;
}
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
</div>
</section>
## Solution
<section id='solution'>
`if`语句中声明的`i`变量的值是 'block scope'。
```js
function checkScope() {
'use strict';
let i = 'function scope';
if (true) {
let i = 'block scope';
console.log('Block scope i is: ', i);
}
console.log('Function scope i is: ', i);
return i;
}
(getUserInput) =>
assert(
getUserInput('index').match(/(i\s*=\s*).*\s*.*\s*.*\1('|")block\s*scope\2/g)
);
```
</section>
`checkScope()`应当返回 'function scope'
```js
assert(checkScope() === 'function scope');
```
# --solutions--

View File

@ -1,13 +1,13 @@
---
id: 5cdafbc32913098997531680
title: 通过 resolve 和 reject 完成 Promise
challengeType: 1
forumTopicId: 301196
title: 通过 resolve 和 reject 完成 Promise
---
## Description
<section id='description'>
promise 有三个状态:<code>pending</code><code>fulfilled</code><code>rejected</code>。上一个挑战里创建的 promise 一直阻塞在 <code>pending</code> 状态里,因为没有调用 promise 的完成方法。promise 提供的 <code>resolve</code><code>reject</code> 参数就是用来结束 promise 的。promise 成功时调用 <code>resolve</code>promise 执行失败时调用 <code>reject</code>,这两个方法接收一个参数,如下所示。
# --description--
promise 有三个状态:`pending``fulfilled``rejected`。上一个挑战里创建的 promise 一直阻塞在 `pending` 状态里,因为没有调用 promise 的完成方法。promise 提供的 `resolve``reject` 参数就是用来结束 promise 的。promise 成功时调用 `resolve`promise 执行失败时调用 `reject`,这两个方法接收一个参数,如下所示。
```js
const myPromise = new Promise((resolve, reject) => {
@ -20,69 +20,32 @@ const myPromise = new Promise((resolve, reject) => {
```
上面的例子使用字符串做为函数的参数,也可以是任意类型,通常会是对象,里面可能是将要放到页面或其它地方的数据。
</section>
## Instructions
<section id='instructions'>
使 promise 可以处理成功和失败情况。如果 <code>responseFromServer</code><code>true</code>,调用 <code>resolve</code> 方法使 promise 成功。给 <code>resolve</code> 传递值为 <code>We got the data</code> 的字符串。如果 <code>responseFromServer</code><code>false</code> 使用 <code>reject</code> 方法并传入值为 <code>Data not received</code> 的字符串。
</section>
# --instructions--
## Tests
<section id='tests'>
使 promise 可以处理成功和失败情况。如果 `responseFromServer``true`,调用 `resolve` 方法使 promise 成功。给 `resolve` 传递值为 `We got the data` 的字符串。如果 `responseFromServer``false` 使用 `reject` 方法并传入值为 `Data not received` 的字符串。
```yml
tests:
- text: 当 <code>if</code> 条件是 <code>true</code> 时应该执行 <code>resolve</code>。
testString: assert(removeJSComments(code).match(/if\s*\(\s*responseFromServer\s*\)\s*{\s*resolve\s*\(\s*('|"|`)We got the data\1\s*\)(\s*|\s*;\s*)}/g));
- text: 当 <code>if</code> 条件是 <code>false</code> 时应该执行 <code>reject</code>。
testString: assert(removeJSComments(code).match(/}\s*else\s*{\s*reject\s*\(\s*('|"|`)Data not received\1\s*\)(\s*|\s*;\s*)}/g));
```
# --hints--
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`if` 条件是 `true` 时应该执行 `resolve`
```js
const makeServerRequest = new Promise((resolve, reject) => {
// responseFromServer represents a response from a server
let responseFromServer;
if(responseFromServer) {
// change this line
} else {
// change this line
}
});
assert(
removeJSComments(code).match(
/if\s*\(\s*responseFromServer\s*\)\s*{\s*resolve\s*\(\s*('|"|`)We got the data\1\s*\)(\s*|\s*;\s*)}/g
)
);
```
</div>
### After Test
<div id='js-teardown'>
`if` 条件是 `false` 时应该执行 `reject`
```js
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
assert(
removeJSComments(code).match(
/}\s*else\s*{\s*reject\s*\(\s*('|"|`)Data not received\1\s*\)(\s*|\s*;\s*)}/g
)
);
```
</div>
</section>
# --solutions--
## Solution
<section id='solution'>
```js
const makeServerRequest = new Promise((resolve, reject) => {
// responseFromServer represents a response from a server
let responseFromServer;
if(responseFromServer) {
resolve("We got the data");
} else {
reject("Data not received");
}
});
```
</section>

View File

@ -1,13 +1,13 @@
---
id: 5cdafbb0291309899753167f
title: 创建一个 JavaScript Promise
challengeType: 1
forumTopicId: 301197
title: 创建一个 JavaScript Promise
---
## Description
<section id='description'>
Promise 是异步编程的一种解决方案 - 它在未来的某时会生成一个值。任务完成,分执行成功和执行失败两种情况。<code>Promise</code> 是构造器函数,需要通过 <code>new</code> 关键字来创建。构造器参数是一个函数,该函数有两个参数 - <code>resolve</code><code>reject</code>。通过它们来判断 promise 的执行结果。用法如下:
# --description--
Promise 是异步编程的一种解决方案 - 它在未来的某时会生成一个值。任务完成,分执行成功和执行失败两种情况。`Promise` 是构造器函数,需要通过 `new` 关键字来创建。构造器参数是一个函数,该函数有两个参数 - `resolve``reject`。通过它们来判断 promise 的执行结果。用法如下:
```js
const myPromise = new Promise((resolve, reject) => {
@ -15,44 +15,27 @@ const myPromise = new Promise((resolve, reject) => {
});
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
创建一个名为 <code>makeServerRequest</code> 的 promise。给构造器函数传入 <code>resolve</code><code>reject</code> 两个参数。
</section>
创建一个名为 `makeServerRequest` 的 promise。给构造器函数传入 `resolve``reject` 两个参数。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 应该给名为 <code>makeServerRequest</code> 的变量指定一个 promise。
testString: assert(makeServerRequest instanceof Promise);
- text: promise 应该接收一个函数做为参数,该函数应该包含 <code>resolve</code> 和 <code>reject</code> 两个参数。
testString: assert(code.match(/Promise\(\s*(function\s*\(\s*resolve\s*,\s*reject\s*\)\s*{|\(\s*resolve\s*,\s*reject\s*\)\s*=>\s*{)[^}]*}/g));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
应该给名为 `makeServerRequest` 的变量指定一个 promise。
```js
assert(makeServerRequest instanceof Promise);
```
</div>
</section>
## Solution
<section id='solution'>
promise 应该接收一个函数做为参数,该函数应该包含 `resolve``reject` 两个参数。
```js
const makeServerRequest = new Promise((resolve, reject) => {
});
assert(
code.match(
/Promise\(\s*(function\s*\(\s*resolve\s*,\s*reject\s*\)\s*{|\(\s*resolve\s*,\s*reject\s*\)\s*=>\s*{)[^}]*}/g
)
);
```
</section>
# --solutions--

View File

@ -1,69 +1,51 @@
---
id: 5cddbfd622f1a59093ec611d
title: 创建一个模块脚本
challengeType: 6
forumTopicId: 301198
title: 创建一个模块脚本
---
## Description
<section id='description'>
起初JavaScript 几乎只在 HTML web 扮演一个很小的角色。今天,一切不同了,很多网站几乎全是用 JavaScript 所写。为了让 JavaScript 更模块化、更整洁以及更易于维护ES6 引入了在多个 JavaScript 文件之间共享代码的机制。它可以导出文件的一部分供其它文件使用,然后在需要它的地方按需导入。为了使用这一功能, 需要在 HTML 文档里创建一个类型为 <code>module</code> 的脚本。例子如下:
# --description--
起初JavaScript 几乎只在 HTML web 扮演一个很小的角色。今天,一切不同了,很多网站几乎全是用 JavaScript 所写。为了让 JavaScript 更模块化、更整洁以及更易于维护ES6 引入了在多个 JavaScript 文件之间共享代码的机制。它可以导出文件的一部分供其它文件使用,然后在需要它的地方按需导入。为了使用这一功能, 需要在 HTML 文档里创建一个类型为 `module` 的脚本。例子如下:
```html
<script type="module" src="filename.js"></script>
```
使用了 <code>module</code> 类型的脚本后可以再接下来的挑战里使用 <code>import</code><code>export</code> 特性。
</section>
使用了 `module` 类型的脚本后可以再接下来的挑战里使用 `import``export` 特性。
## Instructions
<section id='instructions'>
给 HTML 文档添加 <code>module</code> 类型的脚本,指定源文件为 <code>index.js</code>
</section>
# --instructions--
## Tests
<section id='tests'>
给 HTML 文档添加 `module` 类型的脚本,指定源文件为 `index.js`
```yml
tests:
- text: 应该创建一个 <code>script</code> 标签。
testString: assert(code.match(/<\s*script[^>]*>\s*<\/\s*script\s*>/g));
- text: <code>script</code> 标签的类型应该为 <code>module</code>。
testString: assert(code.match(/<\s*script\s+[^t]*type\s*=\s*('|")module\1[^>]*>\s*<\/\s*script\s*>/g));
- text: <code>script</code> 标签的 <code>src</code> 属性应该为 <code>index.js</code>。
testString: assert(code.match(/<\s*script\s+[^s]*src\s*=\s*('|")index\.js\1[^>]*>\s*<\/\s*script\s*>/g));
# --hints--
应该创建一个 `script` 标签。
```js
assert(code.match(/<\s*script[^>]*>\s*<\/\s*script\s*>/g));
```
</section>
`script` 标签的类型应该为 `module`
## Challenge Seed
<section id='challengeSeed'>
<div id='html-seed'>
```html
<html>
<body>
<!-- add your code below -->
<!-- add your code above -->
</body>
</html>
```js
assert(
code.match(
/<\s*script\s+[^t]*type\s*=\s*('|")module\1[^>]*>\s*<\/\s*script\s*>/g
)
);
```
</div>
</section>
`script` 标签的 `src` 属性应该为 `index.js`
## Solution
<section id='solution'>
```html
<html>
<body>
<!-- add your code below -->
<script type="module" src="index.js"></script>
<!-- add your code above -->
</body>
</html>
```js
assert(
code.match(
/<\s*script\s+[^s]*src\s*=\s*('|")index\.js\1[^>]*>\s*<\/\s*script\s*>/g
)
);
```
</section>
# --solutions--

View File

@ -1,15 +1,17 @@
---
id: 587d7b8c367417b2b2512b58
title: 用 export default 创建一个默认导出
challengeType: 1
forumTopicId: 301199
title: 用 export default 创建一个默认导出
---
## Description
<section id='description'>
<code>export</code>的课程中,学习了<dfn>命名导出</dfn>语法。这可以在其他文件中引用一些函数或者变量。
还需要了解另外一种被称为<dfn>默认导出</dfn><code>export</code>的语法。在文件中只有一个值需要导出的时候,通常会使用这种语法。它也常常用于给文件或者模块创建返回值。
下面是一个简单的<code>export default</code>例子:
# --description--
`export`的课程中,学习了<dfn>命名导出</dfn>语法。这可以在其他文件中引用一些函数或者变量。
还需要了解另外一种被称为<dfn>默认导出</dfn>`export`的语法。在文件中只有一个值需要导出的时候,通常会使用这种语法。它也常常用于给文件或者模块创建返回值。
下面是一个简单的`export default`例子:
```js
// named function
@ -23,45 +25,23 @@ export default function(x, y) {
}
```
注意:当使用<code>export default</code>去声明一个文件或者模块的返回值时,在每个文件或者模块中应当只默认导出一个值。特别地,能将<code>export deafult</code><code>var</code><code>let</code><code>const</code>一起使用。
</section>
注意:当使用`export default`去声明一个文件或者模块的返回值时,在每个文件或者模块中应当只默认导出一个值。特别地,能将`export deafult``var``let``const`一起使用。
# --instructions--
## Instructions
<section id='instructions'>
下面的函数应该在这个模块中返回一个值。请添加需要的代码:
</section>
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 正确的使用<code>export</code>进行返回。
testString: assert(code.match(/export\s+default\s+function(\s+subtract\s*|\s*)\(\s*x,\s*y\s*\)\s*{/g));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
正确的使用`export`进行返回。
```js
function subtract(x, y) {
return x - y;
}
assert(
code.match(
/export\s+default\s+function(\s+subtract\s*|\s*)\(\s*x,\s*y\s*\)\s*{/g
)
);
```
</div>
</section>
# --solutions--
## Solution
<section id='solution'>
```js
export default function subtract(x, y) {
return x - y;
}
```
</section>

View File

@ -1,14 +1,16 @@
---
id: 587d7b8a367417b2b2512b4e
title: 使用模板字面量创建字符串
challengeType: 1
forumTopicId: 301200
title: 使用模板字面量创建字符串
---
## Description
<section id='description'>
# --description--
模板字符串是 ES6 的另外一项新的功能。这是一种可以轻松构建复杂字符串的方法。
模板字符串可以使用多行字符串和字符串插值功能。
请看以下代码:
```js
@ -27,94 +29,49 @@ console.log(greeting); // prints
```
这段代码有许多的不同:
首先,上面的例子使用了反引号(<code>`</code>)而不是引号(<code>'</code> 或者 <code>"</code>)定义字符串。
其次,注意字符串是多行的,不管是代码还是输出。这是因为在字符串内插入了 <code>\n</code>。
上面使用的<code>${variable}</code>语法是一个占位符。这样一来,你将不再需要使用<code>+</code>运算符来连接字符串。当需要在字符串里增加变量的时候,你只需要在变量的外面括上<code>${</code>和<code>}</code>,并将其放在字符串里就可以了。
这个新的方式使你可以更灵活的创建复杂的字符串
</section>
这段代码有许多的不同: 首先,上面的例子使用了反引号(`` ` ``)而不是引号(`'` 或者 `"`)定义字符串。 其次,注意字符串是多行的,不管是代码还是输出。这是因为在字符串内插入了 `\n`。 上面使用的`${variable}`语法是一个占位符。这样一来,你将不再需要使用`+`运算符来连接字符串。当需要在字符串里增加变量的时候,你只需要在变量的外面括上`${`和`}`,并将其放在字符串里就可以了。 这个新的方式使你可以更灵活的创建复杂的字符串。
# --instructions--
使用模板字符串的反引号的语法来展示`result`对象的`failure`数组内的每个条目。每个条目应该括在带有`text-warning`类属性的`li`标签中,并赋值给`resultDisplayArray`
## Instructions
<section id='instructions'>
使用模板字符串的反引号的语法来展示<code>result</code>对象的<code>failure</code>数组内的每个条目。每个条目应该括在带有<code>text-warning</code>类属性的<code>li</code>标签中,并赋值给<code>resultDisplayArray</code>。
使用遍历方法(可以是任意形式的循环)输出指定值。
</section>
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: <code>resultDisplayArray</code> 是一个包含了 <code>result failure</code> 内的消息的数组。
testString: assert(typeof makeList(result.failure) === 'object' && resultDisplayArray.length === 3);
- text: <code>resultDisplayArray</code> 要有正确的输出。
testString: assert(makeList(result.failure).every((v, i) => v === `<li class="text-warning">${result.failure[i]}</li>` || v === `<li class='text-warning'>${result.failure[i]}</li>`));
- text: 应使用模板字符串。
testString: getUserInput => assert(getUserInput('index').match(/(`.*\${.*}.*`)/));
- text: 应该遍历。
testString: getUserInput => assert(getUserInput('index').match(/for|map|reduce|forEach|while/));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`resultDisplayArray` 是一个包含了 `result failure` 内的消息的数组。
```js
const result = {
success: ["max-length", "no-amd", "prefer-arrow-functions"],
failure: ["no-var", "var-on-top", "linebreak"],
skipped: ["no-extra-semi", "no-dup-keys"]
};
function makeList(arr) {
"use strict";
// change code below this line
const resultDisplayArray = null;
// change code above this line
return resultDisplayArray;
}
/**
* makeList(result.failure) should return:
* [ `<li class="text-warning">no-var</li>`,
* `<li class="text-warning">var-on-top</li>`,
* `<li class="text-warning">linebreak</li>` ]
**/
const resultDisplayArray = makeList(result.failure);
assert(
typeof makeList(result.failure) === 'object' &&
resultDisplayArray.length === 3
);
```
</div>
</section>
## Solution
<section id='solution'>
`resultDisplayArray` 要有正确的输出。
```js
const result = {
success: ["max-length", "no-amd", "prefer-arrow-functions"],
failure: ["no-var", "var-on-top", "linebreak"],
skipped: ["id-blacklist", "no-dup-keys"]
};
function makeList(arr) {
"use strict";
const resultDisplayArray = arr.map(val => `<li class="text-warning">${val}</li>`);
return resultDisplayArray;
}
/**
* makeList(result.failure) should return:
* [ `<li class="text-warning">no-var</li>`,
* `<li class="text-warning">var-on-top</li>`,
* `<li class="text-warning">linebreak</li>` ]
**/
const resultDisplayArray = makeList(result.failure);
assert(
makeList(result.failure).every(
(v, i) =>
v === `<li class="text-warning">${result.failure[i]}</li>` ||
v === `<li class='text-warning'>${result.failure[i]}</li>`
)
);
```
</section>
应使用模板字符串。
```js
(getUserInput) => assert(getUserInput('index').match(/(`.*\${.*}.*`)/));
```
应该遍历。
```js
(getUserInput) =>
assert(getUserInput('index').match(/for|map|reduce|forEach|while/));
```
# --solutions--

View File

@ -1,14 +1,15 @@
---
id: 587d7b87367417b2b2512b41
title: 用 const 关键字声明只读变量
challengeType: 1
forumTopicId: 301201
title: 用 const 关键字声明只读变量
---
## Description
<section id='description'>
<code>let</code>并不是唯一的新的声明变量的方式。在 ES6里面你还可以使用<code>const</code>关键字来声明变量。
<code>const</code>拥有<code>let</code>的所有优点,所不同的是,通过<code>const</code>声明的变量是只读的。这意味着通过<code>const</code>声明的变量只能被赋值一次,而不能被再次赋值。
# --description--
`let`并不是唯一的新的声明变量的方式。在 ES6里面你还可以使用`const`关键字来声明变量。
`const`拥有`let`的所有优点,所不同的是,通过`const`声明的变量是只读的。这意味着通过`const`声明的变量只能被赋值一次,而不能被再次赋值。
```js
"use strict";
@ -16,80 +17,40 @@ const FAV_PET = "Cats";
FAV_PET = "Dogs"; // returns error
```
可以看见,尝试给通过<code>const</code>声明的变量再次赋值会报错。你应该使用<code>const</code>关键字来对所有不打算再次赋值的变量进行声明。这有助于你避免给一个常量进行额外的再次赋值。一个最佳实践是对所有常量的命名采用全大写字母,并在单词之间使用下划线进行分隔。
可以看见,尝试给通过`const`声明的变量再次赋值会报错。你应该使用`const`关键字来对所有不打算再次赋值的变量进行声明。这有助于你避免给一个常量进行额外的再次赋值。一个最佳实践是对所有常量的命名采用全大写字母,并在单词之间使用下划线进行分隔。
<strong>注意:</strong> 一般开发者会以大写做为常量标识符,小写字母或者驼峰命名做为变量(对象或数组)标识符。接下来的挑战里会涉及到小写变量标识符的数组。
</section>
**注意:** 一般开发者会以大写做为常量标识符,小写字母或者驼峰命名做为变量(对象或数组)标识符。接下来的挑战里会涉及到小写变量标识符的数组。
## Instructions
<section id='instructions'>
改变以下代码,使得所有的变量都使用<code>let</code><code>const</code>关键词来声明。当变量将会改变的时候使用<code>let</code>关键字,当变量要保持常量的时候使用<code>const</code>关键字。同时,对使用<code>const</code>声明的变量按照最佳实践重命名,变量名中的字母应该都是大写的。
</section>
# --instructions--
## Tests
<section id='tests'>
改变以下代码,使得所有的变量都使用`let``const`关键词来声明。当变量将会改变的时候使用`let`关键字,当变量要保持常量的时候使用`const`关键字。同时,对使用`const`声明的变量按照最佳实践重命名,变量名中的字母应该都是大写的。
```yml
tests:
- text: <code>var</code>在代码中不存在。
testString: getUserInput => assert(!getUserInput('index').match(/var/g));
- text: <code>SENTENCE</code>应该是使用<code>const</code>声明的常量。
testString: getUserInput => assert(getUserInput('index').match(/(const SENTENCE)/g));
- text: <code>i</code>应该是使用<code>let</code>声明的变量。
testString: getUserInput => assert(getUserInput('index').match(/(let i)/g));
- text: <code>console.log</code>应该修改为用于打印<code>SENTENCE</code>变量。
testString: getUserInput => assert(getUserInput('index').match(/console\.log\(\s*SENTENCE\s*\)\s*;?/g));
# --hints--
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`var`在代码中不存在。
```js
function printManyTimes(str) {
"use strict";
// change code below this line
var sentence = str + " is cool!";
for (var i = 0; i < str.length; i+=2) {
console.log(sentence);
}
// change code above this line
}
printManyTimes("freeCodeCamp");
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
</div>
</section>
## Solution
<section id='solution'>
`SENTENCE`应该是使用`const`声明的常量。
```js
function printManyTimes(str) {
"use strict";
// change code below this line
const SENTENCE = str + " is cool!";
for (let i = 0; i < str.length; i+=2) {
console.log(SENTENCE);
}
// change code above this line
}
printManyTimes("freeCodeCamp");
(getUserInput) => assert(getUserInput('index').match(/(const SENTENCE)/g));
```
</section>
`i`应该是使用`let`声明的变量。
```js
(getUserInput) => assert(getUserInput('index').match(/(let i)/g));
```
`console.log`应该修改为用于打印`SENTENCE`变量。
```js
(getUserInput) =>
assert(getUserInput('index').match(/console\.log\(\s*SENTENCE\s*\)\s*;?/g));
```
# --solutions--

View File

@ -1,13 +1,13 @@
---
id: 587d7b87367417b2b2512b3f
title: 探索 var 和 let 关键字之间的差异
challengeType: 1
forumTopicId: 301202
title: 探索 var 和 let 关键字之间的差异
---
## Description
<section id='description'>
使用<code>var</code>关键字来声明变量,会出现重复声明导致变量被覆盖却不会报错的问题:
# --description--
使用`var`关键字来声明变量,会出现重复声明导致变量被覆盖却不会报错的问题:
```js
var camper = 'James';
@ -16,86 +16,44 @@ console.log(camper);
// logs 'David'
```
在上面的代码中,<code>camper</code>的初始值为<code>'James'</code>,然后又被覆盖成了<code>'David'</code>
小型的应用中,你可能不会遇到这样的问题,但是当你的代码规模变得更加庞大的时候,就可能会在不经意间覆盖了之前定义的变量
这样的行为不会报错,导致了 debug 非常困难。<br>
在 ES6 中引入了新的关键字<code>let</code>来解决<code>var</code>关键字带来的潜在问题。
如果你在上面的代码中,使用了<code>let</code>关键字来代替<code>var</code>关键字,结果会是一个报错。
在上面的代码中,`camper`的初始值为`'James'`,然后又被覆盖成了`'David'`。 在小型的应用中,你可能不会遇到这样的问题,但是当你的代码规模变得更加庞大的时候,就可能会在不经意间覆盖了之前定义的变量。 这样的行为不会报错,导致了 debug 非常困难。
ES6 中引入了新的关键字`let`来解决`var`关键字带来的潜在问题。 如果你在上面的代码中,使用了`let`关键字来代替`var`关键字,结果会是一个报错
```js
let camper = 'James';
let camper = 'David'; // throws an error
```
你可以在浏览器的控制台里看见这个错误。
<code>var</code>不同的是,当使用<code>let</code>的时候,同一名字的变量只能被声明一次。
请注意<code>"use strict"</code>。这代表着开启了严格模式,用于检测常见的代码错误以及"不安全"的行为,例如:
你可以在浏览器的控制台里看见这个错误。`var`不同的是,当使用`let`的时候,同一名字的变量只能被声明一次。 请注意`"use strict"`。这代表着开启了严格模式,用于检测常见的代码错误以及"不安全"的行为,例如:
```js
"use strict";
x = 3.14; // throws an error because x is not declared
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
请更新这段代码,并且在其中只使用<code>let</code>关键字
</section>
请更新这段代码,并且在其中只使用`let`关键字
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 在代码中不应存在<code>var</code>。
testString: getUserInput => assert(!getUserInput('index').match(/var/g));
- text: "<code>catName</code>变量的值应该为<code>'Oliver'</code>。"
testString: assert(catName === "Oliver");
- text: "<code>quote</code>变量的值应该为<code>'Oliver says Meow!'</code>"
testString: assert(quote === "Oliver says Meow!");
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
在代码中不应存在`var`
```js
var catName;
var quote;
function catTalk() {
"use strict";
catName = "Oliver";
quote = catName + " says Meow!";
}
catTalk();
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
</div>
</section>
## Solution
<section id='solution'>
`catName`变量的值应该为`'Oliver'`
```js
let catName;
let quote;
function catTalk() {
'use strict';
catName = 'Oliver';
quote = catName + ' says Meow!';
}
catTalk();
assert(catName === 'Oliver');
```
</section>
`quote`变量的值应该为`'Oliver says Meow!'`
```js
assert(quote === 'Oliver says Meow!');
```
# --solutions--

View File

@ -1,13 +1,13 @@
---
id: 5cdafbd72913098997531681
title: 在 then 中处理 Promise 完成的情况
challengeType: 1
forumTopicId: 301203
title: 在 then 中处理 Promise 完成的情况
---
## Description
<section id='description'>
当程序需要花费未知的时间才能完成时 Promise 很有用(比如,一些异步操作),一般是网络请求。网络请求会花费一些时间,当结束时需要根据服务器的响应执行一些操作。这可以用 <code>then</code> 方法来实现,当 promise 完成 <code>resolve</code> 时会触发 <code>then</code> 方法。例子如下:
# --description--
当程序需要花费未知的时间才能完成时 Promise 很有用(比如,一些异步操作),一般是网络请求。网络请求会花费一些时间,当结束时需要根据服务器的响应执行一些操作。这可以用 `then` 方法来实现,当 promise 完成 `resolve` 时会触发 `then` 方法。例子如下:
```js
myPromise.then(result => {
@ -15,77 +15,34 @@ myPromise.then(result => {
});
```
<code>result</code> 即传入 <code>resolve</code> 方法的参数。
</section>
`result` 即传入 `resolve` 方法的参数。
## Instructions
<section id='instructions'>
给 promise 添加 <code>then</code> 方法。用 <code>result</code> 做为回调函数的参数并将 <code>result</code> 打印在控制台。
</section>
# --instructions--
## Tests
<section id='tests'>
给 promise 添加 `then` 方法。用 `result` 做为回调函数的参数并将 `result` 打印在控制台。
```yml
tests:
- text: 应该给 promise 方法调用 <code>then</code> 方法。
testString: assert(codeWithoutSpaces.match(/(makeServerRequest|\))\.then\(/g));
- text: <code>then</code> 方法应该有一个回调函数,回调函数参数为 <code>result</code>。
testString: assert(resultIsParameter);
- text: 应该打印 <code>result</code> 到控制台。
testString: assert(resultIsParameter && codeWithoutSpaces.match(/\.then\(.*?result.*?console.log\(result\).*?\)/));
```
# --hints--
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
应该给 promise 方法调用 `then` 方法。
```js
const makeServerRequest = new Promise((resolve, reject) => {
// responseFromServer is set to true to represent a successful response from a server
let responseFromServer = true;
if(responseFromServer) {
resolve("We got the data");
} else {
reject("Data not received");
}
});
assert(codeWithoutSpaces.match(/(makeServerRequest|\))\.then\(/g));
```
</div>
### After Test
<div id='js-teardown'>
`then` 方法应该有一个回调函数,回调函数参数为 `result`
```js
const codeWithoutSpaces = code.replace(/\s/g, '');
const resultIsParameter = /\.then\((function\(result\){|result|\(result\)=>)/.test(codeWithoutSpaces);
assert(resultIsParameter);
```
</div>
</section>
## Solution
<section id='solution'>
应该打印 `result` 到控制台。
```js
const makeServerRequest = new Promise((resolve, reject) => {
// responseFromServer is set to true to represent a successful response from a server
let responseFromServer = true;
if(responseFromServer) {
resolve("We got the data");
} else {
reject("Data not received");
}
});
makeServerRequest.then(result => {
console.log(result);
});
assert(
resultIsParameter &&
codeWithoutSpaces.match(/\.then\(.*?result.*?console.log\(result\).*?\)/)
);
```
</section>
# --solutions--

View File

@ -1,13 +1,13 @@
---
id: 5cdafbe72913098997531682
title: 在 catch 中处理 Promise 失败的情况
challengeType: 1
forumTopicId: 301204
title: 在 catch 中处理 Promise 失败的情况
---
## Description
<section id='description'>
当 promise 失败时会调用 <code>catch</code> 方法。当 promise 的 <code>reject</code> 方法执行时会直接调用。用法如下:
# --description--
当 promise 失败时会调用 `catch` 方法。当 promise 的 `reject` 方法执行时会直接调用。用法如下:
```js
myPromise.catch(error => {
@ -15,88 +15,36 @@ myPromise.catch(error => {
});
```
<code>error</code> 是传入 <code>reject</code> 方法的参数。
`error` 是传入 `reject` 方法的参数。
<strong>注意:</strong> <code>then</code><code>catch</code> 方法可以在 promise 后面链式调用。
</section>
**注意:** `then``catch` 方法可以在 promise 后面链式调用。
## Instructions
<section id='instructions'>
给 promise 添加 <code>catch</code> 方法。用 <code>error</code> 做为回调函数的参数并把 <code>error</code> 打印到控制台。
</section>
# --instructions--
## Tests
<section id='tests'>
给 promise 添加 `catch` 方法。用 `error` 做为回调函数的参数并把 `error` 打印到控制台。
```yml
tests:
- text: 应该在 promise 上调用 <code>catch</code> 方法。
testString: assert(codeWithoutSpaces.match(/(makeServerRequest|\))\.catch\(/g));
- text: <code>catch</code> 方法应该有一个回调函数,函数参数为<code>error</code>。
testString: assert(errorIsParameter);
- text: 应该打印<code>error</code>到控制台。
testString: assert(errorIsParameter && codeWithoutSpaces.match(/\.catch\(.*?error.*?console.log\(error\).*?\)/));
```
# --hints--
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
应该在 promise 上调用 `catch` 方法。
```js
const makeServerRequest = new Promise((resolve, reject) => {
// responseFromServer is set to false to represent an unsuccessful response from a server
let responseFromServer = false;
if(responseFromServer) {
resolve("We got the data");
} else {
reject("Data not received");
}
});
makeServerRequest.then(result => {
console.log(result);
});
assert(codeWithoutSpaces.match(/(makeServerRequest|\))\.catch\(/g));
```
</div>
### After Test
<div id='js-teardown'>
`catch` 方法应该有一个回调函数,函数参数为`error`
```js
const codeWithoutSpaces = code.replace(/\s/g, '');
const errorIsParameter = /\.catch\((function\(error\){|error|\(error\)=>)/.test(codeWithoutSpaces);
assert(errorIsParameter);
```
</div>
</section>
## Solution
<section id='solution'>
应该打印`error`到控制台。
```js
const makeServerRequest = new Promise((resolve, reject) => {
// responseFromServer is set to false to represent an unsuccessful response from a server
let responseFromServer = false;
if(responseFromServer) {
resolve("We got the data");
} else {
reject("Data not received");
}
});
makeServerRequest.then(result => {
console.log(result);
});
makeServerRequest.catch(error => {
console.log(error);
});
assert(
errorIsParameter &&
codeWithoutSpaces.match(/\.catch\(.*?error.*?console.log\(error\).*?\)/)
);
```
</section>
# --solutions--

View File

@ -1,60 +1,33 @@
---
id: 587d7b8d367417b2b2512b59
title: 导入一个默认的导出
challengeType: 1
forumTopicId: 301205
title: 导入一个默认的导出
---
## Description
<section id='description'>
在上一个挑战里,学习了<code>export default</code>的用法。还需要一种<code>import</code>的语法来导入默认的导出。
在下面的例子里有一个<code>add</code>函数, 它在<code>"math_functions"</code>文件里默认被导出。来看看来如何导入它:
# --description--
在上一个挑战里,学习了`export default`的用法。还需要一种`import`的语法来导入默认的导出。
在下面的例子里有一个`add`函数, 它在`"math_functions"`文件里默认被导出。来看看来如何导入它:
```js
import add from "./math_functions.js";
```
这个语法只有一处不同的地方 —— 被导入的<code>add</code>值,并没有被花括号<code>{}</code>所包围。与导出值的方法不同,导入默认导出的写法仅仅只是简单的将变量名写在<code>import</code>之后。
</section>
这个语法只有一处不同的地方 —— 被导入的`add`值,并没有被花括号`{}`所包围。与导出值的方法不同,导入默认导出的写法仅仅只是简单的将变量名写在`import`之后。
## Instructions
<section id='instructions'>
在下面的代码中,请导入在同目录下的<code>"math_functions"</code>文件中默认导出的<code>subtract</code>值。
</section>
# --instructions--
## Tests
<section id='tests'>
在下面的代码中,请导入在同目录下的`"math_functions"`文件中默认导出的`subtract`值。
```yml
tests:
- text: 正确导入<code>export default</code>方法导出的值。
testString: assert(code.match(/import\s+subtract\s+from\s+('|")\.\/math_functions\.js\1/g));
```
# --hints--
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
正确导入`export default`方法导出的值。
```js
// add code above this line
subtract(7,4);
assert(code.match(/import\s+subtract\s+from\s+('|")\.\/math_functions\.js\1/g));
```
</div>
</section>
# --solutions--
## Solution
<section id='solution'>
```js
import subtract from "./math_functions.js";
// add code above this line
subtract(7,4);
```
</section>

View File

@ -1,15 +1,17 @@
---
id: 587d7b87367417b2b2512b42
title: 改变一个用 const 声明的数组
challengeType: 1
forumTopicId: 301206
title: 改变一个用 const 声明的数组
---
## Description
<section id='description'>
在现代的 JavaScript 里,<code>const</code>声明有很多用法。
一些开发者倾向默认使用<code>const</code>来声明所有变量,但如果它们打算在后续的代码中修改某个值,那在声明的时候就会用<code>let</code>
然而,你要注意,对象(包括数组和函数)在使用<code>const</code>声明的时候依然是可变的。使用<code>const</code>来声明只会保证它的标识不会被重新赋值
# --description--
在现代的 JavaScript 里,`const`声明有很多用法。
一些开发者倾向默认使用`const`来声明所有变量,但如果它们打算在后续的代码中修改某个值,那在声明的时候就会用`let`
然而,你要注意,对象(包括数组和函数)在使用`const`声明的时候依然是可变的。使用`const`来声明只会保证它的标识不会被重新赋值。
```js
"use strict";
@ -19,72 +21,42 @@ s[2] = 45; // works just as it would with an array declared with var or let
console.log(s); // returns [5, 6, 45]
```
从以上代码看出,你可以改变<code>[5, 6, 7]</code>自身,所以<code>s</code>变量指向了改变后的数组<code>[5, 6, 45]</code>。和所有数组一样,数组<code>s</code>中的数组元素是可以被改变的,但是因为使用了<code>const</code>关键字,你不能使用赋值操作符将变量标识<code>s</code>指向另外一个数组。
</section>
从以上代码看出,你可以改变`[5, 6, 7]`自身,所以`s`变量指向了改变后的数组`[5, 6, 45]`。和所有数组一样,数组`s`中的数组元素是可以被改变的,但是因为使用了`const`关键字,你不能使用赋值操作符将变量标识`s`指向另外一个数组。
## Instructions
<section id='instructions'>
这里有一个使用<code>const s = [5, 7, 2]</code>声明的数组。使用对各元素赋值的方法将数组改成<code>[2, 5, 7]</code>
</section>
# --instructions--
## Tests
<section id='tests'>
这里有一个使用`const s = [5, 7, 2]`声明的数组。使用对各元素赋值的方法将数组改成`[2, 5, 7]`
```yml
tests:
- text: 不要替换<code>const</code>关键字。
testString: getUserInput => assert(getUserInput('index').match(/const/g));
- text: <code>s</code>应该为常量 (通过使用<code>const</code>)。
testString: getUserInput => assert(getUserInput('index').match(/const\s+s/g));
- text: 不要改变原数组的声明。
testString: getUserInput => assert(getUserInput('index').match(/const\s+s\s*=\s*\[\s*5\s*,\s*7\s*,\s*2\s*\]\s*;?/g));
- text: <code>s</code>应该等于<code>[2, 5, 7]</code>。
testString: assert.deepEqual(s, [2, 5, 7]);
# --hints--
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
不要替换`const`关键字。
```js
const s = [5, 7, 2];
function editInPlace() {
'use strict';
// change code below this line
// s = [2, 5, 7]; <- this is invalid
// change code above this line
}
editInPlace();
(getUserInput) => assert(getUserInput('index').match(/const/g));
```
</div>
</section>
## Solution
<section id='solution'>
`s`应该为常量 (通过使用`const`)。
```js
const s = [5, 7, 2];
function editInPlace() {
'use strict';
// change code below this line
// s = [2, 5, 7]; <- this is invalid
s[0] = 2;
s[1] = 5;
s[2] = 7;
// change code above this line
}
editInPlace();
(getUserInput) => assert(getUserInput('index').match(/const\s+s/g));
```
</section>
不要改变原数组的声明。
```js
(getUserInput) =>
assert(
getUserInput('index').match(
/const\s+s\s*=\s*\[\s*5\s*,\s*7\s*,\s*2\s*\]\s*;?/g
)
);
```
`s`应该等于`[2, 5, 7]`
```js
assert.deepEqual(s, [2, 5, 7]);
```
# --solutions--

View File

@ -1,13 +1,14 @@
---
id: 598f48a36c8c40764b4e52b3
title: 防止对象改变
challengeType: 1
forumTopicId: 301207
title: 防止对象改变
---
## Description
<section id='description'>
通过之前的挑战可以看出,<code>const</code>声明并不会真的保护你的数据不被改变。为了确保数据不被改变JavaScript 提供了一个函数<code>Object.freeze</code>来防止数据改变。
# --description--
通过之前的挑战可以看出,`const`声明并不会真的保护你的数据不被改变。为了确保数据不被改变JavaScript 提供了一个函数`Object.freeze`来防止数据改变。
当一个对象被冻结的时候,你不能再对它的属性再进行增、删、改的操作。任何试图改变对象的操作都会被阻止,却不会报错。
```js
@ -22,83 +23,41 @@ console.log(obj);
// { name: "FreeCodeCamp", review:"Awesome"}
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
在这个挑战中,你将使用<code>Object.freeze</code>来防止数学常量被改变。你需要冻结<code>MATH_CONSTANTS</code>对象,使得没有人可以改变<code>PI</code>的值,抑或增加或删除属性。
</section>
在这个挑战中,你将使用`Object.freeze`来防止数学常量被改变。你需要冻结`MATH_CONSTANTS`对象,使得没有人可以改变`PI`的值,抑或增加或删除属性。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 不要替换<code>const</code>关键字。
testString: getUserInput => assert(getUserInput('index').match(/const/g));
- text: <code>MATH_CONSTANTS</code>应该为一个常量 (使用<code>const</code>)。
testString: getUserInput => assert(getUserInput('index').match(/const\s+MATH_CONSTANTS/g));
- text: 不要改变原始的<code>MATH_CONSTANTS</code>。
testString: getUserInput => assert(getUserInput('index').match(/const\s+MATH_CONSTANTS\s+=\s+{\s+PI:\s+3.14\s+};/g));
- text: <code>PI</code>等于<code>3.14</code>。
testString: assert(PI === 3.14);
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
不要替换`const`关键字。
```js
function freezeObj() {
'use strict';
const MATH_CONSTANTS = {
PI: 3.14
};
// change code below this line
// change code above this line
try {
MATH_CONSTANTS.PI = 99;
} catch(ex) {
console.log(ex);
}
return MATH_CONSTANTS.PI;
}
const PI = freezeObj();
(getUserInput) => assert(getUserInput('index').match(/const/g));
```
</div>
</section>
## Solution
<section id='solution'>
`MATH_CONSTANTS`应该为一个常量 (使用`const`)。
```js
function freezeObj() {
'use strict';
const MATH_CONSTANTS = {
PI: 3.14
};
// change code below this line
Object.freeze(MATH_CONSTANTS);
// change code above this line
try {
MATH_CONSTANTS.PI = 99;
} catch(ex) {
console.log(ex);
}
return MATH_CONSTANTS.PI;
}
const PI = freezeObj();
(getUserInput) =>
assert(getUserInput('index').match(/const\s+MATH_CONSTANTS/g));
```
</section>
不要改变原始的`MATH_CONSTANTS`
```js
(getUserInput) =>
assert(
getUserInput('index').match(
/const\s+MATH_CONSTANTS\s+=\s+{\s+PI:\s+3.14\s+};/g
)
);
```
`PI`等于`3.14`
```js
assert(PI === 3.14);
```
# --solutions--

View File

@ -1,19 +1,19 @@
---
id: 587d7b8c367417b2b2512b55
title: 通过 import 复用 JavaScript 代码
challengeType: 1
forumTopicId: 301208
title: 通过 import 复用 JavaScript 代码
---
## Description
<section id='description'>
<code>import</code> 可以导入文件或模块的一部分。在之前的课程里,例子从 <code>math_functions.js</code> 文件里导出了 <code>add</code>,下面看一下如何在其它的文件导入它:
# --description--
`import` 可以导入文件或模块的一部分。在之前的课程里,例子从 `math_functions.js` 文件里导出了 `add`,下面看一下如何在其它的文件导入它:
```js
import { add } from './math_functions.js';
```
在这里,<code>import</code> 会在 <code>math_functions.js</code> 里找到 <code>add</code>,只导入这个函数,忽略剩余的部分。<code>./</code> 告诉程序在当前文件的相同目录寻找 <code>math_functions.js</code> 文件。用这种方式导入时,相对路径(<code>./</code>)和文件扩展名(<code>.js</code>)都是必需的。
在这里,`import` 会在 `math_functions.js` 里找到 `add`,只导入这个函数,忽略剩余的部分。`./` 告诉程序在当前文件的相同目录寻找 `math_functions.js` 文件。用这种方式导入时,相对路径(`./`)和文件扩展名(`.js`)都是必需的。
可以在导入语句里导入多个项目,如下:
@ -21,50 +21,31 @@ import { add } from './math_functions.js';
import { add, subtract } from './math_functions.js';
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
添加 <code>import</code> 语句,使当前文件可以使用你在之前课程里导出的 <code>uppercaseString</code><code>lowercaseString</code> 函数,函数在当前路径下的 <code>string_functions.js</code> 文件里。
</section>
添加 `import` 语句,使当前文件可以使用你在之前课程里导出的 `uppercaseString``lowercaseString` 函数,函数在当前路径下的 `string_functions.js` 文件里。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 应该导入 <code>uppercaseString</code>、
testString: assert(code.match(/import\s*{\s*(uppercaseString[^}]*|[^,]*,\s*uppercaseString\s*)}\s+from\s+('|")\.\/string_functions\.js\2/g));
- text: 应该导入 <code>lowercaseString</code>、
testString: assert(code.match(/import\s*{\s*(lowercaseString[^}]*|[^,]*,\s*lowercaseString\s*)}\s+from\s+('|")\.\/string_functions\.js\2/g));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
应该导入 `uppercaseString`
```js
// add code above this line
uppercaseString("hello");
lowercaseString("WORLD!");
assert(
code.match(
/import\s*{\s*(uppercaseString[^}]*|[^,]*,\s*uppercaseString\s*)}\s+from\s+('|")\.\/string_functions\.js\2/g
)
);
```
</div>
</section>
## Solution
<section id='solution'>
应该导入 `lowercaseString`
```js
import { uppercaseString, lowercaseString } from './string_functions.js';
// add code above this line
uppercaseString("hello");
lowercaseString("WORLD!");
assert(
code.match(
/import\s*{\s*(lowercaseString[^}]*|[^,]*,\s*lowercaseString\s*)}\s+from\s+('|")\.\/string_functions\.js\2/g
)
);
```
</section>
# --solutions--

View File

@ -1,13 +1,14 @@
---
id: 587d7b88367417b2b2512b46
title: 设置函数的默认参数
challengeType: 1
forumTopicId: 301209
title: 设置函数的默认参数
---
## Description
<section id='description'>
# --description--
ES6 里允许给函数传入<dfn>默认参数</dfn>,来构建更加灵活的函数。
请看以下代码:
```js
@ -17,53 +18,31 @@ console.log(greeting("John")); // Hello John
console.log(greeting()); // Hello Anonymous
```
默认参数会在参数没有被指定(值为 undefined )的时候起作用。在上面的例子中,参数<code>name</code>会在没有得到新的值的时候,默认使用值 "Anonymous"。你还可以给多个参数赋予默认值。
</section>
默认参数会在参数没有被指定(值为 undefined )的时候起作用。在上面的例子中,参数`name`会在没有得到新的值的时候,默认使用值 "Anonymous"。你还可以给多个参数赋予默认值。
## Instructions
<section id='instructions'>
给函数<code>increment</code>加上默认参数,使得在<code>value</code>没有被赋值的时候,默认给<code>number</code>加1。
</section>
# --instructions--
## Tests
<section id='tests'>
给函数`increment`加上默认参数,使得在`value`没有被赋值的时候,默认给`number`加1。
```yml
tests:
- text: <code>increment(5, 2)</code>的结果应该为<code>7</code>。
testString: assert(increment(5, 2) === 7);
- text: <code>increment(5)</code>的结果应该为<code>6</code>。
testString: assert(increment(5) === 6);
- text: 参数<code>value</code>的默认值应该为<code>1</code>。
testString: assert(code.match(/value\s*=\s*1/g));
# --hints--
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`increment(5, 2)`的结果应该为`7`
```js
const increment = (number, value) => number + value;
console.log(increment(5, 2)); // returns 7
console.log(increment(5)); // returns 6
assert(increment(5, 2) === 7);
```
</div>
</section>
## Solution
<section id='solution'>
`increment(5)`的结果应该为`6`
```js
const increment = (number, value = 1) => number + value;
assert(increment(5) === 6);
```
</section>
参数`value`的默认值应该为`1`
```js
assert(code.match(/value\s*=\s*1/g));
```
# --solutions--

View File

@ -1,67 +1,40 @@
---
id: 587d7b8c367417b2b2512b57
title: 用 * 从文件中导入所有内容
challengeType: 1
forumTopicId: 301210
title: 用 * 从文件中导入所有内容
---
## Description
<section id='description'>
我们还可以用<code>import</code>语法从文件中导入所有的内容。下面是一个从同目录下的<code>"math_functions"</code>文件中导入所有内容的例子:
# --description--
我们还可以用`import`语法从文件中导入所有的内容。下面是一个从同目录下的`"math_functions"`文件中导入所有内容的例子:
```js
import * as myMathModule from "./math_functions.js";
```
上面的 <code>import</code> 语句会创建一个叫做 <code>myMathModule</code> 的对象。这只是一个变量名,可以随便命名。对象包含 <code>math_functions.js</code> 文件里的所有导出,可以像访问对象的属性那样访问里面的函数。下面是使用导入的 <code>add</code><code>subtract</code> 函数的例子:
上面的 `import` 语句会创建一个叫做 `myMathModule` 的对象。这只是一个变量名,可以随便命名。对象包含 `math_functions.js` 文件里的所有导出,可以像访问对象的属性那样访问里面的函数。下面是使用导入的 `add``subtract` 函数的例子:
```js
myMathModule.add(2,3);
myMathModule.subtract(5,3);
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
下面的代码需要从同目录下的<code>"string_functions"</code>文件中导入所有内容。使用提供的对象,在当前文件的顶部添加正确的<code>import *</code>语句
</section>
下面的代码需要从同目录下的`"string_functions"`文件中导入所有内容。使用提供的对象,在当前文件的顶部添加正确的`import *`语句
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 正确使用<code>import * as</code>语法。
testString: assert(code.match(/import\s*\*\s*as\s+stringFunctions\s+from\s*('|")\.\/string_functions\.js\1/g));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
正确使用`import * as`语法。
```js
// add code above this line
stringFunctions.uppercaseString("hello");
stringFunctions.lowercaseString("WORLD!");
assert(
code.match(
/import\s*\*\s*as\s+stringFunctions\s+from\s*('|")\.\/string_functions\.js\1/g
)
);
```
</div>
</section>
# --solutions--
## Solution
<section id='solution'>
```js
import * as stringFunctions from "./string_functions.js";
// add code above this line
stringFunctions.uppercaseString("hello");
stringFunctions.lowercaseString("WORLD!");
```
</section>

View File

@ -1,13 +1,14 @@
---
id: 587d7b87367417b2b2512b43
title: 使用箭头函数编写简洁的匿名函数
challengeType: 1
forumTopicId: 301211
title: 使用箭头函数编写简洁的匿名函数
---
## Description
<section id='description'>
# --description--
在 JavaScript 里,我们会经常遇到不需要给函数命名的情况,尤其是在需要将一个函数作为参数传给另外一个函数的时候。这时,我们会创建匿名函数。因为这些函数不会在其他地方复用,所以我们不需要给它们命名。
这种情况下,我们通常会使用以下语法:
```js
@ -26,66 +27,49 @@ const myFunc = () => {
}
```
当不需要函数体,只返回一个值的时候,箭头函数允许你省略<code>return</code>关键字和外面的大括号。这样就可以将一个简单的函数简化成一个单行语句。
当不需要函数体,只返回一个值的时候,箭头函数允许你省略`return`关键字和外面的大括号。这样就可以将一个简单的函数简化成一个单行语句。
```js
const myFunc = () => "value";
```
这段代码仍然会返回<code>value</code>
</section>
这段代码仍然会返回`value`
## Instructions
<section id='instructions'>
使用箭头函数的语法重写<code>magic</code>函数,使其返回一个新的<code>Date()</code>。同时不要用<code>var</code>关键字来定义任何变量。
</section>
# --instructions--
## Tests
<section id='tests'>
使用箭头函数的语法重写`magic`函数,使其返回一个新的`Date()`。同时不要用`var`关键字来定义任何变量。
```yml
tests:
- text: 替换掉<code>var</code>关键字。
testString: getUserInput => assert(!getUserInput('index').match(/var/g));
- text: <code>magic</code>应该为一个常量 (使用<code>const</code>)。
testString: getUserInput => assert(getUserInput('index').match(/const\s+magic/g));
- text: <code>magic</code>是一个<code>function</code>。
testString: assert(typeof magic === 'function');
- text: <code>magic()</code>返回正确的日期。
testString: assert(magic().setHours(0,0,0,0) === new Date().setHours(0,0,0,0));
- text: 不要使用<code>function</code>关键字。
testString: getUserInput => assert(!getUserInput('index').match(/function/g));
# --hints--
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
替换掉`var`关键字。
```js
var magic = function() {
"use strict";
return new Date();
};
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
</div>
</section>
## Solution
<section id='solution'>
`magic`应该为一个常量 (使用`const`)。
```js
const magic = () => {
"use strict";
return new Date();
};
(getUserInput) => assert(getUserInput('index').match(/const\s+magic/g));
```
</section>
`magic`是一个`function`
```js
assert(typeof magic === 'function');
```
`magic()`返回正确的日期。
```js
assert(magic().setHours(0, 0, 0, 0) === new Date().setHours(0, 0, 0, 0));
```
不要使用`function`关键字。
```js
(getUserInput) => assert(!getUserInput('index').match(/function/g));
```
# --solutions--

View File

@ -1,15 +1,17 @@
---
id: 587d7b8b367417b2b2512b53
title: 使用 class 语法定义构造函数
challengeType: 1
forumTopicId: 301212
title: 使用 class 语法定义构造函数
---
## Description
<section id='description'>
ES6 提供了一个新的创建对象的语法,使用关键字<code>class</code>
值得注意的是,<code>class</code>只是一个语法糖,它并不像 Java、Python 或者 Ruby 这一类的语言一样,严格履行了面向对象的开发规范。
在 ES5 里面,我们通常会定义一个构造函数,然后使用 <code>new</code> 关键字来实例化一个对象:
# --description--
ES6 提供了一个新的创建对象的语法,使用关键字`class`
值得注意的是,`class`只是一个语法糖,它并不像 Java、Python 或者 Ruby 这一类的语言一样,严格履行了面向对象的开发规范。
在 ES5 里面,我们通常会定义一个构造函数,然后使用 `new` 关键字来实例化一个对象:
```js
var SpaceShuttle = function(targetPlanet){
@ -18,7 +20,7 @@ var SpaceShuttle = function(targetPlanet){
var zeus = new SpaceShuttle('Jupiter');
```
<code>class</code>的语法只是简单地替换了构造函数的写法:
`class`的语法只是简单地替换了构造函数的写法:
```js
class SpaceShuttle {
@ -29,67 +31,51 @@ class SpaceShuttle {
const zeus = new SpaceShuttle('Jupiter');
```
应该注意 <code>class</code> 关键字声明了一个函数里面添加了一个构造器constructor。当调用 <code>new</code> 来创建一个新对象时构造器会被调用。
应该注意 `class` 关键字声明了一个函数里面添加了一个构造器constructor。当调用 `new` 来创建一个新对象时构造器会被调用。
**注意:**
-
<strong>注意:</strong><br><ul>
<li> 首字母大写驼峰命名法是 ES6 class 名的惯例,就像上面的 <code>SpaceShuttle</code></li>
<li> 构造函数是一个特殊的函数,在用 class 创建时来创建和初始化对象。在 JavaScript 算法和数据结构证书的面向对象章节里会更深入介绍。</li></ul>
</section>
## Instructions
<section id='instructions'>
使用<code>class</code>关键字,并写出正确的构造函数,来创建<code>Vegetable</code>这个类:
<code>Vegetable</code>这个类可以创建 vegetable 对象,这个对象拥有一个在构造函数中赋值的<code>name</code>属性。
</section>
# --instructions--
## Tests
<section id='tests'>
使用`class`关键字,并写出正确的构造函数,来创建`Vegetable`这个类:
```yml
tests:
- text: <code>Vegetable</code> 应该是一个 <code>class</code>,并在其中定义了<code>constructor</code>方法。
testString: assert(typeof Vegetable === 'function' && typeof Vegetable.constructor === 'function');
- text: 使用了<code>class</code>关键字。
testString: assert(code.match(/class/g));
- text: <code>Vegetable</code>可以被实例化。
testString: assert(() => {const a = new Vegetable("apple"); return typeof a === 'object';});
- text: <code>carrot.name</code> 应该返回 <code>carrot</code>.
testString: assert(carrot.name=='carrot');
`Vegetable`这个类可以创建 vegetable 对象,这个对象拥有一个在构造函数中赋值的`name`属性。
```
# --hints--
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`Vegetable` 应该是一个 `class`,并在其中定义了`constructor`方法。
```js
/* Alter code below this line */
/* Alter code above this line */
const carrot = new Vegetable('carrot');
console.log(carrot.name); // => should be 'carrot'
assert(
typeof Vegetable === 'function' && typeof Vegetable.constructor === 'function'
);
```
</div>
</section>
## Solution
<section id='solution'>
使用了`class`关键字。
```js
class Vegetable {
constructor(name) {
this.name = name;
}
}
const carrot = new Vegetable('carrot');
assert(code.match(/class/g));
```
</section>
`Vegetable`可以被实例化。
```js
assert(() => {
const a = new Vegetable('apple');
return typeof a === 'object';
});
```
`carrot.name` 应该返回 `carrot`.
```js
assert(carrot.name == 'carrot');
```
# --solutions--

View File

@ -1,14 +1,16 @@
---
id: 587d7b89367417b2b2512b4b
title: 使用解构赋值从数组中分配变量
challengeType: 1
forumTopicId: 301213
title: 使用解构赋值从数组中分配变量
---
## Description
<section id='description'>
# --description--
在 ES6 里面,解构数组可以如同解构对象一样简单。
与数组解构不同,数组的扩展运算会将数组里的所有内容分解成一个由逗号分隔的列表。所以,你不能选择哪个元素来给变量赋值。
而对数组进行解构却可以让我们做到这一点:
```js
@ -16,63 +18,36 @@ const [a, b] = [1, 2, 3, 4, 5, 6];
console.log(a, b); // 1, 2
```
变量<code>a</code>以及<code>b</code>分别被数组的第一、第二个元素赋值。
我们甚至能在数组解构中使用逗号分隔符,来获取任意一个想要的值:
变量`a`以及`b`分别被数组的第一、第二个元素赋值。 我们甚至能在数组解构中使用逗号分隔符,来获取任意一个想要的值:
```js
const [a, b,,, c] = [1, 2, 3, 4, 5, 6];
console.log(a, b, c); // 1, 2, 5
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
使用数组解构来交换变量<code>a</code><code>b</code>的值。使<code>a</code><code>b</code>能分别获得对方的值。
</section>
使用数组解构来交换变量`a``b`的值。使`a``b`能分别获得对方的值。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 在交换后,<code>a</code>的值应该为6。
testString: assert(a === 6);
- text: 在交换后,<code>b</code>的值应该为8。
testString: assert(b === 8);
- text: 使用数组解构来交换<code>a</code>和<code>b</code>。
testString: assert(/\[\s*(\w)\s*,\s*(\w)\s*\]\s*=\s*\[\s*\2\s*,\s*\1\s*\]/g.test(code));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
在交换后,`a`的值应该为6。
```js
let a = 8, b = 6;
// change code below this line
// change code above this line
console.log(a); // should be 6
console.log(b); // should be 8
assert(a === 6);
```
</div>
</section>
## Solution
<section id='solution'>
在交换后,`b`的值应该为8。
```js
let a = 8, b = 6;
[a, b] = [b, a];
assert(b === 8);
```
</section>
使用数组解构来交换`a``b`
```js
assert(/\[\s*(\w)\s*,\s*(\w)\s*\]\s*=\s*\[\s*\2\s*,\s*\1\s*\]/g.test(code));
```
# --solutions--

View File

@ -1,13 +1,13 @@
---
id: 587d7b89367417b2b2512b4a
title: 使用解构赋值从嵌套对象中分配变量
challengeType: 1
forumTopicId: 301214
title: 使用解构赋值从嵌套对象中分配变量
---
## Description
<section id='description'>
同样,我们可以将 <em>嵌套的对象</em>解构到变量中。
# --description--
同样,我们可以将 *嵌套的对象*解构到变量中。
请看以下代码:
@ -32,71 +32,40 @@ const { johnDoe: { age, email }} = user;
const { johnDoe: { age: userAge, email: userEmail }} = user;
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
将两个赋值语句替换成等价的解构赋值。<code>lowToday</code><code>highToday</code> 应该为 <code>LOCAL_FORECAST</code><code>today.low</code><code>today.high</code> 的值。
</section>
将两个赋值语句替换成等价的解构赋值。`lowToday``highToday` 应该为 `LOCAL_FORECAST``today.low``today.high` 的值。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 不能使用 ES5 的赋值语句。
testString: assert(!code.match(/lowToday = LOCAL_FORECAST\.today\.low/g) && !code.match(/highToday = LOCAL_FORECAST\.today.high/g))
- text: 应该使用解构创建 <code>lowToday</code> 变量。
testString: assert(code.match(/(var|const|let)\s*{\s*today\s*:\s*{\s*(low\s*:\s*lowToday[^}]*|[^,]*,\s*low\s*:\s*lowToday\s*)}\s*}\s*=\s*LOCAL_FORECAST(;|\s+|\/\/)/g));
- text: 应该使用解构创建 <code>highToday</code> 变量。
testString: assert(code.match(/(var|const|let)\s*{\s*today\s*:\s*{\s*(high\s*:\s*highToday[^}]*|[^,]*,\s*high\s*:\s*highToday\s*)}\s*}\s*=\s*LOCAL_FORECAST(;|\s+|\/\/)/g));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
不能使用 ES5 的赋值语句。
```js
const LOCAL_FORECAST = {
yesterday: { low: 61, high: 75 },
today: { low: 64, high: 77 },
tomorrow: { low: 68, high: 80 }
};
// change code below this line
const lowToday = LOCAL_FORECAST.today.low;
const highToday = LOCAL_FORECAST.today.high;
// change code above this line
console.log(lowToday); // should be 64
console.log(highToday); // should be 77
assert(
!code.match(/lowToday = LOCAL_FORECAST\.today\.low/g) &&
!code.match(/highToday = LOCAL_FORECAST\.today.high/g)
);
```
</div>
</section>
## Solution
<section id='solution'>
应该使用解构创建 `lowToday` 变量。
```js
const LOCAL_FORECAST = {
yesterday: { low: 61, high: 75 },
today: { low: 64, high: 77 },
tomorrow: { low: 68, high: 80 }
};
// change code below this line
const { today: { low: lowToday, high: highToday }} = LOCAL_FORECAST;
// change code above this line
console.log(highToday); // should be 77
console.log(highTomorrow); // should be 80
assert(
code.match(
/(var|const|let)\s*{\s*today\s*:\s*{\s*(low\s*:\s*lowToday[^}]*|[^,]*,\s*low\s*:\s*lowToday\s*)}\s*}\s*=\s*LOCAL_FORECAST(;|\s+|\/\/)/g
)
);
```
</section>
应该使用解构创建 `highToday` 变量。
```js
assert(
code.match(
/(var|const|let)\s*{\s*today\s*:\s*{\s*(high\s*:\s*highToday[^}]*|[^,]*,\s*high\s*:\s*highToday\s*)}\s*}\s*=\s*LOCAL_FORECAST(;|\s+|\/\/)/g
)
);
```
# --solutions--

View File

@ -1,12 +1,12 @@
---
id: 587d7b89367417b2b2512b49
title: 使用解构赋值从对象中分配变量
challengeType: 1
forumTopicId: 301215
title: 使用解构赋值从对象中分配变量
---
## Description
<section id='description'>
# --description--
可以在解构的属性后添加冒号和新的变量名来给解构的值赋予一个新的变量名。
还是以上个例子的对象来举例:
@ -22,73 +22,42 @@ const { name: userName, age: userAge } = user;
// userName = 'John Doe', userAge = 34
```
获取到了 <code>user.name</code> 的值并赋值给名为 <code>userName</code> 的变量。
</section>
获取到了 `user.name` 的值并赋值给名为 `userName` 的变量。
## Instructions
<section id='instructions'>
使用解构赋值语句替换两个赋值语句。确保 <code>HIGH_TEMPERATURES</code><code>today</code><code>tomorrow</code> 属性赋值给 <code>highToday</code><code>highTomorrow</code>
</section>
# --instructions--
## Tests
<section id='tests'>
使用解构赋值语句替换两个赋值语句。确保 `HIGH_TEMPERATURES``today``tomorrow` 属性赋值给 `highToday``highTomorrow`
```yml
tests:
- text: 应该移除 ES5 赋值语句。
testString: assert(!code.match(/highToday = HIGH_TEMPERATURES\.today/g) && !code.match(/highTomorrow = HIGH_TEMPERATURES\.tomorrow/g))
- text: 应该使用解构赋值语句创建 <code>highToday</code> 变量。
testString: assert(code.match(/(var|const|let)\s*{\s*(today:\s*highToday[^}]*|[^,]*,\s*today\s*:\s*highToday\s*)}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g));
- text: 应该使用解构赋值语句创建 <code>highTomorrow</code> 变量。
testString: assert(code.match(/(var|const|let)\s*{\s*(tomorrow:\s*highTomorrow[^}]*|[^,]*,\s*tomorrow\s*:\s*highTomorrow\s*)}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g));
```
# --hints--
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
应该移除 ES5 赋值语句。
```js
const HIGH_TEMPERATURES = {
yesterday: 75,
today: 77,
tomorrow: 80
};
// change code below this line
const highToday = HIGH_TEMPERATURES.today;
const highTomorrow = HIGH_TEMPERATURES.tomorrow;
// change code above this line
console.log(yesterday) // should be not defined
console.log(highToday); // should be 77
console.log(highTomorrow); // should be 80
assert(
!code.match(/highToday = HIGH_TEMPERATURES\.today/g) &&
!code.match(/highTomorrow = HIGH_TEMPERATURES\.tomorrow/g)
);
```
</div>
</section>
## Solution
<section id='solution'>
应该使用解构赋值语句创建 `highToday` 变量。
```js
const HIGH_TEMPERATURES = {
yesterday: 75,
today: 77,
tomorrow: 80
};
// change code below this line
const { today: highToday, tomorrow: highTomorrow } = HIGH_TEMPERATURES;
// change code above this line
console.log(highToday); // should be 77
console.log(highTomorrow); // should be 80
assert(
code.match(
/(var|const|let)\s*{\s*(today:\s*highToday[^}]*|[^,]*,\s*today\s*:\s*highToday\s*)}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g
)
);
```
</section>
应该使用解构赋值语句创建 `highTomorrow` 变量。
```js
assert(
code.match(
/(var|const|let)\s*{\s*(tomorrow:\s*highTomorrow[^}]*|[^,]*,\s*tomorrow\s*:\s*highTomorrow\s*)}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g
)
);
```
# --solutions--

View File

@ -1,12 +1,12 @@
---
id: 5cfa550e84205a357704ccb6
title: 使用解构赋值来获取对象的值
challengeType: 1
forumTopicId: 301216
title: 使用解构赋值来获取对象的值
---
## Description
<section id='description'>
# --description--
<dfn>解构赋值</dfn> 是 ES6 引入的新语法,用来从数组和对象中提取值,并优雅的对变量进行赋值。
有如下 ES5 代码:
@ -25,76 +25,44 @@ const { name, age } = user;
// name = 'John Doe', age = 34
```
在这里,<code>name</code><code>age</code> 被自动创建并赋予 <code>user</code> 对象相应属性的值。一目了然。
在这里,`name``age` 被自动创建并赋予 `user` 对象相应属性的值。一目了然。
解构赋值的参数数量可以任意。
</section>
## Instructions
<section id='instructions'>
把两个赋值语句替换成等价的解构赋值。<code>today</code><code>tomorrow</code> 的值应该还为 <code>HIGH_TEMPERATURES</code> 对象的 <code>today</code><code>tomorrow</code> 属性的值。
</section>
# --instructions--
## Tests
<section id='tests'>
把两个赋值语句替换成等价的解构赋值。`today``tomorrow` 的值应该还为 `HIGH_TEMPERATURES` 对象的 `today``tomorrow` 属性的值。
```yml
tests:
- text: 应该移除 ES5 赋值语句。
testString: assert(!code.match(/today = HIGH_TEMPERATURES\.today/g) && !code.match(/tomorrow = HIGH_TEMPERATURES\.tomorrow/g))
- text: 应该解构创建 <code>today</code> 变量。
testString: assert(code.match(/(var|let|const)\s*{\s*(today[^}]*|[^,]*,\s*today)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g));
- text: 应该解构创建 <code>tomorrow</code> 变量。
testString: assert(code.match(/(var|let|const)\s*{\s*(tomorrow[^}]*|[^,]*,\s*tomorrow)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g));
```
# --hints--
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
应该移除 ES5 赋值语句。
```js
const HIGH_TEMPERATURES = {
yesterday: 75,
today: 77,
tomorrow: 80
};
// change code below this line
const today = HIGH_TEMPERATURES.today;
const tomorrow = HIGH_TEMPERATURES.tomorrow;
// change code above this line
console.log(yesterday) // should be not defined
console.log(today); // should be 77
console.log(tomorrow); // should be 80
assert(
!code.match(/today = HIGH_TEMPERATURES\.today/g) &&
!code.match(/tomorrow = HIGH_TEMPERATURES\.tomorrow/g)
);
```
</div>
</section>
## Solution
<section id='solution'>
应该解构创建 `today` 变量。
```js
const HIGH_TEMPERATURES = {
yesterday: 75,
today: 77,
tomorrow: 80
};
// change code below this line
const { today, tomorrow } = HIGH_TEMPERATURES;
// change code above this line
console.log(yesterday) // should be not defined
console.log(today); // should be 77
console.log(tomorrow); // should be 80
assert(
code.match(
/(var|let|const)\s*{\s*(today[^}]*|[^,]*,\s*today)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g
)
);
```
</section>
应该解构创建 `tomorrow` 变量。
```js
assert(
code.match(
/(var|let|const)\s*{\s*(tomorrow[^}]*|[^,]*,\s*tomorrow)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g
)
);
```
# --solutions--

View File

@ -1,13 +1,14 @@
---
id: 587d7b8a367417b2b2512b4d
title: 使用解构赋值将对象作为函数的参数传递
challengeType: 1
forumTopicId: 301217
title: 使用解构赋值将对象作为函数的参数传递
---
## Description
<section id='description'>
# --description--
在某些情况下,你可以在函数的参数里直接解构对象。
请看以下代码:
```js
@ -25,76 +26,37 @@ const profileUpdate = ({ name, age, nationality, location }) => {
}
```
这样的操作去除了多余的代码,使代码更加整洁。
这样做还有个额外的好处:函数不需要再去操作整个对象,而仅仅是操作复制到函数作用域内部的参数。
</section>
这样的操作去除了多余的代码,使代码更加整洁。 这样做还有个额外的好处:函数不需要再去操作整个对象,而仅仅是操作复制到函数作用域内部的参数。
## Instructions
<section id='instructions'>
<code>half</code>的参数进行解构赋值,使得仅仅将<code>max</code><code>min</code>的值传进函数。
</section>
# --instructions--
## Tests
<section id='tests'>
`half`的参数进行解构赋值,使得仅仅将`max``min`的值传进函数。
```yml
tests:
- text: <code>stats</code>的类型应该是一个<code>object</code>。
testString: assert(typeof stats === 'object');
- text: <code>half(stats)</code>应该等于<code>28.015</code>
testString: assert(half(stats) === 28.015);
- text: 应该使用解构赋值。
testString: assert(code.replace(/\s/g, '').match(/half=\({\w+,\w+}\)/));
- text: 应该使用解构参数。
testString: assert(!code.match(/stats\.max|stats\.min/));
# --hints--
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`stats`的类型应该是一个`object`
```js
const stats = {
max: 56.78,
standard_deviation: 4.34,
median: 34.54,
mode: 23.87,
min: -0.75,
average: 35.85
};
// change code below this line
const half = (stats) => (stats.max + stats.min) / 2.0; // use function argument destructuring
// change code above this line
console.log(stats); // should be object
console.log(half(stats)); // should be 28.015
assert(typeof stats === 'object');
```
</div>
</section>
## Solution
<section id='solution'>
`half(stats)`应该等于`28.015`
```js
const stats = {
max: 56.78,
standard_deviation: 4.34,
median: 34.54,
mode: 23.87,
min: -0.75,
average: 35.85
};
const half = ( {max, min} ) => (max + min) / 2.0;
assert(half(stats) === 28.015);
```
</section>
应该使用解构赋值。
```js
assert(code.replace(/\s/g, '').match(/half=\({\w+,\w+}\)/));
```
应该使用解构参数。
```js
assert(!code.match(/stats\.max|stats\.min/));
```
# --solutions--

View File

@ -1,14 +1,15 @@
---
id: 587d7b8a367417b2b2512b4c
title: 使用解构赋值配合 rest 操作符来重新分配数组元素
challengeType: 1
forumTopicId: 301218
title: 使用解构赋值配合 rest 操作符来重新分配数组元素
---
## Description
<section id='description'>
# --description--
在解构数组的某些情况下,我们可能希望将剩下的元素放进另一个数组里面。
以下代码的结果与使用<code>Array.prototype.slice()</code>相同:
以下代码的结果与使用`Array.prototype.slice()`相同:
```js
const [a, b, ...arr] = [1, 2, 3, 4, 5, 7];
@ -16,69 +17,33 @@ console.log(a, b); // 1, 2
console.log(arr); // [3, 4, 5, 7]
```
变量<code>a</code><code>b</code>分别获取了数组的前两个元素的值。之后,因为<code>rest</code>操作符的存在,<code>arr</code>获取了原数组剩余的元素的值,并构成了一个新的数组。
<code>rest</code>操作只能对数组列表最后的元素起作用。这意味着你不能使用<code>rest</code>操作符来截取原数组中间元素的子数组。
</section>
变量`a``b`分别获取了数组的前两个元素的值。之后,因为`rest`操作符的存在,`arr`获取了原数组剩余的元素的值,并构成了一个新的数组。 `rest`操作只能对数组列表最后的元素起作用。这意味着你不能使用`rest`操作符来截取原数组中间元素的子数组。
## Instructions
<section id='instructions'>
使用解构赋值以及<code>rest</code>操作符来进行一个<code>Array.prototype.slice</code>相同的操作。使得<code>arr</code>是原数组<code>source</code>除开前两个元素的子数组。
</section>
# --instructions--
## Tests
<section id='tests'>
使用解构赋值以及`rest`操作符来进行一个`Array.prototype.slice`相同的操作。使得`arr`是原数组`source`除开前两个元素的子数组。
```yml
tests:
- text: <code>arr</code>应该为<code>[3,4,5,6,7,8,9,10]</code>
testString: assert(arr.every((v, i) => v === i + 3) && arr.length === 8);
- text: 没有使用<code>Array.slice()</code>。
testString: getUserInput => assert(!getUserInput('index').match(/slice/g));
- text: 使用了解构赋值。
testString: assert(code.replace(/\s/g, '').match(/\[(([_$a-z]\w*)?,){1,}\.\.\.arr\]=list/i));
# --hints--
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`arr`应该为`[3,4,5,6,7,8,9,10]`
```js
const source = [1,2,3,4,5,6,7,8,9,10];
function removeFirstTwo(list) {
"use strict";
// change code below this line
const arr = list; // change this
// change code above this line
return arr;
}
const arr = removeFirstTwo(source);
console.log(arr); // should be [3,4,5,6,7,8,9,10]
console.log(source); // should be [1,2,3,4,5,6,7,8,9,10];
assert(arr.every((v, i) => v === i + 3) && arr.length === 8);
```
</div>
</section>
## Solution
<section id='solution'>
没有使用`Array.slice()`
```js
const source = [1,2,3,4,5,6,7,8,9,10];
function removeFirstTwo(list) {
"use strict";
// change code below this line
const [, , ...arr] = list;
// change code above this line
return arr;
}
const arr = removeFirstTwo(source);
(getUserInput) => assert(!getUserInput('index').match(/slice/g));
```
</section>
使用了解构赋值。
```js
assert(
code.replace(/\s/g, '').match(/\[(([_$a-z]\w*)?,){1,}\.\.\.arr\]=list/i)
);
```
# --solutions--

View File

@ -1,13 +1,13 @@
---
id: 587d7b8c367417b2b2512b56
title: 用 export 来重用代码块
challengeType: 1
forumTopicId: 301219
title: 用 export 来重用代码块
---
## Description
<section id='description'>
假设有一个文件 <code>math_functions.js</code>,该文件包含了数学运算相关的一些函数。其中一个存储在变量 <code>add</code> 里,该函数接受两个数字做为参数返回它们的和。如果想在其它不同的 JavaScript 文件里使用这个函数,就需要 <code>export</code> 它。
# --description--
假设有一个文件 `math_functions.js`,该文件包含了数学运算相关的一些函数。其中一个存储在变量 `add` 里,该函数接受两个数字做为参数返回它们的和。如果想在其它不同的 JavaScript 文件里使用这个函数,就需要 `export` 它。
```js
export const add = (x, y) => {
@ -31,55 +31,31 @@ export { add };
export { add, subtract };
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
下面有两个变量需要在别的文件中可以使用。利用刚才展示的第一种方式,导出两个变量。
</section>
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 应该导出<code>uppercaseString</code>变量。
testString: assert(code.match(/(export\s+const\s+uppercaseString|export\s*{\s*(uppercaseString[^}]*|[^,]*,\s*uppercaseString\s*)})/g));
- text: 应该导出<code>lowercaseString</code>变量。
testString: assert(code.match(/(export\s+const\s+lowercaseString|export\s*{\s*(lowercaseString[^}]*|[^,]*,\s*lowercaseString\s*)})/g));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
应该导出`uppercaseString`变量。
```js
const uppercaseString = (string) => {
return string.toUpperCase();
}
const lowercaseString = (string) => {
return string.toLowerCase()
}
assert(
code.match(
/(export\s+const\s+uppercaseString|export\s*{\s*(uppercaseString[^}]*|[^,]*,\s*uppercaseString\s*)})/g
)
);
```
</div>
</section>
## Solution
<section id='solution'>
应该导出`lowercaseString`变量。
```js
export const uppercaseString = (string) => {
return string.toUpperCase();
}
export const lowercaseString = (string) => {
return string.toLowerCase()
}
assert(
code.match(
/(export\s+const\s+lowercaseString|export\s*{\s*(lowercaseString[^}]*|[^,]*,\s*lowercaseString\s*)})/g
)
);
```
</section>
# --solutions--

View File

@ -1,15 +1,18 @@
---
id: 587d7b8c367417b2b2512b54
title: 使用 getter 和 setter 来控制对象的访问
challengeType: 1
forumTopicId: 301220
title: 使用 getter 和 setter 来控制对象的访问
---
## Description
<section id='description'>
# --description--
你可以从对象中获得一个值,也可以给对象的属性赋值。
这些通常行为被称为 <dfn>getters</dfn> 以及 <dfn>setters</dfn>
Getter 函数的作用是可以让对象返回一个私有变量,而不需要直接去访问私有变量。
Setter 函数的作用是可以基于传进的参数来修改对象中私有变量。这些修改可以是计算,或者是直接替换之前的值。
```js
@ -32,89 +35,91 @@ lol.writer = 'wut';
console.log(lol.writer); // wut
```
注意我们调用 getter 和 setter 的语法,它们看起来并不像一个函数调用。
Getter 和 Setter 非常重要,因为它们隐藏了内部的实现细节。
注意我们调用 getter 和 setter 的语法,它们看起来并不像一个函数调用。 Getter 和 Setter 非常重要,因为它们隐藏了内部的实现细节。
<strong>注意:</strong> 通常会在私有变量前添加下划线(<code>_</code>)。这里并没有真正意义上让变量私有。
</section>
**注意:** 通常会在私有变量前添加下划线(`_`)。这里并没有真正意义上让变量私有。
# --instructions--
使用`class`关键字来创建`Thermostat`类,它的构造函数应该可以接收 fahrenheit华氏温度作为参数。
在类中创建 temperature 的 `getter``setter`,将温度转换成摄氏温度。
温度转换的公式是`C = 5/9 * (F - 32)`以及`F = C * 9.0 / 5 + 32`F 代表华氏温度C 代表摄氏温度。
**注意:** 当你实现这个作业的时候,你应当在类中使用一个温度标准,无论是华氏温度还是摄氏温度。
## Instructions
<section id='instructions'>
使用<code>class</code>关键字来创建<code>Thermostat</code>类,它的构造函数应该可以接收 fahrenheit华氏温度作为参数。
在类中创建 temperature 的 <code>getter</code><code>setter</code>,将温度转换成摄氏温度。
温度转换的公式是<code>C = 5/9 * (F - 32)</code>以及<code>F = C * 9.0 / 5 + 32</code>F 代表华氏温度C 代表摄氏温度。
<strong>注意:</strong> 当你实现这个作业的时候,你应当在类中使用一个温度标准,无论是华氏温度还是摄氏温度。
是时候展现 getter 和 setter 的威力了——无论你的 API 内部使用的是哪种温度标准,用户都能得到正确的结果。
或者说,你从用户需求中抽象出了实现细节。
</section>
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: <code>Thermostat</code>应该是一个<code>class</code>,并且在其中定义了<code>constructor</code>方法。
testString: assert(typeof Thermostat === 'function' && typeof Thermostat.constructor === 'function');
- text: 应该使用 <code>class</code> 关键字。
testString: assert(code.match(/class/g));
- text: <code>Thermostat</code>应该可以被实例化。
testString: assert((() => {const t = new Thermostat(32);return typeof t === 'object' && t.temperature === 0;})());
- text: 应该定义一个 <code>getter</code>。
testString: assert((() => {const desc = Object.getOwnPropertyDescriptor(Thermostat.prototype, 'temperature');return !!desc && typeof desc.get === 'function';})());
- text: 应该定义一个 <code>setter</code>。
testString: assert((() => {const desc = Object.getOwnPropertyDescriptor(Thermostat.prototype, 'temperature');return !!desc && typeof desc.set === 'function';})());
- text: 调用 <code>setter</code> 应该设置 temperature。
testString: assert((() => {const t = new Thermostat(32); t.temperature = 26;return t.temperature !== 0;})());
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`Thermostat`应该是一个`class`,并且在其中定义了`constructor`方法。
```js
/* Alter code below this line */
/* Alter code above this line */
const thermos = new Thermostat(76); // setting in Fahrenheit scale
let temp = thermos.temperature; // 24.44 in C
thermos.temperature = 26;
temp = thermos.temperature; // 26 in C
assert(
typeof Thermostat === 'function' &&
typeof Thermostat.constructor === 'function'
);
```
</div>
</section>
## Solution
<section id='solution'>
应该使用 `class` 关键字。
```js
/* Alter code below this line */
class Thermostat {
constructor(fahrenheit) {
this._tempInCelsius = 5/9 * (fahrenheit - 32);
}
get temperature(){
return this._tempInCelsius;
}
set temperature(newTemp){
this._tempInCelsius = newTemp;
}
}
/* Alter code above this line */
const thermos = new Thermostat(76); // setting in Fahrenheit scale
let temp = thermos.temperature; // 24.44 in C
thermos.temperature = 26;
temp = thermos.temperature; // 26 in C
assert(code.match(/class/g));
```
</section>
`Thermostat`应该可以被实例化。
```js
assert(
(() => {
const t = new Thermostat(32);
return typeof t === 'object' && t.temperature === 0;
})()
);
```
应该定义一个 `getter`
```js
assert(
(() => {
const desc = Object.getOwnPropertyDescriptor(
Thermostat.prototype,
'temperature'
);
return !!desc && typeof desc.get === 'function';
})()
);
```
应该定义一个 `setter`
```js
assert(
(() => {
const desc = Object.getOwnPropertyDescriptor(
Thermostat.prototype,
'temperature'
);
return !!desc && typeof desc.set === 'function';
})()
);
```
调用 `setter` 应该设置 temperature。
```js
assert(
(() => {
const t = new Thermostat(32);
t.temperature = 26;
return t.temperature !== 0;
})()
);
```
# --solutions--

View File

@ -1,13 +1,14 @@
---
id: 587d7b88367417b2b2512b47
title: 将 rest 操作符与函数参数一起使用
challengeType: 1
forumTopicId: 301221
title: 将 rest 操作符与函数参数一起使用
---
## Description
<section id='description'>
ES6 推出了用于函数参数的<dfn> rest 操作符</dfn>帮助我们创建更加灵活的函数。在<code>rest</code>操作符的帮助下,你可以创建有一个变量来接受多个参数的函数。这些参数被储存在一个可以在函数内部读取的数组中。
# --description--
ES6 推出了用于函数参数的<dfn>rest 操作符</dfn>帮助我们创建更加灵活的函数。在`rest`操作符的帮助下,你可以创建有一个变量来接受多个参数的函数。这些参数被储存在一个可以在函数内部读取的数组中。
请看以下代码:
```js
@ -18,60 +19,43 @@ console.log(howMany(0, 1, 2)); // You have passed 3 arguments.
console.log(howMany("string", null, [1, 2, 3], { })); // You have passed 4 arguments.
```
<code>rest</code>操作符可以避免查看<code>args</code>数组的需求,并且允许我们在参数数组上使用<code>map()</code><code>fiter()</code><code>reduce()</code>
</section>
`rest`操作符可以避免查看`args`数组的需求,并且允许我们在参数数组上使用`map()``fiter()``reduce()`
## Instructions
<section id='instructions'>
修改<code>sum</code>函数,来让它使用<code>rest</code>操作符,并且它可以在有任何数量的参数时以相同的形式工作。
</section>
# --instructions--
## Tests
<section id='tests'>
修改`sum`函数,来让它使用`rest`操作符,并且它可以在有任何数量的参数时以相同的形式工作。
```yml
tests:
- text: <code>sum(0,1,2)</code>的返回结果应该为3。
testString: assert(sum(0,1,2) === 3);
- text: <code>sum(1,2,3,4)</code>的返回结果应该为10。
testString: assert(sum(1,2,3,4) === 10);
- text: <code>sum(5)</code>的返回结果应该为5。
testString: assert(sum(5) === 5);
- text: <code>sum()</code>的返回结果应该为 0。
testString: assert(sum() === 0);
- text: 对<code>sum</code>函数的<code>args</code>参数使用了<code>...</code>展开操作符。
testString: assert(code.replace(/\s/g,'').match(/sum=\(\.\.\.args\)=>/));
# --hints--
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`sum(0,1,2)`的返回结果应该为3。
```js
const sum = (x, y, z) => {
const args = [x, y, z];
return args.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3)); // 6
assert(sum(0, 1, 2) === 3);
```
</div>
</section>
## Solution
<section id='solution'>
`sum(1,2,3,4)`的返回结果应该为10。
```js
const sum = (...args) => {
return args.reduce((a, b) => a + b, 0);
}
assert(sum(1, 2, 3, 4) === 10);
```
</section>
`sum(5)`的返回结果应该为5。
```js
assert(sum(5) === 5);
```
`sum()`的返回结果应该为 0。
```js
assert(sum() === 0);
```
`sum`函数的`args`参数使用了`...`展开操作符。
```js
assert(code.replace(/\s/g, '').match(/sum=\(\.\.\.args\)=>/));
```
# --solutions--

View File

@ -1,86 +1,60 @@
---
id: 587d7b89367417b2b2512b48
title: 使用 spread 运算符展开数组项
challengeType: 1
forumTopicId: 301222
title: 使用 spread 运算符展开数组项
---
## Description
<section id='description'>
# --description--
ES6 允许我们使用 <dfn>展开操作符</dfn> 来展开数组,以及需要多个参数或元素的表达式。
下面的 ES5 代码使用了<code>apply()</code>来计算数组的最大值:
下面的 ES5 代码使用了`apply()`来计算数组的最大值:
```js
var arr = [6, 89, 3, 45];
var maximus = Math.max.apply(null, arr); // returns 89
```
我们必须使用<code>Math.max.apply(null,arr)</code>,是因为直接调用<code>Math.max(arr)</code>会返回<code>NaN</code><code>Math.max()</code>函数需要传入的是一系列由逗号分隔的参数,而不是一个数组
展开操作符可以提升代码的可读性,这对后续的代码维护是有积极作用的。
我们必须使用`Math.max.apply(null,arr)`,是因为直接调用`Math.max(arr)`会返回`NaN``Math.max()`函数需要传入的是一系列由逗号分隔的参数,而不是一个数组。 展开操作符可以提升代码的可读性,这对后续的代码维护是有积极作用的
```js
const arr = [6, 89, 3, 45];
const maximus = Math.max(...arr); // returns 89
```
<code>...arr</code>返回了一个“打开”的数组。或者说它 <em>展开</em> 了数组。
然而,展开操作符只能够在函数的参数中,或者数组之中使用。下面的代码将会报错:
`...arr`返回了一个“打开”的数组。或者说它 *展开* 了数组。 然而,展开操作符只能够在函数的参数中,或者数组之中使用。下面的代码将会报错:
```js
const spreaded = ...arr; // will throw a syntax error
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
使用展开操作符将<code>arr1</code>中的内容都赋值到<code>arr2</code>中去。
</section>
使用展开操作符将`arr1`中的内容都赋值到`arr2`中去。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: <code>arr2</code>的值是由<code>arr1</code>拷贝而来的。
testString: assert(arr2.every((v, i) => v === arr1[i]));
- text: 用<code>...</code>展开操作符来赋值<code>arr1</code>。
testString: assert(code.match(/Array\(\s*\.\.\.arr1\s*\)|\[\s*\.\.\.arr1\s*\]/));
- text: 当<code>arr1</code>改变的时候,<code>arr2</code>不会改变。
testString: assert((arr1, arr2) => {arr1.push('JUN'); return arr2.length < arr1.length});
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
`arr2`的值是由`arr1`拷贝而来的。
```js
const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];
let arr2;
arr2 = []; // change this line
console.log(arr2);
assert(arr2.every((v, i) => v === arr1[i]));
```
</div>
</section>
## Solution
<section id='solution'>
`...`展开操作符来赋值`arr1`
```js
const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];
let arr2;
arr2 = [...arr1];
assert(code.match(/Array\(\s*\.\.\.arr1\s*\)|\[\s*\.\.\.arr1\s*\]/));
```
</section>
`arr1`改变的时候,`arr2`不会改变。
```js
assert((arr1, arr2) => {
arr1.push('JUN');
return arr2.length < arr1.length;
});
```
# --solutions--

View File

@ -1,12 +1,12 @@
---
id: 587d7b88367417b2b2512b44
title: 编写带参数的箭头函数
challengeType: 1
forumTopicId: 301223
title: 编写带参数的箭头函数
---
## Description
<section id='description'>
# --description--
和一般的函数一样,你也可以给箭头函数传递参数。
```js
@ -28,63 +28,44 @@ const doubler = item => item * 2;
const multiplier = (item, multi) => item * multi;
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
使用箭头函数的语法重写<code>myConcat</code>函数,使其可以将<code>arr2</code>的内容填充在<code>arr1</code>里。
</section>
使用箭头函数的语法重写`myConcat`函数,使其可以将`arr2`的内容填充在`arr1`里。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 替换掉所有的<code>var</code>关键字。
testString: getUserInput => assert(!getUserInput('index').match(/var/g));
- text: <code>myConcat</code>应该是一个常量 (使用<code>const</code>)。
testString: getUserInput => assert(getUserInput('index').match(/const\s+myConcat/g));
- text: <code>myConcat</code>应该是一个函数。
testString: assert(typeof myConcat === 'function');
- text: <code>myConcat()</code> 应该返回 <code>[1, 2, 3, 4, 5]</code>。
testString: assert(() => { const a = myConcat([1], [2]); return a[0] == 1 && a[1] == 2; });
- text: 不要使用<code>function</code>关键字。
testString: getUserInput => assert(!getUserInput('index').match(/function/g));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
替换掉所有的`var`关键字。
```js
var myConcat = function(arr1, arr2) {
"use strict";
return arr1.concat(arr2);
};
// test your code
console.log(myConcat([1, 2], [3, 4, 5]));
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
</div>
</section>
## Solution
<section id='solution'>
`myConcat`应该是一个常量 (使用`const`)。
```js
const myConcat = (arr1, arr2) => {
"use strict";
return arr1.concat(arr2);
};
// test your code
console.log(myConcat([1, 2], [3, 4, 5]));
(getUserInput) => assert(getUserInput('index').match(/const\s+myConcat/g));
```
</section>
`myConcat`应该是一个函数。
```js
assert(typeof myConcat === 'function');
```
`myConcat()` 应该返回 `[1, 2, 3, 4, 5]`
```js
assert(() => {
const a = myConcat([1], [2]);
return a[0] == 1 && a[1] == 2;
});
```
不要使用`function`关键字。
```js
(getUserInput) => assert(!getUserInput('index').match(/function/g));
```
# --solutions--

View File

@ -1,13 +1,13 @@
---
id: 587d7b8b367417b2b2512b50
title: 用 ES6 编写简洁的函数声明
challengeType: 1
forumTopicId: 301224
title: 用 ES6 编写简洁的函数声明
---
## Description
<section id='description'>
在 ES5 中,当我们需要在对象中定义一个函数的时候,我们必须如下面这般使用<code>function</code>关键字:
# --description--
在 ES5 中,当我们需要在对象中定义一个函数的时候,我们必须如下面这般使用`function`关键字:
```js
const person = {
@ -18,7 +18,7 @@ const person = {
};
```
在 ES6 语法的对象中定义函数的时候,你可以完全删除<code>function</code>关键字和冒号。请看以下例子:
在 ES6 语法的对象中定义函数的时候,你可以完全删除`function`关键字和冒号。请看以下例子:
```js
const person = {
@ -29,71 +29,31 @@ const person = {
};
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
使用以上这种简短的语法,重构在<code>bicycle</code>对象中的<code>setGear</code>函数。
</section>
使用以上这种简短的语法,重构在`bicycle`对象中的`setGear`函数。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: 不应使用<code>function</code>关键字定义方法。
testString: getUserInput => assert(!removeJSComments(code).match(/function/));
- text: <code>setGear</code>应是一个函数。
testString: assert(typeof bicycle.setGear === 'function' && code.match(/setGear\s*\(.+\)\s*\{/));
- text: 执行<code>bicycle.setGear(48)</code>应可以让<code>gear</code>的值变为 48。
testString: assert((new bicycle.setGear(48)).gear === 48);
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
不应使用`function`关键字定义方法。
```js
// change code below this line
const bicycle = {
gear: 2,
setGear: function(newGear) {
this.gear = newGear;
}
};
// change code above this line
bicycle.setGear(3);
console.log(bicycle.gear);
(getUserInput) => assert(!removeJSComments(code).match(/function/));
```
</div>
### After Test
<div id='js-teardown'>
`setGear`应是一个函数。
```js
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
assert(
typeof bicycle.setGear === 'function' && code.match(/setGear\s*\(.+\)\s*\{/)
);
```
</div>
</section>
## Solution
<section id='solution'>
执行`bicycle.setGear(48)`应可以让`gear`的值变为 48。
```js
const bicycle = {
gear: 2,
setGear(newGear) {
this.gear = newGear;
}
};
bicycle.setGear(3);
assert(new bicycle.setGear(48).gear === 48);
```
</section>
# --solutions--

View File

@ -1,13 +1,14 @@
---
id: 587d7b8a367417b2b2512b4f
title: 使用简单字段编写简洁的对象字面量声明
challengeType: 1
forumTopicId: 301225
title: 使用简单字段编写简洁的对象字面量声明
---
## Description
<section id='description'>
# --description--
ES6 添加了一些很棒的功能,以便于更方便地定义对象。
请看以下代码:
```js
@ -17,72 +18,32 @@ const getMousePosition = (x, y) => ({
});
```
<code>getMousePosition</code>是一个返回了拥有2个属性的对象的简单函数。
ES6 提供了一个语法糖,消除了类似<code>x: x</code>这种冗余的写法.你可以仅仅只写一次<code>x</code>,解释器会自动将其转换成<code>x: x</code>
下面是使用这种语法重写的同样的函数:
`getMousePosition`是一个返回了拥有2个属性的对象的简单函数。 ES6 提供了一个语法糖,消除了类似`x: x`这种冗余的写法.你可以仅仅只写一次`x`,解释器会自动将其转换成`x: x`。 下面是使用这种语法重写的同样的函数:
```js
const getMousePosition = (x, y) => ({ x, y });
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
请使用简单属性对象的语法来创建并返回一个<code>Person</code>对象。
</section>
请使用简单属性对象的语法来创建并返回一个`Person`对象。
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: '输出是<code>{name: "Zodiac Hasbro", age: 56, gender: "male"}</code>。'
testString: assert.deepEqual({name:"Zodiac Hasbro",age:56,gender:"male"}, createPerson("Zodiac Hasbro", 56, "male"));
- text: '不要使用<code>key:value</code>。'
testString: getUserInput => assert(!getUserInput('index').match(/:/g));
```
</section>
## Challenge Seed
<section id='challengeSeed'>
<div id='js-seed'>
输出是`{name: "Zodiac Hasbro", age: 56, gender: "male"}`
```js
const createPerson = (name, age, gender) => {
"use strict";
// change code below this line
return {
name: name,
age: age,
gender: gender
};
// change code above this line
};
console.log(createPerson("Zodiac Hasbro", 56, "male")); // returns a proper object
assert.deepEqual(
{ name: 'Zodiac Hasbro', age: 56, gender: 'male' },
createPerson('Zodiac Hasbro', 56, 'male')
);
```
</div>
</section>
## Solution
<section id='solution'>
不要使用`key:value`
```js
const createPerson = (name, age, gender) => {
"use strict";
return {
name,
age,
gender
};
};
(getUserInput) => assert(!getUserInput('index').match(/:/g));
```
</section>
# --solutions--