chore: seed chinese traditional (#42005)

Seeds the chinese traditional files manually so we can deploy to
staging.
This commit is contained in:
Nicholas Carrigan (he/him)
2021-05-05 10:13:49 -07:00
committed by GitHub
parent e46e80e08f
commit 3da4be21bb
1669 changed files with 153114 additions and 678 deletions

View File

@ -0,0 +1,135 @@
---
id: 587d7b87367417b2b2512b40
title: 比較 var 和 let 關鍵字的作用域
challengeType: 1
forumTopicId: 301195
dashedName: compare-scopes-of-the-var-and-let-keywords
---
# --description--
使用 `var` 關鍵字來聲明一個變量的時候,這個變量會被聲明成全局變量,或是函數內的局部變量。
`let` 關鍵字的作用與此類似,但會有一些額外的特性。 如果在代碼塊、語句或表達式中使用關鍵字 `let` 聲明變量,這個變量的作用域就被限制在當前的代碼塊、語句或表達式之中。
舉個例子:
```js
var numArray = [];
for (var i = 0; i < 3; i++) {
numArray.push(i);
}
console.log(numArray);
console.log(i);
```
這裏控制檯將顯示值 `[0, 1, 2]``3`
因爲使用了 `var` 關鍵字,`i` 被聲明爲全局變量。 所以當 `i++` 執行時,它會更新全局變量。 這個代碼和下方的代碼類似:
```js
var numArray = [];
var i;
for (i = 0; i < 3; i++) {
numArray.push(i);
}
console.log(numArray);
console.log(i);
```
這裏控制檯將顯示值 `[0, 1, 2]``3`
如果你創建一個函數,將它存儲起來,稍後在使用 `i` 變量的 `for` 循環中使用。這麼做可能會出現問題。 這是因爲存儲的函數會總是指向更新後的全局 `i` 變量的值。
```js
var printNumTwo;
for (var i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo());
```
這裏控制檯將顯示值 `3`
可以看到,`printNumTwo()` 打印了 3而不是 2。 這是因爲賦值給 `i` 的值已經更新,`printNumTwo()` 返回全局的 `i`,而不是在 for 循環中創建函數時 `i` 的值。 `let` 關鍵字就不會出現這種現象:
```js
let printNumTwo;
for (let i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo());
console.log(i);
```
在這裏控制檯將顯示值 `2` 和一個錯誤提示 `i is not defined`
`i` 未定義,因爲它沒有在全局範圍內聲明。 它只在 `for` 循環語句中被聲明。 `printNumTwo()` 返回了正確的值,因爲 `let` 關鍵字在循環語句中使 `i` 變量產生了三個不同的值(分別爲 0、1、2
# --instructions--
修改這段代碼,使 `if` 語句中聲明的 `i` 變量與在函數的第一行聲明的 `i` 變量是彼此獨立的。 請注意不要在你的代碼的任何地方使用 `var` 關鍵字。
這個練習旨在表明使用 `var``let` 關鍵字聲明變量時作用域之間的區別。 當編寫類似這個練習中的函數的時候,通常來說最好使用不同的變量名,以避免混淆。
# --hints--
代碼中不應該出現 `var`
```js
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
`if` 語句中聲明的變量 `i` 應該等於字符串 `block scope`
```js
(getUserInput) =>
assert(
getUserInput('index').match(/(i\s*=\s*).*\s*.*\s*.*\1('|")block\s*scope\2/g)
);
```
`checkScope()` 應該返回字符串 `function scope`
```js
assert(checkScope() === 'function scope');
```
# --seed--
## --seed-contents--
```js
function checkScope() {
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;
}
```
# --solutions--
```js
function checkScope() {
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;
}
```

View File

@ -0,0 +1,77 @@
---
id: 5cdafbc32913098997531680
title: 通過 resolve 和 reject 完成 Promise
challengeType: 1
forumTopicId: 301196
dashedName: complete-a-promise-with-resolve-and-reject
---
# --description--
Promise 有三個狀態:`pending``fulfilled``rejected`。 上一個挑戰裏創建的 promise 一直阻塞在 `pending` 狀態裏,因爲沒有調用 promise 的完成方法。 Promise 提供的 `resolve``reject` 參數就是用來結束 promise 的。 Promise 成功時調用 `resolve`promise 執行失敗時調用 `reject` 如下文所述,這些方法需要有一個參數。
```js
const myPromise = new Promise((resolve, reject) => {
if(condition here) {
resolve("Promise was fulfilled");
} else {
reject("Promise was rejected");
}
});
```
上面的示例使用字符串作爲這些函數的參數,但參數實際上可以是任何格式。 通常,它可能是一個包含數據的對象,你可以將它放在網站或其他地方。
# --instructions--
使 promise 可以處理成功和失敗情況。 如果 `responseFromServer``true`,調用 `resolve` 方法使 promise 成功。 給 `resolve` 傳遞值爲 `We got the data` 的字符串。 如果 `responseFromServer``false` 使用 `reject` 方法並傳入值爲 `Data not received` 的字符串。
# --hints--
`if` 條件是 `true` 時應該執行 `resolve`
```js
assert(
code.match(/if\s*\(\s*responseFromServer\s*\)\s*{\s*resolve\s*\(\s*('|"|`)We got the data\1\s*\)(\s*|\s*;\s*)}/g)
);
```
`if` 條件是 `false` 時應該執行 `reject`
```js
assert(
code.match(/}\s*else\s*{\s*reject\s*\(\s*('|"|`)Data not received\1\s*\)(\s*|\s*;\s*)}/g)
);
```
# --seed--
## --seed-contents--
```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
}
});
```
# --solutions--
```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");
}
});
```

View File

@ -0,0 +1,55 @@
---
id: 5cdafbb0291309899753167f
title: 創建一個 JavaScript Promise
challengeType: 1
forumTopicId: 301197
dashedName: create-a-javascript-promise
---
# --description--
Promise 是異步編程的一種解決方案 - 它在未來的某時會生成一個值。 任務完成,分執行成功和執行失敗兩種情況。 `Promise` 是構造器函數,需要通過 `new` 關鍵字來創建。 構造器參數是一個函數,該函數有兩個參數 - `resolve``reject`。 通過它們來判斷 promise 的執行結果。 用法如下:
```js
const myPromise = new Promise((resolve, reject) => {
});
```
# --instructions--
創建一個名爲 `makeServerRequest` 的 promise。 給構造器函數傳入 `resolve``reject` 兩個參數。
# --hints--
應該給名爲 `makeServerRequest` 的變量指定一個 promise。
```js
assert(makeServerRequest instanceof Promise);
```
promise 應該接收一個函數做爲參數,該函數應該包含 `resolve``reject` 兩個參數。
```js
assert(
code.match(
/Promise\(\s*(function\s*\(\s*resolve\s*,\s*reject\s*\)\s*{|\(\s*resolve\s*,\s*reject\s*\)\s*=>\s*{)[^}]*}/g
)
);
```
# --seed--
## --seed-contents--
```js
```
# --solutions--
```js
const makeServerRequest = new Promise((resolve, reject) => {
});
```

View File

@ -0,0 +1,73 @@
---
id: 5cddbfd622f1a59093ec611d
title: 創建一個模塊腳本
challengeType: 6
forumTopicId: 301198
dashedName: create-a-module-script
---
# --description--
起初JavaScript 幾乎只在 HTML web 扮演一個很小的角色。 今天,一切不同了,很多網站幾乎全是用 JavaScript 所寫。 爲了讓 JavaScript 更模塊化、更整潔以及更易於維護ES6 引入了在多個 JavaScript 文件之間共享代碼的機制。 它可以導出文件的一部分供其它文件使用,然後在需要它的地方按需導入。 爲了使用這一功能, 需要在 HTML 文檔裏創建一個 `type``module` 的腳本。 例子如下:
```html
<script type="module" src="filename.js"></script>
```
使用了 `module` 類型的腳本可以使用 `import``export` 特性(接下來的挑戰會介紹)。
# --instructions--
給 HTML 文檔添加 `module` 類型的腳本,指定源文件爲 `index.js`
# --hints--
應該創建一個 `script` 標籤。
```js
assert(code.match(/<\s*script[^>]*>\s*<\/\s*script\s*>/g));
```
`script` 標籤應該有一個值爲 `module``type` 屬性。
```js
assert(
code.match(
/<\s*script\s+[^t]*type\s*=\s*('|")module\1[^>]*>\s*<\/\s*script\s*>/g
)
);
```
`script` 標籤的 `src` 屬性應該爲 `index.js`
```js
assert(
code.match(
/<\s*script\s+[^s]*src\s*=\s*('|")index\.js\1[^>]*>\s*<\/\s*script\s*>/g
)
);
```
# --seed--
## --seed-contents--
```html
<html>
<body>
<!-- Only change code below this line -->
<!-- Only change code above this line -->
</body>
</html>
```
# --solutions--
```html
<html>
<body>
<script type="module" src="index.js"></script>
</body>
</html>
```

View File

@ -0,0 +1,63 @@
---
id: 587d7b8c367417b2b2512b58
title: 用 export default 創建一個默認導出
challengeType: 1
forumTopicId: 301199
dashedName: create-an-export-fallback-with-export-default
---
# --description--
`export` 的課程中,你學習了<dfn>命名導出</dfn>語法, 這可以在其他文件中引用一些函數或者變量。
還需要了解另外一種被稱爲<dfn>默認導出</dfn>`export` 的語法。 在文件中只有一個值需要導出的時候,通常會使用這種語法。 它也常常用於給文件或者模塊創建返回值。
下面是使用 `export default` 的例子:
```js
export default function add(x, y) {
return x + y;
}
export default function(x, y) {
return x + y;
}
```
第一個是命名函數,第二個是匿名函數。
`export default` 用於爲模塊或文件聲明一個返回值,在每個文件或者模塊中應當只默認導出一個值。 此外,你不能將 `export default``var``let``const` 同時使用。
# --instructions--
下面的函數應該在這個模塊中返回一個值。 請添加需要的代碼。
# --hints--
正確地使用 `export` 返回值。
```js
assert(
code.match(
/export\s+default\s+function(\s+subtract\s*|\s*)\(\s*x,\s*y\s*\)\s*{/g
)
);
```
# --seed--
## --seed-contents--
```js
function subtract(x, y) {
return x - y;
}
```
# --solutions--
```js
export default function subtract(x, y) {
return x - y;
}
```

View File

@ -0,0 +1,116 @@
---
id: 587d7b8a367417b2b2512b4e
title: 使用模板字面量創建字符串
challengeType: 1
forumTopicId: 301200
dashedName: create-strings-using-template-literals
---
# --description--
模板字符串是 ES6 的另外一項新的功能。 這是一種可以輕鬆構建複雜字符串的方法。
模板字符串可以使用多行字符串和字符串插值功能。
請看以下代碼:
```js
const person = {
name: "Zodiac Hasbro",
age: 56
};
const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;
console.log(greeting);
```
控制檯將顯示字符串 `Hello, my name is Zodiac Hasbro!``I am 56 years old.`
這裏發生了許多事情。 首先,這個例子使用反引號(`` ` ``),而不是引號(`'` 或者 `"`)將字符串括起來。 其次,注意代碼和輸出中的字符串都是多行的。 不需要在字符串中插入 `\n`。 上面使用的 `${variable}` 語法是一個佔位符。 這樣一來,你將不再需要使用 `+` 運算符來連接字符串。 當需要在字符串裏增加變量的時候,你只需要在變量的外面括上 `${` 和 `}`,並將其放在模板字符串裏就可以了。 同樣,你可以在字符串中包含其他表達式,例如 `${a + b}`。 這個新的方式使你可以更靈活地創建複雜的字符串。
# --instructions--
使用模板字符串的反引號的語法創建一個包含條目(`li`)字符串的數組。 每個條目應該是 `result` 對象 `failure` 屬性的數組內的元素,並具有 `class` 屬性,值爲 `text-warning`。 `makeList` 函數應該返回列表項字符串的數組。
使用遍歷方法(可以是任意形式的循環)輸出指定值(如下)。
```js
[
'<li class="text-warning">no-var</li>',
'<li class="text-warning">var-on-top</li>',
'<li class="text-warning">linebreak</li>'
]
```
# --hints--
`failuresList` 應該是一個包含了 `result failure` 信息的數組。
```js
assert(
typeof makeList(result.failure) === 'object' && failuresList.length === 3
);
```
`failuresList` 應該輸出指定的值。
```js
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>`
)
);
```
應使用模板字符串和表達式內插。
```js
(getUserInput) => assert(getUserInput('index').match(/(`.*\${.*}.*`)/));
```
應該使用遍歷。
```js
(getUserInput) =>
assert(getUserInput('index').match(/for|map|reduce|forEach|while/));
```
# --seed--
## --seed-contents--
```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) {
// Only change code below this line
const failureItems = [];
// Only change code above this line
return failureItems;
}
const failuresList = makeList(result.failure);
```
# --solutions--
```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) {
return arr.map(val => `<li class="text-warning">${val}</li>`);
}
const failuresList = makeList(result.failure);
```

View File

@ -0,0 +1,89 @@
---
id: 587d7b87367417b2b2512b41
title: 用 const 關鍵字聲明只讀變量
challengeType: 1
forumTopicId: 301201
dashedName: declare-a-read-only-variable-with-the-const-keyword
---
# --description--
`let` 並不是唯一的新的聲明變量的方式。 在 ES6 裏面,你還可以使用 `const` 關鍵字來聲明變量。
`const` 擁有 `let` 的所有優點,不同的是,通過 `const` 聲明的變量是隻讀的。 這意味着通過 `const` 聲明的變量只能被賦值一次,而不能被再次賦值。
```js
const FAV_PET = "Cats";
FAV_PET = "Dogs";
```
控制檯將由於給 `FAV_PET` 重新賦值而顯示錯誤。
可見,嘗試給用 `const` 聲明的變量重新賦值會報錯。 你應該使用 `const` 關鍵字來聲明所有不打算再次賦值的變量。 這有助於避免給一個常量進行額外的再次賦值。 一個最佳實踐是對所有常量的命名採用全大寫字母,並在單詞之間使用下劃線進行分隔。
**注意:**通常,開發者會用大寫字母作爲常量標識符,用小寫字母或者駝峯命名作爲變量(對象或數組)標識符。 後面的挑戰會涉及到在數組中使用小寫變量標識符。
# --instructions--
改變以下代碼,使得所有的變量都使用 `let``const` 關鍵詞來聲明。 當變量將會改變的時候使用 `let` 關鍵字,當變量要保持常量的時候使用 `const` 關鍵字。 同時,對使用 `const` 聲明的變量按照最佳實踐重命名,變量名中的字母應該都是大寫的。
# --hints--
代碼中不應有 `var`
```js
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
`SENTENCE` 應該是使用 `const` 聲明的常量。
```js
(getUserInput) => assert(getUserInput('index').match(/(const SENTENCE)/g));
```
`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));
```
# --seed--
## --seed-contents--
```js
function printManyTimes(str) {
// Only change code below this line
var sentence = str + " is cool!";
for (var i = 0; i < str.length; i+=2) {
console.log(sentence);
}
// Only change code above this line
}
printManyTimes("freeCodeCamp");
```
# --solutions--
```js
function printManyTimes(str) {
const SENTENCE = str + " is cool!";
for (let i = 0; i < str.length; i+=2) {
console.log(SENTENCE);
}
}
printManyTimes("freeCodeCamp");
```

View File

@ -0,0 +1,91 @@
---
id: 587d7b87367417b2b2512b3f
title: 探索 var 和 let 關鍵字之間的差異
challengeType: 1
forumTopicId: 301202
dashedName: explore-differences-between-the-var-and-let-keywords
---
# --description--
使用 `var` 關鍵字來聲明變量,會出現重複聲明導致變量被覆蓋卻不會報錯的問題。
```js
var camper = 'James';
var camper = 'David';
console.log(camper);
```
這裏控制檯將顯示字符串 `David`
在上面的代碼中,`camper` 變量的初始值爲 `James`,然後又被覆蓋成了 `David`。 在小型的應用中,你可能不會遇到這樣的問題。但是當你的代碼規模變得更加龐大的時候,就可能會在不經意間覆蓋了之前定義的變量。 因爲這樣的情況不會報錯,所以搜索和修復 bug 會變得非常困難。
在 ES6 中引入了新的關鍵字 `let` 來解決 `var` 關鍵字帶來的潛在問題。 如果你在上面的代碼中使用 `let` 關鍵字來代替 `var` 關鍵字,結果會是一個報錯。
```js
let camper = 'James';
let camper = 'David';
```
你可以在瀏覽器的控制檯裏看見這個錯誤。 與 `var` 不同的是,當使用 `let` 的時候,同一名字的變量只能被聲明一次。 請注意 `"use strict"`。 這代表着開啓了嚴格模式,用於檢測常見的代碼錯誤以及“不安全”的行爲, 例如:
```js
"use strict";
x = 3.14;
```
這將顯示一個錯誤 `x is not defined`
# --instructions--
請更新這段代碼,只使用 `let` 關鍵字。
# --hints--
代碼中不應有 `var`
```js
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
`catName` 變量的值應該爲 `Oliver`
```js
assert(catName === 'Oliver');
```
`quote` 變量的值應該爲 `Oliver says Meow!`
```js
assert(quote === 'Oliver says Meow!');
```
# --seed--
## --seed-contents--
```js
var catName;
var quote;
function catTalk() {
"use strict";
catName = "Oliver";
quote = catName + " says Meow!";
}
catTalk();
```
# --solutions--
```js
let catName;
let quote;
function catTalk() {
'use strict';
catName = 'Oliver';
quote = catName + ' says Meow!';
}
catTalk();
```

View File

@ -0,0 +1,92 @@
---
id: 5cdafbd72913098997531681
title: 用 then 處理 Promise 完成的情況
challengeType: 1
forumTopicId: 301203
dashedName: handle-a-fulfilled-promise-with-then
---
# --description--
當程序需要花費未知的時間才能完成時比如一些異步操作一般是服務器請求promise 很有用。 服務器請求會花費一些時間,當結束時,需要根據服務器的響應執行一些操作。 這可以用 `then` 方法來實現, 當 promise 完成 `resolve` 時會觸發 `then` 方法。 例子如下:
```js
myPromise.then(result => {
});
```
`result` 即傳入 `resolve` 方法的參數。
# --instructions--
給 promise 添加 `then` 方法。 用 `result` 做爲回調函數的參數並將 `result` 打印在控制檯。
# --hints--
應該給 promise 方法調用 `then` 方法。
```js
assert(
__helpers.removeWhiteSpace(code).match(/(makeServerRequest|\))\.then\(/g)
);
```
`then` 方法應該有一個回調函數,回調函數參數爲 `result`
```js
assert(resultIsParameter);
```
應該打印 `result` 到控制檯。
```js
assert(
resultIsParameter &&
__helpers
.removeWhiteSpace(code)
.match(/\.then\(.*?result.*?console.log\(result\).*?\)/)
);
```
# --seed--
## --after-user-code--
```js
const resultIsParameter = /\.then\((function\(result\){|result|\(result\)=>)/.test(__helpers.removeWhiteSpace(code));
```
## --seed-contents--
```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");
}
});
```
# --solutions--
```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);
});
```

View File

@ -0,0 +1,100 @@
---
id: 5cdafbe72913098997531682
title: 使用 catch 處理 Promise 失敗的情況
challengeType: 1
forumTopicId: 301204
dashedName: handle-a-rejected-promise-with-catch
---
# --description--
當 promise 失敗時會調用 `catch` 方法。 當 promise 的 `reject` 方法執行時會直接調用。 用法如下:
```js
myPromise.catch(error => {
});
```
`error` 是傳入 `reject` 方法的參數。
# --instructions--
給 promise 添加 `catch` 方法。 用 `error` 作爲回調函數的參數,並把 `error` 打印到控制檯。
# --hints--
應該在 promise 上調用 `catch` 方法。
```js
assert(
__helpers.removeWhiteSpace(code).match(/(makeServerRequest|\))\.catch\(/g)
);
```
`catch` 方法應該有一個回調函數,回調函數參數爲 `error`
```js
assert(errorIsParameter);
```
應該打印 `error` 到控制檯。
```js
assert(
errorIsParameter &&
__helpers
.removeWhiteSpace(code)
.match(/\.catch\(.*?error.*?console.log\(error\).*?\)/)
);
```
# --seed--
## --after-user-code--
```js
const errorIsParameter = /\.catch\((function\(error\){|error|\(error\)=>)/.test(__helpers.removeWhiteSpace(code));
```
## --seed-contents--
```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);
});
```
# --solutions--
```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);
});
```

View File

@ -0,0 +1,48 @@
---
id: 587d7b8d367417b2b2512b59
title: 導入一個默認的導出
challengeType: 1
forumTopicId: 301205
dashedName: import-a-default-export
---
# --description--
在上一個挑戰裏,學習了 `export default` 的用法。 還需要一種 `import` 的語法來導入默認的導出。 在下面的例子裏,`add``math_functions.js` 文件的默認導出。 以下是如何導入它:
```js
import add from "./math_functions.js";
```
這個語法有一處特別的地方, 被導入的 `add` 值沒有被花括號(`{}`)所包圍。 `add` 只是一個變量的名字,對應 `math_functions.js` 文件的任何默認導出值。 在導入默認導出時,可以使用任何名字。
# --instructions--
在下面的代碼中,導入同一目錄中 `math_functions.js` 文件的默認導出。 導入變量的名字爲 `subtract`
# --hints--
應從 `math_functions.js` 中正確導入 `subtract`
```js
assert(code.match(/import\s+subtract\s+from\s+('|")\.\/math_functions\.js\1/g));
```
# --seed--
## --seed-contents--
```js
// Only change code above this line
subtract(7,4);
```
# --solutions--
```js
import subtract from "./math_functions.js";
subtract(7,4);
```

View File

@ -0,0 +1,89 @@
---
id: 587d7b87367417b2b2512b42
title: 改變一個用 const 聲明的數組
challengeType: 1
forumTopicId: 301206
dashedName: mutate-an-array-declared-with-const
---
# --description--
在現代的 JavaScript 裏,`const` 聲明有很多用法。
一些開發者傾向於默認使用 `const` 來聲明所有變量,除非他們打算後續重新給變量賦值, 那麼他們在聲明的時候就會用 `let`
然而,你要注意,對象(包括數組和函數)在使用 `const` 聲明的時候依然是可變的。 使用 `const` 來聲明只會保證變量不會被重新賦值。
```js
const s = [5, 6, 7];
s = [1, 2, 3];
s[2] = 45;
console.log(s);
```
`s = [1, 2, 3]` 會導致一個錯誤。 `console.log` 會顯示值 `[5, 6, 45]`
可以發現,你可以改變對象 `[5, 6, 7]` 本身,而變量 `s` 會指向改變後的數組 `[5, 6, 45]`。 和所有數組一樣,數組 `s` 中的元素是可以被改變的,但是因爲使用了 `const` 關鍵字,你不能使用賦值操作符將變量標識 `s` 指向另外一個數組。
# --instructions--
這裏有一個使用 `const s = [5, 7, 2]` 聲明的數組。 使用對各元素賦值的方法將數組改成 `[2, 5, 7]`
# --hints--
不要替換 `const` 關鍵字。
```js
(getUserInput) => assert(getUserInput('index').match(/const/g));
```
`s` 應該爲常量(使用 `const`)。
```js
(getUserInput) => assert(getUserInput('index').match(/const\s+s/g));
```
不要改變原數組的聲明。
```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]);
```
# --seed--
## --seed-contents--
```js
const s = [5, 7, 2];
function editInPlace() {
// Only change code below this line
// Using s = [2, 5, 7] would be invalid
// Only change code above this line
}
editInPlace();
```
# --solutions--
```js
const s = [5, 7, 2];
function editInPlace() {
s[0] = 2;
s[1] = 5;
s[2] = 7;
}
editInPlace();
```

View File

@ -0,0 +1,104 @@
---
id: 598f48a36c8c40764b4e52b3
title: 防止對象改變
challengeType: 1
forumTopicId: 301207
dashedName: prevent-object-mutation
---
# --description--
通過之前的挑戰可以看出,`const` 聲明並不會真的保護數據不被改變。 爲了確保數據不被改變JavaScript 提供了一個函數 `Object.freeze`
當一個對象被凍結的時候,你不能再對它的屬性再進行增、刪、改的操作。 任何試圖改變對象的操作都會被阻止,卻不會報錯。
```js
let obj = {
name:"FreeCodeCamp",
review:"Awesome"
};
Object.freeze(obj);
obj.review = "bad";
obj.newProp = "Test";
console.log(obj);
```
`obj.review``obj.newProp` 賦值將導致錯誤,控制檯將顯示值 `{ name: "FreeCodeCamp", review: "Awesome" }`
# --instructions--
在這個挑戰中,你將使用 `Object.freeze` 來防止數學常量被改變。 你需要凍結 `MATH_CONSTANTS` 對象,使得沒有人可以改變 `PI` 的值,或增加或刪除屬性。
# --hints--
不要替換 `const` 關鍵字。
```js
(getUserInput) => assert(getUserInput('index').match(/const/g));
```
`MATH_CONSTANTS` 應該爲一個常量(使用 `const`)。
```js
(getUserInput) =>
assert(getUserInput('index').match(/const\s+MATH_CONSTANTS/g));
```
不要改變 `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);
```
# --seed--
## --seed-contents--
```js
function freezeObj() {
const MATH_CONSTANTS = {
PI: 3.14
};
// Only change code below this line
// Only change code above this line
try {
MATH_CONSTANTS.PI = 99;
} catch(ex) {
console.log(ex);
}
return MATH_CONSTANTS.PI;
}
const PI = freezeObj();
```
# --solutions--
```js
function freezeObj() {
const MATH_CONSTANTS = {
PI: 3.14
};
Object.freeze(MATH_CONSTANTS);
try {
MATH_CONSTANTS.PI = 99;
} catch(ex) {
console.log(ex);
}
return MATH_CONSTANTS.PI;
}
const PI = freezeObj();
```

View File

@ -0,0 +1,70 @@
---
id: 587d7b8c367417b2b2512b55
title: 通過 import 複用 JavaScript 代碼
challengeType: 1
forumTopicId: 301208
dashedName: reuse-javascript-code-using-import
---
# --description--
`import` 可以導入文件或模塊的一部分。 在之前的課程裏,例子從 `math_functions.js` 文件裏導出了 `add`。 下面看一下如何在其它文件導入它:
```js
import { add } from './math_functions.js';
```
在這裏,`import` 會在 `math_functions.js` 裏找到 `add`,只導入這個函數,忽略剩餘的部分。 `./` 告訴程序在當前文件的相同目錄尋找 `math_functions.js` 文件。 用這種方式導入時,相對路徑(`./`)和文件擴展名(`.js`)都是必需的。
通過在 `import` 語句裏添加項目,可以從文件裏導入多個項目,如下:
```js
import { add, subtract } from './math_functions.js';
```
# --instructions--
添加 `import` 語句,使當前文件可以使用你在之前課程裏導出的 `uppercaseString``lowercaseString` 函數。 函數在當前路徑下的 `string_functions.js` 文件裏。
# --hints--
應該導入 `uppercaseString`
```js
assert(
code.match(
/import\s*{\s*(uppercaseString[^}]*|[^,]*,\s*uppercaseString\s*)}\s+from\s+('|")\.\/string_functions\.js\2/g
)
);
```
應該導入 `lowercaseString`
```js
assert(
code.match(
/import\s*{\s*(lowercaseString[^}]*|[^,]*,\s*lowercaseString\s*)}\s+from\s+('|")\.\/string_functions\.js\2/g
)
);
```
# --seed--
## --seed-contents--
```js
// Only change code above this line
uppercaseString("hello");
lowercaseString("WORLD!");
```
# --solutions--
```js
import { uppercaseString, lowercaseString } from './string_functions.js';
uppercaseString("hello");
lowercaseString("WORLD!");
```

View File

@ -0,0 +1,64 @@
---
id: 587d7b88367417b2b2512b46
title: 設置函數的默認參數
challengeType: 1
forumTopicId: 301209
dashedName: set-default-parameters-for-your-functions
---
# --description--
ES6 裏允許給函數傳入<dfn>默認參數</dfn>,來構建更加靈活的函數。
請看以下代碼:
```js
const greeting = (name = "Anonymous") => "Hello " + name;
console.log(greeting("John"));
console.log(greeting());
```
控制檯將顯示字符串 `Hello John``Hello Anonymous`
默認參數會在參數沒有被指定(值爲 undefined的時候起作用。 在上面的例子中,參數 `name` 會在沒有得到新的值的時候,默認使用值 `Anonymous`。 你還可以給多個參數賦予默認值。
# --instructions--
給函數 `increment` 加上默認參數,使得在 `value` 沒有被賦值的時候,默認給 `number` 加上 1。
# --hints--
`increment(5, 2)` 的結果應該是 `7`
```js
assert(increment(5, 2) === 7);
```
`increment(5)` 的結果應該是 `6`
```js
assert(increment(5) === 6);
```
參數 `value` 的默認值是 `1`
```js
assert(code.match(/value\s*=\s*1/g));
```
# --seed--
## --seed-contents--
```js
// Only change code below this line
const increment = (number, value) => number + value;
// Only change code above this line
```
# --solutions--
```js
const increment = (number, value = 1) => number + value;
```

View File

@ -0,0 +1,60 @@
---
id: 587d7b8c367417b2b2512b57
title: 用 * 從文件中導入所有內容
challengeType: 1
forumTopicId: 301210
dashedName: use--to-import-everything-from-a-file
---
# --description--
假設你有一個文件,你希望將其所有內容導入到當前文件中。 可以用 `import * as` 語法來實現。 下面是一個從同目錄下的 `math_functions.js` 文件中導入所有內容的例子:
```js
import * as myMathModule from "./math_functions.js";
```
上面的 `import` 語句會創建一個叫作 `myMathModule` 的對象。 這只是一個變量名,可以隨便命名。 對象包含 `math_functions.js` 文件裏的所有導出,可以像訪問對象的屬性那樣訪問裏面的函數。 下面是使用導入的 `add``subtract` 函數的例子:
```js
myMathModule.add(2,3);
myMathModule.subtract(5,3);
```
# --instructions--
下面的代碼需要從同目錄下的 `string_functions.js` 文件中導入所有內容。 使用 `import * as` 語法將文件的所有內容導入對象 `stringFunctions`
# --hints--
正確使用 `import * as` 語法。
```js
assert(
code.match(
/import\s*\*\s*as\s+stringFunctions\s+from\s*('|")\.\/string_functions\.js\1/g
)
);
```
# --seed--
## --seed-contents--
```js
// Only change code above this line
stringFunctions.uppercaseString("hello");
stringFunctions.lowercaseString("WORLD!");
```
# --solutions--
```js
import * as stringFunctions from "./string_functions.js";
// add code above this line
stringFunctions.uppercaseString("hello");
stringFunctions.lowercaseString("WORLD!");
```

View File

@ -0,0 +1,91 @@
---
id: 587d7b87367417b2b2512b43
title: 使用箭頭函數編寫簡潔的匿名函數
challengeType: 1
forumTopicId: 301211
dashedName: use-arrow-functions-to-write-concise-anonymous-functions
---
# --description--
在 JavaScript 裏,我們會經常遇到不需要給函數命名的情況,尤其是在需要將一個函數作爲參數傳給另外一個函數的時候。 這時,我們會創建匿名函數。 因爲這些函數不會在其他地方複用,所以我們不需要給它們命名。
這種情況下,我們通常會使用以下語法:
```js
const myFunc = function() {
const myVar = "value";
return myVar;
}
```
ES6 提供了其他寫匿名函數的方式的語法糖。 你可以使用**箭頭函數**
```js
const myFunc = () => {
const myVar = "value";
return myVar;
}
```
當不需要函數體,只返回一個值的時候,箭頭函數允許你省略 `return` 關鍵字和外面的大括號。 這樣就可以將一個簡單的函數簡化成一個單行語句。
```js
const myFunc = () => "value";
```
這段代碼默認會返回字符串 `value`
# --instructions--
使用箭頭函數的語法重寫賦給 `magic` 變量的函數,使其返回一個新的 Date() `new Date()`。 同時不要用 `var` 關鍵字來定義任何變量。
# --hints--
應該替換 `var` 關鍵字。
```js
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
`magic` 應該爲一個常量(使用 `const`)。
```js
(getUserInput) => assert(getUserInput('index').match(/const\s+magic/g));
```
`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));
```
# --seed--
## --seed-contents--
```js
var magic = function() {
return new Date();
};
```
# --solutions--
```js
const magic = () => {
return new Date();
};
```

View File

@ -0,0 +1,100 @@
---
id: 587d7b8b367417b2b2512b53
title: 使用 class 語法定義構造函數
challengeType: 1
forumTopicId: 301212
dashedName: use-class-syntax-to-define-a-constructor-function
---
# --description--
ES6 提供了一個新的創建對象的語法,使用關鍵字 <dfn>class</dfn>
值得注意的是,`class` 只是一個語法糖,它並不像 Java、Python 或者 Ruby 這一類的語言一樣,嚴格履行了面向對象的開發規範。
在 ES5 裏面,我們通常會定義一個構造函數 `constructor`,然後使用 `new` 關鍵字來實例化一個對象:
```js
var SpaceShuttle = function(targetPlanet){
this.targetPlanet = targetPlanet;
}
var zeus = new SpaceShuttle('Jupiter');
```
`class` 語法只是簡單地替換了構造函數 `constructor` 的寫法:
```js
class SpaceShuttle {
constructor(targetPlanet) {
this.targetPlanet = targetPlanet;
}
}
const zeus = new SpaceShuttle('Jupiter');
```
應該注意 `class` 關鍵字聲明瞭一個新的函數,裏面添加了一個構造函數。 當用 `new` 創建一個新的對象時,構造函數會被調用。
**注意:**首字母大寫駝峯命名法 UpperCamelCase 是 ES6 class 命名的慣例,就像上面的 `SpaceShuttle`
`constructor` 方法是一個特殊方法,用於創建和初始化 class 創建的對象。 在 JavaScript 算法和數據結構認證的面向對象編程章節裏會更深入介紹它。
# --instructions--
使用 `class` 關鍵詞,寫一個 `constructor` 來創建 `Vegetable` class。
`Vegetable` 這個 class 可以創建 vegetable 對象,這個對象擁有一個在 `constructor` 中賦值的 `name` 屬性。
# --hints--
`Vegetable` 應該是一個 `class`,並在其中定義了 `constructor`
```js
assert(
typeof Vegetable === 'function' && typeof Vegetable.constructor === 'function'
);
```
應使用 `class` 關鍵字。
```js
assert(code.match(/class/g));
```
`Vegetable` 可以被實例化。
```js
assert(() => {
const a = new Vegetable('apple');
return typeof a === 'object';
});
```
`carrot.name` 應該返回 `carrot`
```js
assert(carrot.name == 'carrot');
```
# --seed--
## --seed-contents--
```js
// Only change code below this line
// Only change code above this line
const carrot = new Vegetable('carrot');
console.log(carrot.name); // Should display 'carrot'
```
# --solutions--
```js
class Vegetable {
constructor(name) {
this.name = name;
}
}
const carrot = new Vegetable('carrot');
```

View File

@ -0,0 +1,71 @@
---
id: 587d7b89367417b2b2512b4b
title: 使用解構賦值從數組中分配變量
challengeType: 1
forumTopicId: 301213
dashedName: use-destructuring-assignment-to-assign-variables-from-arrays
---
# --description--
在 ES6 裏面,解構數組可以如同解構對象一樣簡單。
與數組解構不同,數組的擴展運算會將數組裏的所有內容分解成一個由逗號分隔的列表。 所以,你不能選擇哪個元素來給變量賦值。
而對數組進行解構卻可以讓我們做到這一點:
```js
const [a, b] = [1, 2, 3, 4, 5, 6];
console.log(a, b);
```
控制檯將顯示 `a``b` 的值爲 `1, 2`
數組的第一個值被賦值給變量 `a`,數組的第二個值被賦值給變量 `b`。 我們甚至能在數組解構中使用逗號分隔符,來獲取任意一個想要的值:
```js
const [a, b,,, c] = [1, 2, 3, 4, 5, 6];
console.log(a, b, c);
```
控制檯將顯示 `a``b``c` 的值爲 `1, 2, 5`
# --instructions--
使用數組解構來交換變量 `a``b` 的值,使 `a` 接收 `b` 的值,而 `b` 接收 `a` 的值。
# --hints--
交換後,`a` 的值應該爲 `6`
```js
assert(a === 6);
```
交換後,`b` 的值應該爲 `8`
```js
assert(b === 8);
```
應使用數組解構來交換 `a``b` 的值。
```js
assert(/\[\s*(\w)\s*,\s*(\w)\s*\]\s*=\s*\[\s*\2\s*,\s*\1\s*\]/g.test(code));
```
# --seed--
## --seed-contents--
```js
let a = 8, b = 6;
// Only change code below this line
```
# --solutions--
```js
let a = 8, b = 6;
[a, b] = [b, a];
```

View File

@ -0,0 +1,106 @@
---
id: 587d7b89367417b2b2512b4a
title: 使用解構賦值從嵌套對象中分配變量
challengeType: 1
forumTopicId: 301214
dashedName: use-destructuring-assignment-to-assign-variables-from-nested-objects
---
# --description--
你可以使用前兩節課程中相同的原則來解構嵌套對象中的值。
使用與前面的例子中類似的對象:
```js
const user = {
johnDoe: {
age: 34,
email: 'johnDoe@freeCodeCamp.com'
}
};
```
這是解構對象的屬性值賦值給具有相同名字的變量:
```js
const { johnDoe: { age, email }} = user;
```
這是將對象的屬性值賦值給具有不同名字的變量:
```js
const { johnDoe: { age: userAge, email: userEmail }} = user;
```
# --instructions--
將兩個賦值語句替換成等價的解構賦值。 `lowToday``highToday` 應該爲 `LOCAL_FORECAST``today.low``today.high` 的值。
# --hints--
不能使用 ES5 的賦值語句。
```js
assert(
!code.match(/lowToday = LOCAL_FORECAST\.today\.low/g) &&
!code.match(/highToday = LOCAL_FORECAST\.today.high/g)
);
```
應該使用解構創建 `lowToday` 變量。
```js
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
)
);
```
應該使用解構創建 `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
)
);
```
`lowToday` 應等於 `64``highToday` 應等於 `77`
```js
assert(lowToday === 64 && highToday === 77);
```
# --seed--
## --seed-contents--
```js
const LOCAL_FORECAST = {
yesterday: { low: 61, high: 75 },
today: { low: 64, high: 77 },
tomorrow: { low: 68, high: 80 }
};
// Only change code below this line
const lowToday = LOCAL_FORECAST.today.low;
const highToday = LOCAL_FORECAST.today.high;
// Only change code above this line
```
# --solutions--
```js
const LOCAL_FORECAST = {
yesterday: { low: 61, high: 75 },
today: { low: 64, high: 77 },
tomorrow: { low: 68, high: 80 }
};
const { today: { low: lowToday, high: highToday }} = LOCAL_FORECAST;
```

View File

@ -0,0 +1,97 @@
---
id: 587d7b89367417b2b2512b49
title: 使用解構賦值從對象中分配變量
challengeType: 1
forumTopicId: 301215
dashedName: use-destructuring-assignment-to-assign-variables-from-objects
---
# --description--
可以給解構的值賦予一個新的變量名, 通過在賦值的時候將新的變量名放在冒號後面來實現。
還是以上個例子的對象來舉例:
```js
const user = { name: 'John Doe', age: 34 };
```
這是指定新的變量名的例子:
```js
const { name: userName, age: userAge } = user;
```
你可以這麼理解這段代碼:獲取 `user.name` 的值,將它賦給一個新的變量 `userName`,等等。 `userName` 的值將是字符串 `John Doe``userAge` 的值將是數字 `34`
# --instructions--
使用解構賦值語句替換兩個賦值語句。 將 `HIGH_TEMPERATURES``today``tomorrow` 的值賦值給 `highToday``highTomorrow`
# --hints--
應該移除 ES5 賦值語句。
```js
assert(
!code.match(/highToday = HIGH_TEMPERATURES\.today/g) &&
!code.match(/highTomorrow = HIGH_TEMPERATURES\.tomorrow/g)
);
```
應該使用解構賦值語句創建 `highToday` 變量。
```js
assert(
code.match(
/(var|const|let)\s*{\s*(today\s*:\s*highToday[^}]*|[^,]*,\s*today\s*:\s*highToday\s*)}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g
)
);
```
應該使用解構賦值語句創建 `highTomorrow` 變量。
```js
assert(
code.match(
/(var|const|let)\s*{\s*(tomorrow\s*:\s*highTomorrow[^}]*|[^,]*,\s*tomorrow\s*:\s*highTomorrow\s*)}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g
)
);
```
`highToday` 應該等於 `77``highTomorrow` 應該等於 `80`
```js
assert(highToday === 77 && highTomorrow === 80);
```
# --seed--
## --seed-contents--
```js
const HIGH_TEMPERATURES = {
yesterday: 75,
today: 77,
tomorrow: 80
};
// Only change code below this line
const highToday = HIGH_TEMPERATURES.today;
const highTomorrow = HIGH_TEMPERATURES.tomorrow;
// Only change code above this line
```
# --solutions--
```js
const HIGH_TEMPERATURES = {
yesterday: 75,
today: 77,
tomorrow: 80
};
const { today: highToday, tomorrow: highTomorrow } = HIGH_TEMPERATURES;
```

View File

@ -0,0 +1,101 @@
---
id: 5cfa550e84205a357704ccb6
title: 使用解構賦值來獲取對象的值
challengeType: 1
forumTopicId: 301216
dashedName: use-destructuring-assignment-to-extract-values-from-objects
---
# --description--
<dfn>解構賦值</dfn>是 ES6 引入的新語法,用來從數組和對象中提取值,並優雅地對變量進行賦值。
有如下 ES5 代碼:
```js
const user = { name: 'John Doe', age: 34 };
const name = user.name;
const age = user.age;
```
`name` 的值應該是字符串 `John Doe` `age` 的值應該是數字 `34`
下面是使用 ES6 解構賦值語句,實現相同效果:
```js
const { name, age } = user;
```
同樣,`name` 的值應該是字符串 `John Doe` `age` 的值應該是數字 `34`
在這裏,自動創建 `name``age` 變量,並將 `user` 對象相應屬性的值賦值給它們。 這個方法簡潔多了。
你可以從對象中提取儘可能多或很少的值。
# --instructions--
把兩個賦值語句替換成效果相同的解構賦值語句。 `today``tomorrow` 的值應該還是 `HIGH_TEMPERATURES` 對象中 `today``tomorrow` 屬性的值。
# --hints--
應該移除 ES5 賦值語句。
```js
assert(
!code.match(/today\s*=\s*HIGH_TEMPERATURES\.(today|tomorrow)/g)
);
```
應該使用解構賦值創建 `today` 變量。
```js
assert(
code.match(/(var|let|const)\s*{\s*(today[^}]*|[^,]*,\s*today)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g)
);
```
應該使用解構賦值創建 `tomorrow` 變量。
```js
assert(
code.match(/(var|let|const)\s*{\s*(tomorrow[^}]*|[^,]*,\s*tomorrow)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g)
);
```
`today` 應該等於 `77``tomorrow` 應該等於 `80`
```js
assert(today === 77 && tomorrow === 80);
```
# --seed--
## --seed-contents--
```js
const HIGH_TEMPERATURES = {
yesterday: 75,
today: 77,
tomorrow: 80
};
// Only change code below this line
const today = HIGH_TEMPERATURES.today;
const tomorrow = HIGH_TEMPERATURES.tomorrow;
// Only change code above this line
```
# --solutions--
```js
const HIGH_TEMPERATURES = {
yesterday: 75,
today: 77,
tomorrow: 80
};
const { today, tomorrow } = HIGH_TEMPERATURES;
```

View File

@ -0,0 +1,94 @@
---
id: 587d7b8a367417b2b2512b4d
title: 使用解構賦值將對象作爲函數的參數傳遞
challengeType: 1
forumTopicId: 301217
dashedName: use-destructuring-assignment-to-pass-an-object-as-a-functions-parameters
---
# --description--
在某些情況下,你可以在函數的參數裏直接解構對象。
請看以下代碼:
```js
const profileUpdate = (profileData) => {
const { name, age, nationality, location } = profileData;
}
```
上面的操作解構了傳給函數的對象。 這樣的操作也可以直接在參數裏完成:
```js
const profileUpdate = ({ name, age, nationality, location }) => {
}
```
`profileData` 被傳遞到上面的函數時,從函數參數中解構出值以在函數內使用。
# --instructions--
`half` 的參數進行解構賦值,僅將 `max``min` 的值傳進函數。
# --hints--
`stats` 的類型應該是一個 `object`
```js
assert(typeof stats === 'object');
```
`half(stats)` 應該等於 `28.015`
```js
assert(half(stats) === 28.015);
```
應該使用解構賦值。
```js
assert(__helpers.removeWhiteSpace(code).match(/half=\({\w+,\w+}\)/));
```
應該使用解構參數。
```js
assert(!code.match(/stats\.max|stats\.min/));
```
# --seed--
## --seed-contents--
```js
const stats = {
max: 56.78,
standard_deviation: 4.34,
median: 34.54,
mode: 23.87,
min: -0.75,
average: 35.85
};
// Only change code below this line
const half = (stats) => (stats.max + stats.min) / 2.0;
// Only change code above this line
```
# --solutions--
```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;
```

View File

@ -0,0 +1,85 @@
---
id: 587d7b8a367417b2b2512b4c
title: >-
使用解構賦值配合 rest 操作符來重新分配數組元素
challengeType: 1
forumTopicId: 301218
dashedName: >-
use-destructuring-assignment-with-the-rest-parameter-to-reassign-array-elements
---
# --description--
在解構數組的某些情況下,我們可能希望將剩下的元素放進另一個數組裏面。
以下代碼的結果與使用 `Array.prototype.slice()` 類似:
```js
const [a, b, ...arr] = [1, 2, 3, 4, 5, 7];
console.log(a, b);
console.log(arr);
```
控制檯將顯示 `1, 2``[3, 4, 5, 7]`
變量 `a``b` 分別接收數組的第一個和第二個值。 之後,因爲 rest 操作符的存在,`arr` 獲取了原數組剩餘的元素的值。 rest 操作符只能對數組列表最後的元素起作用。 這意味着你不能使用 rest 操作符來截取原數組中間的元素作爲子數組。
# --instructions--
使用解構賦值以及 rest 操作符來進行和 `Array.prototype.slice()` 相同的操作,使 `arr` 是原數組 `source` 除開前兩個元素的子數組。
# --hints--
`arr` 應該是 `[3,4,5,6,7,8,9,10]`
```js
assert(arr.every((v, i) => v === i + 3) && arr.length === 8);
```
`source` 應該是 `[1,2,3,4,5,6,7,8,9,10]`
```js
assert(source.every((v, i) => v === i + 1) && source.length === 10);
```
不應該使用 `Array.slice()`
```js
(getUserInput) => assert(!getUserInput('index').match(/slice/g));
```
應該對 `list` 進行解構賦值。
```js
assert(
__helpers
.removeWhiteSpace(code)
.match(/\[(([_$a-z]\w*)?,){1,}\.\.\.arr\]=list/i)
);
```
# --seed--
## --seed-contents--
```js
const source = [1,2,3,4,5,6,7,8,9,10];
function removeFirstTwo(list) {
// Only change code below this line
const arr = list; // Change this line
// Only change code above this line
return arr;
}
const arr = removeFirstTwo(source);
```
# --solutions--
```js
const source = [1,2,3,4,5,6,7,8,9,10];
function removeFirstTwo(list) {
const [, , ...arr] = list;
return arr;
}
const arr = removeFirstTwo(source);
```

View File

@ -0,0 +1,85 @@
---
id: 587d7b8c367417b2b2512b56
title: 用 export 來重用代碼塊
challengeType: 1
forumTopicId: 301219
dashedName: use-export-to-share-a-code-block
---
# --description--
假設有一個文件 `math_functions.js`,該文件包含了數學運算相關的一些函數。 其中一個存儲在變量 `add` 裏,該函數接受兩個數字作爲參數返回它們的和。 你想在幾個不同的 JavaScript 文件中使用這個函數。 要實現這個目的,就需要 `export` 它。
```js
export const add = (x, y) => {
return x + y;
}
```
上面是導出單個函數常用方法,還可以這樣導出:
```js
const add = (x, y) => {
return x + y;
}
export { add };
```
導出變量和函數後,就可以在其它文件裏導入使用從而避免了代碼冗餘。 重複第一個例子的代碼可以導出多個對象或函數,在第二個例子裏面的導出語句中添加更多值也可以導出多項,例子如下:
```js
export { add, subtract };
```
# --instructions--
編輯框中有兩個字符串相關的函數。 選用一種方法導出兩個函數。
# --hints--
應該導出 `uppercaseString` 變量。
```js
assert(
code.match(
/(export\s+const\s+uppercaseString|export\s*{\s*(uppercaseString[^}]*|[^,]*,\s*uppercaseString\s*)})/g
)
);
```
應該導出 `lowercaseString` 變量。
```js
assert(
code.match(
/(export\s+const\s+lowercaseString|export\s*{\s*(lowercaseString[^}]*|[^,]*,\s*lowercaseString\s*)})/g
)
);
```
# --seed--
## --seed-contents--
```js
const uppercaseString = (string) => {
return string.toUpperCase();
}
const lowercaseString = (string) => {
return string.toLowerCase()
}
```
# --solutions--
```js
export const uppercaseString = (string) => {
return string.toUpperCase();
}
export const lowercaseString = (string) => {
return string.toLowerCase()
}
```

View File

@ -0,0 +1,174 @@
---
id: 587d7b8c367417b2b2512b54
title: 使用 getter 和 setter 來控制對象的訪問
challengeType: 1
forumTopicId: 301220
dashedName: use-getters-and-setters-to-control-access-to-an-object
---
# --description--
你可以從對象中獲得一個值,也可以給對象的屬性賦值。
這些操作通常被稱爲 <dfn>getters</dfn> 以及 <dfn>setters</dfn>
Getter 函數的作用是可以讓對象返回一個私有變量,而不需要直接去訪問私有變量。
Setter 函數的作用是可以基於傳進的參數來修改對象中私有變量。 這些修改可以是計算,或者是直接替換之前的值。
```js
class Book {
constructor(author) {
this._author = author;
}
// getter
get writer() {
return this._author;
}
// setter
set writer(updatedAuthor) {
this._author = updatedAuthor;
}
}
const novel = new Book('anonymous');
console.log(novel.writer);
novel.writer = 'newAuthor';
console.log(novel.writer);
```
控制檯將顯示字符串 `anonymous``newAuthor`
請注意用於調用 getter 和 setter 的語法。 它們甚至看起來不像是函數。 getter 和 setter 非常重要,因爲它們隱藏了內部的實現細節。
**注意:**通常會在私有變量前添加下劃線(`_`)。 然而,這種做法本身並不是將變量變成私有的。
# --instructions--
使用 `class` 關鍵字創建一個 `Thermostat` class。 `constructor` 接收一個華氏溫度。
在 class 中,創建一個 `getter` 來獲取攝氏溫度和一個 `setter` 來設置溫度值。
記得在 `C = 5/9 * (F - 32)``F = C * 9.0 / 5 + 32` 中,`F` 是華氏溫度值,`C` 是攝氏溫度值。
**注意:**完成這個挑戰後,應該在 class 中使用一個溫度標準,要麼是華氏溫度,要麼是攝氏溫度。
這就是 getter 和 setter 的功能。 你正在爲別的用戶創建一個 API不論你使用哪一個用戶都將獲得正確的結果。
或者說,你從用戶需求中抽象出了實現細節。
# --hints--
`Thermostat` 應該是一個具有 `constructor` 方法的 `class`
```js
assert(
typeof Thermostat === 'function' &&
typeof Thermostat.constructor === 'function'
);
```
應該使用 `class` 關鍵詞。
```js
assert(code.match(/class/g));
```
`Thermostat` 應該可以被實例化。
```js
assert(
(() => {
const t = new Thermostat(122);
return typeof t === 'object';
})()
);
```
當實例化華氏溫度值時,`Thermostat` 應該被設置爲正確的 `temperature`
```js
assert(
(() => {
const t = new Thermostat(122);
return t.temperature === 50;
})()
);
```
應該定義一個 `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;
const u = new Thermostat(32);
u.temperature = 50;
return t.temperature === 26 && u.temperature === 50;
})()
);
```
# --seed--
## --seed-contents--
```js
// Only change code below this line
// Only change code above this line
const thermos = new Thermostat(76); // Setting in Fahrenheit scale
let temp = thermos.temperature; // 24.44 in Celsius
thermos.temperature = 26;
temp = thermos.temperature; // 26 in Celsius
```
# --solutions--
```js
class Thermostat {
constructor(fahrenheit) {
this._tempInCelsius = 5/9 * (fahrenheit - 32);
}
get temperature(){
return this._tempInCelsius;
}
set temperature(newTemp){
this._tempInCelsius = newTemp;
}
}
const thermos = new Thermostat(76); // Setting in Fahrenheit scale
let temp = thermos.temperature; // 24.44 in Celsius
thermos.temperature = 26;
temp = thermos.temperature; // 26 in Celsius
```

View File

@ -0,0 +1,80 @@
---
id: 587d7b88367417b2b2512b47
title: 將 rest 操作符與函數參數一起使用
challengeType: 1
forumTopicId: 301221
dashedName: use-the-rest-parameter-with-function-parameters
---
# --description--
ES6 推出了用於函數參數的 <dfn>rest 操作符</dfn>幫助我們創建更加靈活的函數。 rest 操作符可以用於創建有一個變量來接受多個參數的函數。 這些參數被儲存在一個可以在函數內部讀取的數組中。
請看以下代碼:
```js
function howMany(...args) {
return "You have passed " + args.length + " arguments.";
}
console.log(howMany(0, 1, 2));
console.log(howMany("string", null, [1, 2, 3], { }));
```
控制檯將顯示字符串 `You have passed 3 arguments.``You have passed 4 arguments.`
使用 rest 參數,就不需要查看 `args` 數組,並且允許我們在參數數組上使用 `map()``filter()``reduce()`
# --instructions--
修改 `sum` 函數,使用 rest 參數,使 `sum` 函數可以接收任意數量的參數,並返回它們的總和。
# --hints--
`sum(0,1,2)` 的結果應是 3。
```js
assert(sum(0, 1, 2) === 3);
```
`sum(1,2,3,4)` 的結果應是 10。
```js
assert(sum(1, 2, 3, 4) === 10);
```
`sum(5)` 的結果應是 5。
```js
assert(sum(5) === 5);
```
`sum()` 的結果應是 0。
```js
assert(sum() === 0);
```
`sum` 應是一個箭頭函數,對 `args` 參數使用 rest 操作符語法(`...`)。
```js
assert(__helpers.removeWhiteSpace(code).match(/sum=\(\.\.\.args\)=>/));
```
# --seed--
## --seed-contents--
```js
const sum = (x, y, z) => {
const args = [x, y, z];
return args.reduce((a, b) => a + b, 0);
}
```
# --solutions--
```js
const sum = (...args) => {
return args.reduce((a, b) => a + b, 0);
}
```

View File

@ -0,0 +1,84 @@
---
id: 587d7b89367417b2b2512b48
title: 使用 spread 運算符展開數組項
challengeType: 1
forumTopicId: 301222
dashedName: use-the-spread-operator-to-evaluate-arrays-in-place
---
# --description--
ES6 引入了<dfn>展開操作符</dfn>,可以展開數組以及需要多個參數或元素的表達式。
下面的 ES5 代碼使用了 `apply()` 來計算數組的最大值:
```js
var arr = [6, 89, 3, 45];
var maximus = Math.max.apply(null, arr);
```
`maximus` 的值爲 `89`
我們必須使用 `Math.max.apply(null, arr)`,因爲 `Math.max(arr)` 返回 `NaN``Math.max()` 函數中需要傳入的是一系列由逗號分隔的參數,而不是一個數組。 展開操作符可以提升代碼的可讀性,使代碼易於維護。
```js
const arr = [6, 89, 3, 45];
const maximus = Math.max(...arr);
```
`maximus` 的值應該是 `89`
`...arr` 返回一個解壓的數組。 也就是說,它*展開*數組。 然而,展開操作符只能夠在函數的參數中或者數組中使用。 下面的代碼將會報錯:
```js
const spreaded = ...arr;
```
# --instructions--
使用展開操作符將 `arr1` 中的內容都複製到 `arr2` 中去。
# --hints--
`arr2` 應該是從 `arr1` 複製而來。
```js
assert(arr2.every((v, i) => v === arr1[i]) && arr2.length);
```
應使用展開操作符 `...` 來複制 `arr1`
```js
assert(code.match(/Array\(\s*\.\.\.arr1\s*\)|\[\s*\.\.\.arr1\s*\]/));
```
`arr1` 改變的時候,`arr2` 應保持不變。
```js
assert((arr1, arr2) => {
arr1.push('JUN');
return arr2.length < arr1.length;
});
```
# --seed--
## --seed-contents--
```js
const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];
let arr2;
arr2 = []; // Change this line
console.log(arr2);
```
# --solutions--
```js
const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];
let arr2;
arr2 = [...arr1];
```

View File

@ -0,0 +1,94 @@
---
id: 587d7b88367417b2b2512b44
title: 編寫帶參數的箭頭函數
challengeType: 1
forumTopicId: 301223
dashedName: write-arrow-functions-with-parameters
---
# --description--
和一般的函數一樣,你也可以給箭頭函數傳遞參數。
```js
const doubler = (item) => item * 2;
doubler(4);
```
`doubler(4)` 將返回 `8`
如果箭頭函數只有一個參數,則可以省略參數外面的括號。
```js
const doubler = item => item * 2;
```
可以給箭頭函數傳遞多個參數。
```js
const multiplier = (item, multi) => item * multi;
multiplier(4, 2);
```
`multiplier(4, 2)` 將返回 `8`
# --instructions--
使用箭頭函數的語法重寫 `myConcat` 函數,將 `arr2` 的內容添加到 `arr1`
# --hints--
應替換 `var` 關鍵詞。
```js
(getUserInput) => assert(!getUserInput('index').match(/var/g));
```
`myConcat` 應該是一個常量(使用`const`)。
```js
(getUserInput) => assert(getUserInput('index').match(/const\s+myConcat/g));
```
`myConcat` 應該是一個帶有兩個參數的箭頭函數。
```js
assert(
/myConcat=\(\w+,\w+\)=>/.test(code.replace(/\s/g, '')) &&
typeof myConcat === 'function'
);
```
`myConcat()` 應該返回 `[1, 2, 3, 4, 5]`
```js
assert.deepEqual(myConcat([1, 2], [3, 4, 5]), [1, 2, 3, 4, 5]);
```
不能使用 `function` 關鍵字。
```js
(getUserInput) => assert(!getUserInput('index').match(/function/g));
```
# --seed--
## --seed-contents--
```js
var myConcat = function(arr1, arr2) {
return arr1.concat(arr2);
};
console.log(myConcat([1, 2], [3, 4, 5]));
```
# --solutions--
```js
const myConcat = (arr1, arr2) => {
return arr1.concat(arr2);
};
console.log(myConcat([1, 2], [3, 4, 5]));
```

View File

@ -0,0 +1,86 @@
---
id: 587d7b8b367417b2b2512b50
title: 用 ES6 編寫簡潔的函數聲明
challengeType: 1
forumTopicId: 301224
dashedName: write-concise-declarative-functions-with-es6
---
# --description--
在 ES5 中,當我們需要在對象中定義一個函數的時候,必須像這樣使用 `function` 關鍵字:
```js
const person = {
name: "Taylor",
sayHello: function() {
return `Hello! My name is ${this.name}.`;
}
};
```
用 ES6 的語法在對象中定義函數的時候,可以刪除 `function` 關鍵詞和冒號。 請看以下例子:
```js
const person = {
name: "Taylor",
sayHello() {
return `Hello! My name is ${this.name}.`;
}
};
```
# --instructions--
使用以上這種簡短的語法,重構在 `bicycle` 對象中的 `setGear` 函數。
# --hints--
不應使用傳統的函數定義方法。
```js
(getUserInput) => assert(!code.match(/function/));
```
`setGear` 應是一個聲明函數。
```js
assert(
typeof bicycle.setGear === 'function' && code.match(/setGear\s*\(.+\)\s*\{/)
);
```
`bicycle.setGear(48)` 應將 `gear` 的值改爲 48。
```js
assert(new bicycle.setGear(48).gear === 48);
```
# --seed--
## --seed-contents--
```js
// Only change code below this line
const bicycle = {
gear: 2,
setGear: function(newGear) {
this.gear = newGear;
}
};
// Only change code above this line
bicycle.setGear(3);
console.log(bicycle.gear);
```
# --solutions--
```js
const bicycle = {
gear: 2,
setGear(newGear) {
this.gear = newGear;
}
};
bicycle.setGear(3);
```

View File

@ -0,0 +1,75 @@
---
id: 587d7b8a367417b2b2512b4f
title: 使用簡單字段編寫簡潔的對象字面量聲明
challengeType: 1
forumTopicId: 301225
dashedName: write-concise-object-literal-declarations-using-object-property-shorthand
---
# --description--
ES6 添加了一些很棒的功能,用於更方便地定義對象。
請看以下代碼:
```js
const getMousePosition = (x, y) => ({
x: x,
y: y
});
```
`getMousePosition` 簡單的函數,返回擁有兩個屬性的對象。 ES6 提供了一個語法糖,消除了類似 `x: x` 這種冗餘的寫法。 你可以只寫一次 `x`,解釋器會自動將其轉換成 `x: x`(或效果相同的內容)。 下面是使用這種語法重寫的同樣的函數:
```js
const getMousePosition = (x, y) => ({ x, y });
```
# --instructions--
請使用簡單屬性對象的語法來創建並返回一個具有 `name``age``gender` 屬性的對象。
# --hints--
`createPerson("Zodiac Hasbro", 56, "male")` 應該返回 `{name: "Zodiac Hasbro", age: 56, gender: "male"}`
```js
assert.deepEqual(
{ name: 'Zodiac Hasbro', age: 56, gender: 'male' },
createPerson('Zodiac Hasbro', 56, 'male')
);
```
不要使用 `key:value`
```js
(getUserInput) => assert(!getUserInput('index').match(/:/g));
```
# --seed--
## --seed-contents--
```js
const createPerson = (name, age, gender) => {
// Only change code below this line
return {
name: name,
age: age,
gender: gender
};
// Only change code above this line
};
```
# --solutions--
```js
const createPerson = (name, age, gender) => {
return {
name,
age,
gender
};
};
```