...
 
Commits (4)
    https://gitcode.net/OpenDocCN/impatient-js-zh/-/commit/25b80784fbea4f688d143fb3b8ef0e38cf69c109 Update CONTRIBUTING.md 2022-07-03T18:56:08+08:00 布客飞龙 562826179@qq.com https://gitcode.net/OpenDocCN/impatient-js-zh/-/commit/618593e35c7619bf533e6c84abb8fe0d229f82d9 2022-07-05 09:55:58 2022-07-05T09:55:58+08:00 wizardforcel 562826179@qq.com https://gitcode.net/OpenDocCN/impatient-js-zh/-/commit/5fdd2ed606ab6369e25ebb57003157cc25cef57d Add files via upload 2022-07-17T11:38:12+08:00 布客飞龙 admin@flygon.net https://gitcode.net/OpenDocCN/impatient-js-zh/-/commit/7714585fe6d06ad496bb123ab59a3a9661f8742a Update README.md 2022-07-17T11:38:22+08:00 布客飞龙 562826179@qq.com
...@@ -6,78 +6,118 @@ ...@@ -6,78 +6,118 @@
+ 飞龙:562826179 + 飞龙:562826179
## 章节列表 ## 有用的链接
+ [1.关于本书(ES2019 版)](docs/2.md) + [ApacheCN 文档导航](https://docs.apachecn.org/)
+ [2.常见问题:本书](docs/3.md) + [谷歌翻译](https://translate.google.cn/)
+ [3\. JavaScript 的历史和演变](docs/4.md) + [ApacheCN 校对活动参与手册](https://github.com/apachecn/home/blob/master/docs/translate/joining-guide.md)
+ [4.常见问题:JavaScript](docs/5.md) + [译后编辑](https://www.bing.com/search?q=%E8%AF%91%E5%90%8E%E7%BC%96%E8%BE%91&mkt=zh-CN)
+ [5.概览](docs/7.md) + [当翻译竟然变成了文本编辑——李笑来](https://zhuanlan.zhihu.com/p/465979584)
+ [6.语法](docs/8.md) + [翻译引擎易错术语列表(欢迎补充)](https://github.com/apachecn/home/blob/master/docs/translate/trans-table.md)
+ [7.在控制台上打印信息(`console.*`)](docs/9.md) + [廖雪峰 Git 教程](https://www.liaoxuefeng.com/wiki/896043488029600)
+ [8.断言 API](docs/10.md)
+ [9.测验和练习入门](docs/11.md)
+ [10.变量和赋值](docs/13.md)
+ [11.值](docs/14.md)
+ [12.运算符](docs/15.md)
+ [13.非值`undefined`和`null`](docs/17.md)
+ [14.布尔值](docs/18.md)
+ [15.数字](docs/19.md)
+ [16\. `Math`](docs/20.md)
+ [17\. Unicode - 简要介绍(高级)](docs/21.md)
+ [18.字符串](docs/22.md)
+ [19.使用模板字面值和标记模板](docs/23.md)
+ [20.符号](docs/24.md)
+ [21.控制流语句](docs/26.md)
+ [22.异常处理](docs/27.md)
+ [23.可调用值](docs/28.md)
+ [24.模块](docs/30.md)
+ [25.单个对象](docs/31.md)
+ [26.原型链和类](docs/32.md)
+ [27.同步迭代](docs/34.md)
+ [28.数组(`Array`)](docs/35.md)
+ [29.类型化数组:处理二进制数据(高级)](docs/36.md)
+ [30.映射(`Map`)](docs/37.md)
+ [31\. WeakMaps(`WeakMap`)](docs/38.md)
+ [32.集(`Set`)](docs/39.md)
+ [33\. WeakSets(`WeakSet`)](docs/40.md)
+ [34.解构](docs/41.md)
+ [35.同步生成器(高级)](docs/42.md)
+ [36\. JavaScript 中的异步编程](docs/44.md)
+ [37.异步编程的 Promise](docs/45.md)
+ [38.异步函数](docs/46.md)
+ [39.正则表达式(`RegExp`)](docs/48.md)
+ [40.日期(`Date`)](docs/49.md)
+ [41.创建和解析 JSON(`JSON`)](docs/50.md)
+ [42.其余章节在哪里?](docs/51.md)
## 流程 ## 流程
### 一、认领 ### 一、认领
首先查看[整体进度](https://github.com/apachecn/impatient-js-zh/issues/1),确认没有人认领了你想认领的章节。 校对者需要熟练掌握 Markdown 和 Git,以及文档的主题(编程,Web开发,大数据,AI,安全之一)。
首先查看[整体进度](https://github.com/apachecn/ds-cmd-line-2e-zh/issues/1),确认没有人认领了你想认领的章节。
然后回复 ISSUE,注明“章节 + QQ 号”(一定要留 QQ) 然后回复 ISSUE,注明“章节 + QQ 号”,便于联系和跟踪进度
### 二、校对 ### 二、校对
需要校对 需要校对【专业术语】和【格式】。
+ 部分语法 【语法】无需校对因为已经校对完了,并且请最大程度保留原文的语言风格。
+ 专业词汇
+ 格式
译文在`docs`目录下,原文请见每个文章开头处的链接。 译文在`docs`目录下,原文请见每个文章开头处的链接。
请见[校对活动参与手册](https://github.com/apachecn/home/blob/master/docs/translate/joining-guide.md)来提高效率。
**注意**:不要修改译文的文件名,因为它们和章节对应! **注意**:不要修改译文的文件名,因为它们和章节对应!
确保译文符合下方的【Markdown 排版要求】一节。
请参考下方的【有用的正则表达式】一节,以及[【翻译引擎易错术语列表】](https://github.com/apachecn/home/blob/master/docs/translate/trans-table.md)来提高效率。
### 三、提交 ### 三、提交
+ `fork` Github 项目 + `fork` Github 项目
+ 修改`docs`中的文档。 + `docs`文件夹下编辑译文
+ `push` + `add``commit``push`
+ `pull request` + `pull request`
请见 [Github 入门指南](https://github.com/apachecn/kaggle/blob/master/docs/GitHub) 请见[廖雪峰 Git 教程](https://www.liaoxuefeng.com/wiki/896043488029600)
## Markdown 排版要求
1. 代码块和图片无需校对,并且不计入字数。
3. 汉字和英文字母,汉字和数字之间空一格。但是中文标点和任何字符之间都不用空格。
4. 粗体斜体和链接要求同上,中文和英文粗体,英文和中文粗体之间也需要空格。
5. 任何编程语言中出现的东西,比如变量名,类名,函数名,包名,以及命令行中出现的东西,比如命令,文件名,路径,扩展名,都需要包在内联代码中。内联代码与汉字/标点之间无需空格,但和英文字母或数字之间空一格。
6. 表格的格式容易乱,保证它们显示正常。
7. 标题和较短的列表需要特别校对。
8. 有少量未翻译的段落,使用[谷歌翻译](https://translate.google.cn/)之后再校对。
## 有用的正则表达式
链接:
```
(?<!!)\[[^\]]*\]
```
表格:
```
^\|
```
中文间空格:
中文间空格一般是翻译引擎出错的地方。
```
[\u4e00-\u9fff]\s+[\u4e00-\u9fff]
```
未翻译段落:
```
^[a-zA-Z0-9][^\u4e00-\u9fff]+$
^\s*([\+\-\*]\x20{3}|\d+\.\x20{2})[^\u4e00-\u9fff]+$
```
内联代码:
在 Markdown 中,内联代码需要用反引号括起来,但一些教程并没有这样做。于是,需要检查中英文边界,将没有用反引号括起来的内联代码改掉。
```
[\u2018-\u201d\u3001-\u301c\u4e00-\u9fff\uff01-\uff65]\x20*[A-Za-z0-9]|[A-Za-z0-9]\x20*[\u2018-\u201d\u3001-\u301c\u4e00-\u9fff\uff01-\uff65]
```
粗体/斜体:
```
\*\*[^\*]+\*\*|(?<!\*)\*[^\*]+\*(?!\*)
```
标题:
```
^#+\x20
```
列表(二十字以内):
短的列表由于没有上下文非常容易出错。
```
^\s*([\+\-\*]\x20{3}|\d+\.\x20{2}).{1,20}$
```
## 奖励
校对者在完工后可以领取千字2~4元的奖励(视难度和工作量而定),请联系飞龙(Q562826179,V:wizardforcel)。
字数统计遵循 word 标准:每一个汉字和标点算一个字,一个连续的英文字母、数字和标点序列算一个字
...@@ -64,4 +64,6 @@ impatient-js-zh <port> ...@@ -64,4 +64,6 @@ impatient-js-zh <port>
## 赞助我们 ## 赞助我们
![](http://data.apachecn.org/img/about/donate.jpg) 本项目由[飞龙](https://github.com/wizardforcel)赞助,扫下面的二维码打赏他来表示感谢:
![](asset/flygon_qr_alipay.png)
# Code for “JavaScript for impatient programmers”
## Installation
1. Requirement: Node.js must be installed. https://nodejs.org/
* The version must be at least 11.11.0 (checked during installation test, see below)
* See the version of your Node.js: `node -v`
2. Installing this repository:
```
cd impatient-js-code/
npm install
```
3. Checking that everything was installed correctly (the “t” is an abbreviation for “test”):
```
npm t installation_test.mjs
```
## Running exercises
Each exercise/test file:
* mentions the command for running the exercise via a command line.
* gives instructions for solving the exercise.
export function id(x) {
return x;
}
// npm t demos/quizzes-exercises/id_test.mjs
import test from 'ava';
import {strict as assert} from 'assert';
import {id} from './id.mjs';
test('My test', t => {
assert.equal(id('abc'), 'abc');
});
/* npm t exercises/booleans/default_via_or_exrc.mjs
Instructions:
- Run test (it succeeds).
- Change getFilename() so that it only contains a return of an expression with the || operator.
- Run the test again, it should still succeed.
*/
import test from 'ava';
import {strict as assert} from 'assert';
function getFilename(options) {
if (options.filename) {
return options.filename;
} else {
return 'Untitled';
}
}
test('Default via ||', t => {
assert.equal(getFilename({}), 'Untitled'); // empty object
assert.equal(getFilename({filename: 'foo.txt'}), 'foo.txt');
});
/* npm t exercises/booleans/truthiness_exrc.mjs
Instructions:
- Run this test (it fails).
- Change the second parameters of assert.equal() so that the test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
test('truthiness', t => {
assert.equal(Boolean(null), 'some value');
assert.equal(Boolean(undefined), 'some value');
assert.equal(Boolean(''), 'some value');
assert.equal(Boolean('abc'), 'some value');
assert.equal(Boolean(0), 'some value');
assert.equal(Boolean(123), 'some value');
assert.equal(Boolean({}), 'some value');
assert.equal(Boolean([]), 'some value');
});
export function handleNamedParameters(params) {
params = params || {};
var x = params.x || 0;
var y = params.y || 0;
var color = params.color || 'black';
return [x, y, color];
}
/* npm t exercises/callables/named_parameters_test.mjs
Instructions:
- Change the ES5 code in named_parameters.mjs so that it uses ES6 and destructuring
- Make sure the tests still pass
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {handleNamedParameters} from './named_parameters.mjs';
test('All named parameters', t => {
assert.deepEqual(
handleNamedParameters({ x: 1, y: 2, color: 'red' }),
[1, 2, 'red']);
});
test('Omitting named parameters', t => {
assert.deepEqual(
handleNamedParameters({ x: 1, y: 2 }),
[1, 2, 'black']);
assert.deepEqual(
handleNamedParameters({ color: 'red' }),
[0, 0, 'red']);
assert.deepEqual(
handleNamedParameters({}),
[0, 0, 'black']);
});
test('Omitting named parameter object', t => {
assert.deepEqual(
handleNamedParameters(),
[0, 0, 'black']);
});
/* npm t exercises/callables/positional_parameters_test.mjs
Instructions:
– Implement positional_parameters.mjs so that it passes the test.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {twoParametersWithDefaultValues, restParameters} from './positional_parameters.mjs';
test('twoParametersWithDefaultValues', t => {
assert.deepEqual(twoParametersWithDefaultValues(), [0, 0]);
assert.deepEqual(twoParametersWithDefaultValues(1), [1, 0]);
assert.deepEqual(twoParametersWithDefaultValues(1, 2), [1, 2]);
assert.deepEqual(twoParametersWithDefaultValues(1, 2, 3), [1, 2]);
});
test('restParameters', t => {
assert.deepEqual(restParameters(), []);
assert.deepEqual(restParameters(1), []);
assert.deepEqual(restParameters(1, 2), [2]);
assert.deepEqual(restParameters(1, 2, 3, 4), [2, 3, 4]);
assert.deepEqual(restParameters(1, 2, 3, 4, 5), [2, 3, 4, 5]);
assert.deepEqual(restParameters(1, 2, 3, 4, 5, 6), [2, 3, 4, 5, 6]);
assert.deepEqual(restParameters(1, 2, 3, 4, 5, 6, 7), [2, 3, 4, 5, 6, 7]);
});
/* npm t exercises/control-flow/array_to_string_test.mjs
Instructions:
– Implement array_to_string.mjs so that it passes the test.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {arrayToString} from './array_to_string.mjs';
test('arrayToString', t => {
const CMYK = [
'cyan',
'magenta',
'yellow',
'key',
];
assert.equal(arrayToString(CMYK), `
1. cyan
2. magenta
3. yellow
4. key
`.trim());
});
export function isObject(x) {
return x !== null && (typeof x === 'object' || typeof x === 'function');
}
/* npm t exercises/control-flow/is_object_via_switch_test.mjs
Instructions:
– Change is_object_via_switch.mjs so that it uses a switch statement
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {isObject} from './is_object_via_switch.mjs';
test('isObject via switch', t => {
assert.equal(isObject(undefined), false);
assert.equal(isObject(null), false);
assert.equal(isObject(true), false);
assert.equal(isObject(123), false);
assert.equal(isObject('abc'), false);
assert.equal(isObject(function () {}), true);
assert.equal(isObject({}), true);
assert.equal(isObject([]), true);
});
/* npm t exercises/control-flow/number_to_month_test.mjs
Instructions:
– Implement number_to_month.mjs so that it passes the test.
– Errors are thrown via: throw new Error(str)
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {numberToMonth} from './number_to_month.mjs';
test('numberToMonth', t => {
assert.equal(numberToMonth(1), 'January');
assert.throws(() => numberToMonth(0), /^Error: Unknown number: 0$/);
});
export function callFunction(func) {
const result = func();
return {
success: result,
};
}
\ No newline at end of file
/* npm t exercises/exception-handling/call_function_test.mjs
Instructions:
– Change call_function.mjs so that it passes the test.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {callFunction} from './call_function.mjs';
test('monthToNumber', t => {
assert.deepEqual(
callFunction(() => { return 'abc' }),
{ success: 'abc' });
const err = new Error('Failed!');
assert.deepEqual(
callFunction(() => { throw err }),
{ failure: err });
});
/* npm t exercises/modules/export_default_test.mjs
Instructions:
– Create export_default.mjs so that this test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
import func from './export_default.mjs';
test('export_default', t => {
assert.equal(func(), 'hello');
});
/* npm t exercises/modules/export_named_test.mjs
Instructions:
– Create export_named.mjs so that this test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {func} from './export_named.mjs';
test('export_named', t => {
assert.equal(func(), 'hello');
});
/* npm t exercises/numbers-math/find_max_test.mjs
Instructions:
- Create the file find_max.mjs
- Ensure this test passes
– Use function addAll() from this file as a template.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {findMax} from './find_max.mjs';
test('findMax', t => {
assert.equal(findMax([]), -Infinity);
assert.equal(findMax([8]), 8);
assert.equal(findMax([-20, -3, -15]), -3);
assert.equal(findMax([100, 200, 5]), 200);
});
//----------
function addAll(nums) {
let result = 0;
for (const num of nums) {
result += num;
}
return result;
}
test('addAll', t => {
assert.equal(addAll([]), 0);
assert.equal(addAll([4]), 4);
assert.equal(addAll([1, 2]), 3);
assert.equal(addAll([100, 200, 500]), 800);
});
/* npm t exercises/numbers-math/is_odd_test.mjs
Instructions:
- Create the file is_odd.mjs
- Ensure the test passes
- Possibly useful: Math.abs()
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {isOdd} from './is_odd.mjs';
test('isOdd', t => {
assert.equal(isOdd(3), true);
assert.equal(isOdd(-3), true);
assert.equal(isOdd(10001), true);
assert.equal(isOdd(0), false);
assert.equal(isOdd(2), false);
assert.equal(isOdd(-2), false);
assert.equal(isOdd(10000), false);
});
/* npm t exercises/numbers-math/is_safe_integer_test.mjs
Instructions:
- Create the file is_safe_integer.mjs
- Ensure the test passes
– Don’t use Number.isInteger()
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {isSafeInteger} from './is_safe_integer.mjs';
test('Is it an integer?', t => {
assert.equal(isSafeInteger(123), true);
assert.equal(isSafeInteger(123.1), false);
// We don’t want isSafeInteger() to coerce its arguments
assert.equal(isSafeInteger('123'), false);
assert.equal(isSafeInteger(true), false);
});
test('Is it safe?', t => {
assert.equal(isSafeInteger(2 ** 53), false);
assert.equal(isSafeInteger(-(2 ** 53)), false);
assert.equal(isSafeInteger((2 ** 53)-1), true);
assert.equal(isSafeInteger(-(2 ** 53)+1), true);
assert.equal(isSafeInteger(0), true);
assert.equal(isSafeInteger(5), true);
assert.equal(isSafeInteger(-5), true);
});
/* npm t exercises/numbers-math/parse_number_test.mjs
Instructions:
- Create the file parse_number.mjs
- Ensure the test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {parseNumber} from './parse_number.mjs';
test('parseNumber', t => {
assert.equal(parseNumber('16'), 16);
assert.equal(parseNumber(''), 0);
// Whitespace
assert.equal(parseNumber('\t 123 \n'), 123);
// Other non-digit characters
assert.equal(parseNumber('456#'), NaN);
// Hexadecimal integer number
assert.equal(parseNumber('0xFF'), 255);
// Binary integer number
assert.equal(parseNumber('0b111'), 7);
});
/* npm t exercises/proto-chains-classes/color_point_class_test.mjs
Instructions:
- Create the file color_point_class.mjs
- Ensure the test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {Point} from './point_class.mjs';
import {ColorPoint} from './color_point_class.mjs';
test('Class ColorPoint', t => {
const cpt = new ColorPoint(4, 7, 'red');
assert.ok(cpt instanceof Point);
assert.ok(cpt instanceof ColorPoint);
assert.equal(cpt.toString(), `(4, 7) in red`);
});
/* npm t exercises/proto-chains-classes/point_class_test.mjs
Instructions:
- Create the file point_class.mjs
- Ensure the test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {Point} from './point_class.mjs';
test('Class Point', t => {
const pt = new Point(4, 7);
assert.equal(pt.x, 4);
assert.equal(pt.y, 7);
assert.equal(pt.dist(), Math.sqrt(4**2 + 7**2));
assert.equal(pt.toString(), `(4, 7)`);
});
export class StringBuilder {
constructor() {
this._data = '';
}
add(str) {
this._data += str;
return this;
}
toString() {
return this._data;
}
}
/* npm t exercises/proto-chains-classes/string_builder_symbol_test.mjs
Instructions:
- Change string_builder_symbol.mjs: use symbols for private data, not property names with underscores
- Make sure the tests still pass
Similar exercise: exercises/weakmaps/weakmaps_private_data_test.mjs
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {StringBuilder} from './string_builder_symbol.mjs';
test('Empty StringBuilder', t => {
assert.equal(new StringBuilder().toString(), '');
});
test('Adding strings to a StringBuilder', t => {
assert.equal(new StringBuilder().add('foo').add('bar').toString(), 'foobar');
});
test('Rule out singleton implementations', t => {
const sb1 = new StringBuilder().add('sb1');
const sb2 = new StringBuilder().add('sb2');
assert.equal(sb1.toString(), 'sb1');
assert.equal(sb2.toString(), 'sb2');
});
test('Is private data hidden?', t => {
const sb = new StringBuilder();
assert.deepEqual(Object.getOwnPropertyNames(sb), []);
});
// We export a function so that the test can import it
export function hello(x) {
return 'Goodbye ' + x + '!';
}
/* npm t exercises/quizzes-exercises/first_module_test.mjs
Instructions:
- Run the test (fails)
- Change first_module.mjs so that the test passes.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {hello} from './first_module.mjs';
test('First exercise', t => {
assert.equal(hello('world'), 'Hello world!');
assert.equal(hello('Jane'), 'Hello Jane!');
assert.equal(hello('John'), 'Hello John!');
assert.equal(hello(''), 'Hello !');
});
/* npm t exercises/single-objects/color_point_object_test.mjs
Instructions:
- Create the file color_point_object.mjs
- Ensure the test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {colorPoint} from './color_point_object.mjs';
test('Object colorPoint', t => {
assert.equal(colorPoint.x, 3);
assert.equal(colorPoint.y, 5);
assert.equal(colorPoint.dist(), Math.sqrt(3**2 + 5**2));
assert.equal(colorPoint.toString(), `(3, 5)`);
colorPoint.x = 2;
colorPoint.y = 4;
assert.equal(colorPoint.x, 2);
assert.equal(colorPoint.y, 4);
assert.equal(colorPoint.dist(), Math.sqrt(2**2 + 4**2));
assert.equal(colorPoint.toString(), `(2, 4)`);
});
/* npm t exercises/single-objects/find_key_test.mjs
Instructions:
– Implement find_key.mjs so that the test passes. Use Object.entries() to do so.
– findKey(object, callback) returns the first property key for which callback(propValue, propKey, object) returns true.
– Inspired by Underscore function _.findKey(): https://underscorejs.org/#findKey
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {findKey} from './find_key.mjs';
test('Find key via value', t => {
assert.equal(
findKey({a:1, b:2, c:3}, (v) => v > 1),
'b'
);
});
test('Find key via key', t => {
assert.equal(
findKey({a:1, bb:2, ccc:3}, (_v, k) => k.length > 2),
'ccc'
);
});
test('Is object passed to callback?', t => {
const obj = {a:1, b:2, c:3};
findKey(obj, (v, k, o) => assert.equal(o, obj));
});
/* npm t exercises/single-objects/method_extraction_exrc.mjs
Instructions:
- Run this test (fails)
- Change the code so that the test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
const jane = {
first: 'Jane',
describe() {
return `Person named ${this.first}`;
},
};
test('method_extraction_exrc', t => {
const func = jane.describe;
assert.equal(func(), 'Person named Jane');
jane.first = 'John';
assert.equal(func(), 'Person named John');
});
/* npm t exercises/single-objects/omit_properties_test.mjs
Instructions:
– Implement omit_properties.mjs so that the test passes. Use Object.entries() and Object.fromEntries() to do so.
– omitProperties(object, ...keys) returns a shallow copy of `object` that has all of the properties of the original except for those whose `keys` are mentioned at the end.
– Inspired by Underscore function _.omit(): https://underscorejs.org/#omit
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {omitProperties} from './omit_properties.mjs';
test('omitProperties', t => {
const obj = {a: 1, b: 2, c: 3};
assert.deepEqual(
omitProperties(obj), // omit nothing
{a: 1, b: 2, c: 3}
);
assert.deepEqual(
omitProperties(obj, 'c'),
{a: 1, b: 2}
);
assert.deepEqual(
omitProperties(obj, 'c', 'b'),
{a: 1}
);
assert.deepEqual(
omitProperties(obj, 'a', 'c'),
{b: 2}
);
assert.deepEqual(
omitProperties(obj, 'a', 'c', 'b'), // omit everything
{}
);
});
/* npm t exercises/single-objects/simple_dict_test.mjs
Instructions:
- Implement simple_dict.mjs so that the test passes.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import { createDict, setValue, getValue, hasKey, getKeys } from './simple_dict.mjs';
test('updateProperty: update existing property', t => {
const dict = createDict();
setValue(dict, '__proto__', 'abc');
assert.equal(getValue(dict, '__proto__'), 'abc');
assert.ok(hasKey(dict, '__proto__'));
setValue(dict, 'foo', 123);
assert.equal(getValue(dict, 'foo'), 123);
assert.ok(hasKey(dict, 'foo'));
assert.deepEqual(hasKey(dict, 'toString'), false);
// Keys are listed in creation order!
assert.deepEqual(getKeys(dict), ['__proto__', 'foo']);
});
/* npm t exercises/single-objects/update_name_test.mjs
Instructions:
- Create the file update_name.mjs so that the tests pass.
- Use spreading.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {updateName} from './update_name.mjs';
test('updateName: update existing property', t => {
const input = { name: 'John', age: 54 };
const output = updateName(input, 'Jane');
// The function must return a copy, not the original:
assert.notEqual(input, output);
assert.deepEqual(output, { name: 'Jane', age: 54 });
});
test('updateName: add new property', t => {
const input = {};
const output = updateName(input, 'Rumpelstiltskin');
// The function must return a copy, not the original:
assert.notEqual(input, output);
assert.deepEqual(output, { name: 'Rumpelstiltskin' });
});
/* npm t exercises/single-objects/update_property_test.mjs
Instructions:
- Create the file update_property.mjs so that the tests pass.
- Use spreading.
– Same as update_name.mjs, but with arbitrary keys
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {updateProperty} from './update_property.mjs';
test('updateProperty: update existing property', t => {
const input = { name: 'Jane', age: 54 };
const output = updateProperty(input, 'age', 82);
// The function must return a copy, not the original:
assert.notEqual(input, output);
assert.deepEqual(output, { name: 'Jane', age: 82 });
});
test('updateProperty: add new property', t => {
const input = {};
const output = updateProperty(input, 'data', 123);
// The function must return a copy, not the original:
assert.notEqual(input, output);
assert.deepEqual(output, { data: 123 });
});
/* npm t exercises/strings/concat_string_array_test.mjs
Instructions:
- Create the file concat_string_array.mjs
- Ensure this test passes
– Use function logStringArray() from this file as a template.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {concatStringArray} from './concat_string_array.mjs';
test('concatStringArray', t => {
assert.equal(concatStringArray([]), '');
assert.equal(concatStringArray(['abc']), 'abc');
assert.equal(concatStringArray(['x', 'y', 'z']), 'xyz');
});
//----------
function logStringArray(stringArray) {
for (const str of stringArray) {
console.log(str);
}
}
/* npm t exercises/strings/remove_extension_test.mjs
Instructions:
- Create the file remove_extension.mjs
- Ensure this test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {removeExtension} from './remove_extension.mjs';
test('removeExtension', t => {
assert.equal(removeExtension(''), '');
assert.equal(removeExtension('foo.txt'), 'foo');
assert.equal(removeExtension('foo.mjs'), 'foo');
assert.equal(removeExtension('foo.tar.gz'), 'foo.tar');
assert.equal(removeExtension('foo'), 'foo');
assert.equal(removeExtension('.foo'), '');
});
/* npm t exercises/symbols/has_instance_test.mjs
Instructions:
- Implement has_instance.mjs so that the test passes.
– Use the property key Symbol.hasInstance
– Syntax for creating the class PrimitiveString: check the material on symbols
*/
import test from 'ava';
import {strict as assert} from 'assert';
import { PrimitiveString } from './has_instance.mjs';
test('Symbol.hasInstance', t => {
assert.equal('abc' instanceof String, false);
assert.equal(new String('abc') instanceof String, true);
assert.equal('abc' instanceof PrimitiveString, true);
assert.equal(new String('abc') instanceof PrimitiveString, false);
assert.equal(123 instanceof PrimitiveString, false);
});
/* npm t exercises/symbols/to_string_tag_test.mjs
Instructions:
- Implement to_string_tag.mjs so that the test passes.
– Use the property key Symbol.toStringTag
– Syntax for creating the object SPECIAL_OBJECT: check the material on symbols
*/
import test from 'ava';
import {strict as assert} from 'assert';
import { SPECIAL_OBJECT } from './to_string_tag.mjs';
test('Symbol.toStringTag', t => {
assert.equal(String({}), '[object Object]'); // default
// Instance property [Symbol.toStringTag] must be changed
assert.notEqual(SPECIAL_OBJECT[Symbol.toStringTag], Object.prototype[Symbol.toStringTag]);
// Method .toString() must not be changed
assert.equal(SPECIAL_OBJECT.toString, {}.toString);
assert.equal(String(SPECIAL_OBJECT), '[object Hello]');
});
/* npm t exercises/template-literals/templating_test.mjs
Instructions: Implement templating.mjs
– Use the HTML templating technique as described in the slides.
– You don’t need to escape the template data.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {arrayWithObjectsToTable, arrayToUnorderedListWithEscaping} from './templating.mjs'
test('arrayWithObjectsToTable', t => {
const data = [
{ first: 'Lars', last: 'Croft' },
{ first: 'Jane', last: 'Bond' },
];
// Lenient testing via .trim()
assert.equal(arrayWithObjectsToTable(data).trim(),
`<table>
<tr><td>Croft</td><td>Lars</td></tr>
<tr><td>Bond</td><td>Jane</td></tr>
</table>`);
});
//---------- Bonus (remove "#bonus" to activate)
test('arrayToUnorderedListWithEscaping #bonus', t => {
const data = [
'<first item>',
'second item',
];
assert.equal(arrayToUnorderedListWithEscaping(data).trim(), `
<ul>
<li>&lt;first item&gt;</li>
<li>second item</li>
</ul>
`.trim());
});
/* npm t exercises/values/conversion_exrc.mjs
Instructions:
- Run this test (it fails).
- Change the second parameter of each assert.equal() so that the test succeeds
*/
import test from 'ava';
import {strict as assert} from 'assert';
test('conversion', t => {
assert.equal(Boolean(5), '???');
assert.equal(Number('7'), '???');
assert.equal(String(21), '???');
});
/* npm t exercises/values/instanceof_exrc.mjs
Instructions:
- Run this test (it fails).
- Change the second parameters of assert.equal() so that the test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
test('instanceof', t => {
assert.equal('abc' instanceof String, '???');
assert.equal(null instanceof Object, '???');
assert.equal(undefined instanceof Object, '???');
assert.equal([true, false] instanceof Array, '???');
assert.equal([true, false] instanceof Object, '???');
assert.equal({} instanceof Object, '???');
});
// Function is exported so that the test can import it
export function isObject(x) {
// Use the following patterns (instead of `true`):
// x === null
// x !== undefined
// typeof x === 'number'
// typeof x !== 'object'
// x === 3 || x === 4 // logical OR
// x !== 3 && x !== 4 // logical AND
return true;
}
/* npm t exercises/values/is_object_test.mjs
Instructions:
- Run the test (fails).
- Change is_object.mjs so that the test passes.
*/
import test from 'ava';
import {strict as assert} from 'assert';
import {isObject} from './is_object.mjs';
test('isObject', t => {
assert.equal(isObject(undefined), false);
assert.equal(isObject(null), false);
assert.equal(isObject(true), false);
assert.equal(isObject(123), false);
assert.equal(isObject('abc'), false);
assert.equal(isObject(function () {}), true);
assert.equal(isObject({}), true);
assert.equal(isObject([]), true);
});
/* npm t exercises/values/typeof_exrc.mjs
Instructions:
- Run this test (it fails).
- Change the second parameter of each assert.equal() so that the test passes
*/
import test from 'ava';
import {strict as assert} from 'assert';
test('typeof', t => {
assert.equal(typeof null, '???');
assert.equal(typeof undefined, '???');
assert.equal(typeof 123, '???');
assert.equal(typeof 'a', '???');
assert.equal(typeof "abc", '???');
assert.equal(typeof {}, '???');
assert.equal(typeof function () {}, '???');
assert.equal(typeof [], '???');
});
/* npm t exercises/variables-assignment/const_exrc.mjs
Instructions:
- Run this test (it fails).
- Insert a single(!) const statement so that the test passes.
*/
import test from 'ava';
import {strict as assert} from 'assert';
test('const', t => {
const x = 3;
assert.equal(x, 3);
{
assert.equal(x, 12);
}
assert.equal(x, 3);
});
// npm t installation_test.mjs
import test from 'ava';
import {strict as assert} from 'assert';
const MIN_VERSION = [12, 2, 0];
function greaterOrEqual(numArr1, numArr2) {
const maxLen = Math.max(numArr1.length, numArr2.length);
for (let i=0; i<maxLen; i++) {
// Missing parts are considered to be zero.
let num1 = numArr1[i] || 0;
let num2 = numArr2[i] || 0;
if (num1 < num2) {
return false;
}
if (num1 > num2) {
return true;
}
}
// The arrays are “equal”
return true
}
test('Do assertions work?', t => {
// Assert something simple
assert.equal(1+1, 2);
});
test('Does greaterOrEqual() work?', () => {
assert.equal(greaterOrEqual([1,2,3], [1,2]), true);
assert.equal(greaterOrEqual([1,2], [1,2,3]), false);
assert.equal(greaterOrEqual([4,0,5], [4,0,4]), true);
assert.equal(greaterOrEqual([4,0,5], [4,0,5]), true);
assert.equal(greaterOrEqual([4,0,5], [4,0,6]), false);
assert.equal(greaterOrEqual([4,0,5], [3,0,0]), true);
assert.equal(greaterOrEqual([4,0,5], [5,0,0]), false);
});
test(`Is Node.js version at least ${MIN_VERSION.join('.')}?`, () => {
const installedVersionStr = process.versions.node;
const installedVersion = installedVersionStr.split('.').map(str => Number(str));
assert.ok(greaterOrEqual(installedVersion, MIN_VERSION),
`Please use Node.js ${MIN_VERSION.join('.')} or later. Installed version: ${installedVersionStr}`);
});
此差异已折叠。
{
"name": "js-foundations-code",
"version": "1.0.0",
"private": true,
"scripts": {
"test": "ava --match \"!*#bonus\"",
"testone": "ava",
"testall": "ava \"{exercises,demos}/**/*{_test,_exrc}.mjs\"",
"serve": "http-server test_data/"
},
"author": "Axel Rauschmayer",
"// dependencies": [
"http-server is needed for fetch_json_test.mjs and fetch_json_test2.mjs",
"isomorphic-fetch is needed for fetch_json_test.mjs and fetch_json_test2.mjs"
],
"dependencies": {
"ava": "^2.0.0",
"esm": "^3.2.18",
"http-server": "^0.11.1",
"isomorphic-fetch": "^2.2.1"
},
"// ava": [
"failWithoutAssertions must be false, because assert.* is not tracked by AVA",
"esm completely replaces Babel, which is switched off via babel:false and compileEnhancements:false"
],
"ava": {
"babel": false,
"compileEnhancements": false,
"extensions": [
"mjs"
],
"require": [
"esm"
],
"failWithoutAssertions": false
}
}
import test from 'ava';
import {strict as assert} from 'assert';
function getFilename(options) {
return options.filename || 'Untitled';
}
test('Default via ||', t => {
assert.equal(getFilename({}), 'Untitled'); // empty object
assert.equal(getFilename({filename: 'foo.txt'}), 'foo.txt');
});
import test from 'ava';
import {strict as assert} from 'assert';
test('truthiness', t => {
assert.equal(Boolean(null), false);
assert.equal(Boolean(undefined), false);
assert.equal(Boolean(''), false);
assert.equal(Boolean('abc'), true);
assert.equal(Boolean(0), false);
assert.equal(Boolean(123), true);
assert.equal(Boolean({}), true);
assert.equal(Boolean([]), true);
});
export function handleNamedParameters(
{ x=0, y=0, color='black' } = {}) {
return [x, y, color];
}
export function twoParametersWithDefaultValues(x=0, y=0) {
return [x, y];
}
export function restParameters(x, ...rest) {
return rest;
}
\ No newline at end of file
export function arrayToString(arr) {
let result = '';
for (const [index, elem] of arr.entries()) {
if (index > 0) {
result += '\n';
}
result += (index+1) + '. ' + elem;
}
return result;
}
\ No newline at end of file
export function isObject(value) {
switch (typeof value) {
case 'object':
case 'function':
return value !== null;
default:
return false;
}
}
export function numberToMonth(num) {
switch (num) {
case 1:
return 'January';
case 2:
return 'February';
case 3:
return 'March';
case 4:
return 'April';
case 5:
return 'May';
case 6:
return 'June';
case 7:
return 'July';
case 8:
return 'August';
case 9:
return 'September';
case 10:
return 'October';
case 11:
return 'November';
case 12:
return 'December';
default:
throw new Error('Unknown number: ' + num);
}
}
export function callFunction(func) {
try {
const result = func();
return {
success: result,
};
}
catch (err) {
return {
failure: err,
};
}
}
\ No newline at end of file
export default function func() {
return 'hello';
}
\ No newline at end of file
export function func() {
return 'hello';
}
\ No newline at end of file
export function findMax(numbers) {
let max = -Infinity;
for (const n of numbers) {
if (n > max) max = n;
}
return max;
}
export function isOdd(n) {
return Math.abs(n % 2) === 1;
}
\ No newline at end of file
export function isSafeInteger(n) {
return (typeof n === 'number' // Is n a number?
&& Math.trunc(n) === n // Is n an integer?
&& Number.MIN_SAFE_INTEGER <= n
&& n <= Number.MAX_SAFE_INTEGER);
}
export function parseNumber(str) {
return Number(str);
}
\ No newline at end of file
import {Point} from './point_class.mjs';
export class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
toString() {
return super.toString() + ' in ' + this.color;
}
}
export class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
dist() {
return Math.sqrt(this.x**2 + this.y**2);
}
toString() {
return `(${this.x}, ${this.y})`;
}
}
const data = Symbol('data');
export class StringBuilder {
constructor() {
this[data] = '';
}
add(str) {
this[data] += str;
return this;
}
toString() {
return this[data];
}
}
// We export a function so that the test can import it
export function hello(x) {
return 'Hello ' + x + '!';
}
export const colorPoint = {
x: 3,
y: 5,
dist() {
return Math.sqrt(this.x ** 2 + this.y ** 2);
},
toString() {
return `(${this.x}, ${this.y})`;
},
};
export function findKey(object, callback) {
for (const [key, value] of Object.entries(object)) {
if (callback(value, key, object)) {
return key;
}
}
return undefined;
}
import test from 'ava';
import {strict as assert} from 'assert';
const jane = {
first: 'Jane',
describe() {
return `Person named ${this.first}`;
},
};
test('method_extraction_exrc', t => {
const func = jane.describe.bind(jane);
assert.equal(func(), 'Person named Jane');
jane.first = 'John';
assert.equal(func(), 'Person named John');
});
export function omitProperties(object, ...keys) {
const filteredEntries = Object.entries(object)
.filter(entry => !keys.includes(entry[0]));
return Object.fromEntries(filteredEntries);
}
export function createDict() {
return Object.create(null);
}
export function setValue(dict, key, value) {
dict[key] = value;
}
export function getValue(dict, key) {
return dict[key];
}
export function hasKey(dict, key) {
return key in dict;
}
export function getKeys(dict) {
return Object.keys(dict);
}
\ No newline at end of file
export function updateName(obj, name) {
return {...obj, name};
}
\ No newline at end of file
export function updateProperty(obj, key, value) {
return { ...obj, [key]: value };
}
\ No newline at end of file
export function concatStringArray(stringArray) {
let result = '';
for (const str of stringArray) {
result += str;
}
return result;
}
\ No newline at end of file
export function removeExtension(str) {
const dotIndex = str.lastIndexOf('.');
if (dotIndex < 0) return str;
return str.slice(0, dotIndex);
}
\ No newline at end of file
export class PrimitiveString {
static [Symbol.hasInstance](x) {
return typeof x === 'string';
}
}
\ No newline at end of file
export const SPECIAL_OBJECT = {
[Symbol.toStringTag]: 'Hello',
};
\ No newline at end of file
export const arrayWithObjectsToTable = (persons) =>
`<table>
${persons.map(
({last,first}) =>
` <tr><td>${last}</td><td>${first}</td></tr>`)
.join('\n')}
</table>`;
//---------- Bonus
export const arrayToUnorderedListWithEscaping = (items) =>
`<ul>
${items.map(item => ` <li>${escapeHtml(item)}</li>`).join('\n')}
</ul>`;
function escapeHtml(str) {
return str.replace(/&/g, '&amp;') // first!
.replace(/>/g, '&gt;')
.replace(/</g, '&lt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/`/g, '&#96;');
}
\ No newline at end of file
import test from 'ava';
import {strict as assert} from 'assert';
test('conversion', t => {
assert.equal(Boolean(5), true);
assert.equal(Number('7'), 7);
assert.equal(String(21), '21');
});
import test from 'ava';
import {strict as assert} from 'assert';
test('instanceof', t => {
assert.equal('abc' instanceof String, false);
assert.equal(null instanceof Object, false);
assert.equal(undefined instanceof Object, false);
assert.equal([true, false] instanceof Array, true);
assert.equal([true, false] instanceof Object, true);
assert.equal({} instanceof Object, true);
});
export function isObject(x) {
return x !== null && (typeof x === 'object' || typeof x === 'function');
}
import test from 'ava';
import {strict as assert} from 'assert';
test('typeof', t => {
assert.equal(typeof null, 'object');
assert.equal(typeof undefined, 'undefined');
assert.equal(typeof 123, 'number');
assert.equal(typeof 'a', 'string');
assert.equal(typeof "abc", 'string');
assert.equal(typeof {}, 'object');
assert.equal(typeof function () {}, 'function');
assert.equal(typeof [], 'object');
});
import test from 'ava';
import {strict as assert} from 'assert';
test('const', t => {
const x = 3;
assert.equal(x, 3);
{
const x = 12;
assert.equal(x, 12);
}
assert.equal(x, 3);
});
{
"first": "Jane",
"last": "Bond"
}
\ No newline at end of file