kn-es-features 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esfeatures.iife.js +11 -14
- package/dist/esfeatures.js +1592 -2278
- package/dist/esfeatures.umd.cjs +11 -14
- package/dist/polyfills.iife.js +7 -7
- package/package.json +7 -3
- package/src/features/es2015/01-let-const.js +0 -33
- package/src/features/es2015/02-arrow-functions.js +0 -56
- package/src/features/es2015/03-template-literals.js +0 -38
- package/src/features/es2015/04-destructuring.js +0 -51
- package/src/features/es2015/05-default-rest-spread.js +0 -74
- package/src/features/es2015/08-symbols.js +0 -71
- package/src/features/es2015/09-iterators-generators.js +0 -71
- package/src/features/es2015/10-map-set.js +1 -86
- package/src/features/es2015/11-proxy-reflect.js +1 -84
- package/src/features/es2015/12-enhanced-objects.js +0 -80
- package/src/features/es2015/16-for-of.js +0 -33
- package/src/features/es2015/17-map.js +0 -46
- package/src/features/es2022/06-regexp-d-flag.js +4 -0
- package/src/features/es2022/07-top-level-await.js +6 -6
- package/src/features/es2025/01-iterator-helpers.js +4 -0
- package/src/features/es2025/02-set-methods.js +5 -1
- package/src/features/es2025/03-promise-try.js +15 -7
- package/src/features/es2025/04-regexp-duplicate-groups.js +4 -0
- package/src/features/es2025/05-uint8array-base64-hex.js +4 -0
- package/src/features/es2025/06-json-parse-source.js +4 -0
- package/src/features/es2025/07-error-is-error.js +4 -0
- package/src/features/es2025/08-float16array.js +4 -8
- package/src/features/es2026/01-math-sum-precise.js +4 -0
- package/src/features/es2026/02-regexp-escape.js +10 -6
- package/src/features/es2026/03-explicit-resource-management.js +5 -1
- package/src/features/es2026/04-atomics-pause.js +4 -0
- package/src/features/es2026/05-import-attributes.js +11 -4
- package/src/polyfills.js +1 -1
- package/src/validate-main.js +223 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kn-es-features",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "ES2015/2022/2025/2026所有特性的测试案例集合",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"es2015",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"import": "./dist/esfeatures.js",
|
|
19
19
|
"require": "./dist/esfeatures.umd.cjs"
|
|
20
20
|
},
|
|
21
|
+
"./polyfills": "./dist/polyfills.iife.js",
|
|
21
22
|
"./src": "./src/index.js"
|
|
22
23
|
},
|
|
23
24
|
"files": [
|
|
@@ -25,14 +26,17 @@
|
|
|
25
26
|
"src"
|
|
26
27
|
],
|
|
27
28
|
"scripts": {
|
|
28
|
-
"build": "vite build",
|
|
29
|
-
"polyfill": "vite build --config vite.polyfill.config.js"
|
|
29
|
+
"build": "vite build & npm run polyfill",
|
|
30
|
+
"polyfill": "vite build --config vite.polyfill.config.js",
|
|
31
|
+
"validate": "vite --config vite.validate.config.js",
|
|
32
|
+
"validate:build": "vite build --config vite.validate.config.js"
|
|
30
33
|
},
|
|
31
34
|
"devDependencies": {
|
|
32
35
|
"@babel/core": "~7.29.0",
|
|
33
36
|
"@babel/preset-env": "~7.29.3",
|
|
34
37
|
"@rollup/plugin-babel": "~7.0.0",
|
|
35
38
|
"core-js": "~3.49.0",
|
|
39
|
+
"regenerator-runtime": "~0.14.1",
|
|
36
40
|
"terser": "~5.46.2",
|
|
37
41
|
"vite": "~4.5.14"
|
|
38
42
|
}
|
|
@@ -11,44 +11,11 @@ export function testLetConst() {
|
|
|
11
11
|
assert(results[0] === 0 && results[2] === 2, 'let 循环变量应为独立值')
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
test('let 不可重复声明', () => {
|
|
15
|
-
try {
|
|
16
|
-
// 用 Function 构造器在独立作用域测试
|
|
17
|
-
new Function('"use strict"; let x = 1; let x = 2;')()
|
|
18
|
-
assert(false, '应抛出 SyntaxError')
|
|
19
|
-
} catch (e) {
|
|
20
|
-
assert(e instanceof SyntaxError || e instanceof TypeError, '应为语法错误')
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('let 暂时性死区(TDZ)', () => {
|
|
25
|
-
try {
|
|
26
|
-
new Function('"use strict"; console.log(y); let y = 1;')()
|
|
27
|
-
assert(false, '应抛出 ReferenceError')
|
|
28
|
-
} catch (e) {
|
|
29
|
-
assert(true)
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
|
|
33
14
|
test('const 声明常量', () => {
|
|
34
15
|
const PI = 3.14159
|
|
35
16
|
assert(PI === 3.14159, 'const 值应保持不变')
|
|
36
17
|
})
|
|
37
18
|
|
|
38
|
-
test('const 不可重新赋值', () => {
|
|
39
|
-
try {
|
|
40
|
-
new Function('"use strict"; const x = 1; x = 2;')()
|
|
41
|
-
assert(false, '应抛出 TypeError')
|
|
42
|
-
} catch (e) {
|
|
43
|
-
assert(e instanceof TypeError, '应为 TypeError')
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('const 对象属性可修改', () => {
|
|
48
|
-
const obj = { a: 1 }
|
|
49
|
-
obj.a = 2
|
|
50
|
-
assert(obj.a === 2, 'const 对象的属性可以修改')
|
|
51
|
-
})
|
|
52
19
|
|
|
53
20
|
return getResults()
|
|
54
21
|
}
|
|
@@ -8,61 +8,5 @@ export function testArrowFunctions() {
|
|
|
8
8
|
assert(add(2, 3) === 5, '箭头函数返回值应为 5')
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
-
test('单参数省略括号', () => {
|
|
12
|
-
const double = n => n * 2
|
|
13
|
-
assert(double(4) === 8, '单参数箭头函数应正常工作')
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
test('无参数需要括号', () => {
|
|
17
|
-
const greet = () => 'hello'
|
|
18
|
-
assert(greet() === 'hello', '无参数箭头函数应正常工作')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test('多行函数体需要花括号和 return', () => {
|
|
22
|
-
const calc = (a, b) => {
|
|
23
|
-
const sum = a + b
|
|
24
|
-
return sum * 2
|
|
25
|
-
}
|
|
26
|
-
assert(calc(2, 3) === 10, '多行箭头函数应正确计算')
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('返回对象字面量需要括号', () => {
|
|
30
|
-
const makeObj = (x) => ({ value: x })
|
|
31
|
-
const obj = makeObj(42)
|
|
32
|
-
assert(obj.value === 42, '箭头函数返回对象应正确包裹')
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('this 词法绑定', () => {
|
|
36
|
-
function Timer() {
|
|
37
|
-
this.count = 0
|
|
38
|
-
const tick = () => {
|
|
39
|
-
this.count++
|
|
40
|
-
}
|
|
41
|
-
tick()
|
|
42
|
-
tick()
|
|
43
|
-
}
|
|
44
|
-
const t = new Timer()
|
|
45
|
-
assert(t.count === 2, '箭头函数 this 应绑定外层作用域')
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test('没有 arguments 对象', () => {
|
|
49
|
-
const fn = () => typeof arguments === 'undefined' || true
|
|
50
|
-
// 在模块顶层 arguments 未定义,所以箭头函数内也未定义
|
|
51
|
-
assert(true, '箭头函数无独立 arguments')
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('不能用作构造函数(原生环境)', () => {
|
|
55
|
-
const Fn = () => {}
|
|
56
|
-
// Babel 将箭头函数编译为普通函数时,此限制在运行时不可复现,故跳过检测
|
|
57
|
-
const isNativeArrow = Fn.prototype === undefined
|
|
58
|
-
if (!isNativeArrow) return // 编译降级环境跳过
|
|
59
|
-
try {
|
|
60
|
-
new Fn()
|
|
61
|
-
assert(false, '应抛出 TypeError')
|
|
62
|
-
} catch (e) {
|
|
63
|
-
assert(e instanceof TypeError, '箭头函数不能 new')
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
|
|
67
11
|
return getResults()
|
|
68
12
|
}
|
|
@@ -9,43 +9,5 @@ export function testTemplateLiterals() {
|
|
|
9
9
|
assert(str === 'Hello, ES2015!', '模板字符串插值应正确')
|
|
10
10
|
})
|
|
11
11
|
|
|
12
|
-
test('表达式插值', () => {
|
|
13
|
-
const a = 3, b = 4
|
|
14
|
-
const str = `${a} + ${b} = ${a + b}`
|
|
15
|
-
assert(str === '3 + 4 = 7', '模板字符串支持表达式')
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
test('多行字符串', () => {
|
|
19
|
-
const multi = `第一行
|
|
20
|
-
第二行`
|
|
21
|
-
assert(multi.includes('\n'), '模板字符串支持多行')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('嵌套模板', () => {
|
|
25
|
-
const items = ['a', 'b', 'c']
|
|
26
|
-
const list = `items: ${items.map(i => `[${i}]`).join(', ')}`
|
|
27
|
-
assert(list === 'items: [a], [b], [c]', '模板字符串可以嵌套')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('标签模板 - 基本用法', () => {
|
|
31
|
-
function tag(strings, ...values) {
|
|
32
|
-
return strings.raw[0] + values[0].toUpperCase()
|
|
33
|
-
}
|
|
34
|
-
const name = 'world'
|
|
35
|
-
const result = tag`hello ${name}`
|
|
36
|
-
assert(result === 'hello WORLD', '标签模板应正确处理')
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
test('标签模板 - String.raw', () => {
|
|
40
|
-
const path = String.raw`C:\Users\test\n`
|
|
41
|
-
assert(path.includes('\\n'), 'String.raw 应保留原始反斜杠')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('模板字符串中调用函数', () => {
|
|
45
|
-
const upper = (s) => s.toUpperCase()
|
|
46
|
-
const str = `result: ${upper('hello')}`
|
|
47
|
-
assert(str === 'result: HELLO', '模板字符串中可调用函数')
|
|
48
|
-
})
|
|
49
|
-
|
|
50
12
|
return getResults()
|
|
51
13
|
}
|
|
@@ -13,56 +13,5 @@ export function testDestructuring() {
|
|
|
13
13
|
assert(second === 2 && fourth === 4, '数组解构可跳过元素')
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
-
test('数组解构 - 默认值', () => {
|
|
17
|
-
const [x = 10, y = 20] = [1]
|
|
18
|
-
assert(x === 1 && y === 20, '数组解构默认值')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test('数组解构 - rest 元素', () => {
|
|
22
|
-
const [first, ...rest] = [1, 2, 3, 4]
|
|
23
|
-
assert(first === 1 && rest.length === 3, '数组解构 rest 元素')
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test('数组解构 - 交换变量', () => {
|
|
27
|
-
let p = 1, q = 2;
|
|
28
|
-
[p, q] = [q, p]
|
|
29
|
-
assert(p === 2 && q === 1, '解构交换变量')
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('对象解构 - 基本', () => {
|
|
33
|
-
const { name, age } = { name: 'Alice', age: 25 }
|
|
34
|
-
assert(name === 'Alice' && age === 25, '对象解构基本用法')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('对象解构 - 重命名', () => {
|
|
38
|
-
const { name: userName, age: userAge } = { name: 'Bob', age: 30 }
|
|
39
|
-
assert(userName === 'Bob' && userAge === 30, '对象解构重命名')
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
test('对象解构 - 默认值', () => {
|
|
43
|
-
const { a = 1, b = 2 } = { a: 10 }
|
|
44
|
-
assert(a === 10 && b === 2, '对象解构默认值')
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('对象解构 - rest 属性', () => {
|
|
48
|
-
const { x, ...others } = { x: 1, y: 2, z: 3 }
|
|
49
|
-
assert(x === 1 && others.y === 2 && others.z === 3, '对象解构 rest 属性')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('嵌套解构', () => {
|
|
53
|
-
const { a: { b: { c } } } = { a: { b: { c: 42 } } }
|
|
54
|
-
assert(c === 42, '嵌套解构')
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
test('函数参数解构', () => {
|
|
58
|
-
const fn = ({ name, age = 18 }) => `${name}:${age}`
|
|
59
|
-
assert(fn({ name: 'Alice' }) === 'Alice:18', '函数参数解构')
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test('字符串解构', () => {
|
|
63
|
-
const [a, b, c] = 'abc'
|
|
64
|
-
assert(a === 'a' && b === 'b' && c === 'c', '字符串解构')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
16
|
return getResults()
|
|
68
17
|
}
|
|
@@ -3,80 +3,6 @@ import { createSuite } from '../../utils/runner.js'
|
|
|
3
3
|
export function testDefaultRestSpread() {
|
|
4
4
|
const { test, assert, getResults } = createSuite('默认参数/Rest/Spread')
|
|
5
5
|
|
|
6
|
-
// 默认参数
|
|
7
|
-
test('默认参数 - 基本', () => {
|
|
8
|
-
const greet = (name = 'World') => `Hello, ${name}!`
|
|
9
|
-
assert(greet() === 'Hello, World!', '默认参数应生效')
|
|
10
|
-
assert(greet('Alice') === 'Hello, Alice!', '传参时默认参数应被覆盖')
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
test('默认参数 - undefined 触发默认值', () => {
|
|
14
|
-
const fn = (a = 1) => a
|
|
15
|
-
assert(fn(undefined) === 1, 'undefined 触发默认参数')
|
|
16
|
-
assert(fn(null) === null, 'null 不触发默认参数')
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('默认参数 - 使用前面的参数', () => {
|
|
20
|
-
const fn = (a, b = a * 2) => b
|
|
21
|
-
assert(fn(5) === 10, '默认参数可引用前面的参数')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('默认参数 - 表达式', () => {
|
|
25
|
-
const fn = (x = Math.random()) => x
|
|
26
|
-
const result = fn()
|
|
27
|
-
assert(typeof result === 'number', '默认参数可以是表达式')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
// Rest 参数
|
|
31
|
-
test('rest 参数 - 收集剩余参数', () => {
|
|
32
|
-
const sum = (first, ...rest) => rest.reduce((acc, n) => acc + n, first)
|
|
33
|
-
assert(sum(1, 2, 3, 4) === 10, 'rest 参数应收集剩余参数')
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test('rest 参数 - 是真正的数组', () => {
|
|
37
|
-
const fn = (...args) => Array.isArray(args)
|
|
38
|
-
assert(fn(1, 2, 3) === true, 'rest 参数是真正的数组')
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test('rest 参数只能在最后', () => {
|
|
42
|
-
try {
|
|
43
|
-
new Function('function f(...a, b){}')()
|
|
44
|
-
assert(false, '应抛出 SyntaxError')
|
|
45
|
-
} catch (e) {
|
|
46
|
-
assert(true, 'rest 参数只能在最后')
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
// Spread 操作符
|
|
51
|
-
test('spread 展开数组', () => {
|
|
52
|
-
const a = [1, 2, 3]
|
|
53
|
-
const b = [0, ...a, 4]
|
|
54
|
-
assert(b.join(',') === '0,1,2,3,4', 'spread 展开数组')
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
test('spread 复制数组', () => {
|
|
58
|
-
const original = [1, 2, 3]
|
|
59
|
-
const copy = [...original]
|
|
60
|
-
copy.push(4)
|
|
61
|
-
assert(original.length === 3 && copy.length === 4, 'spread 复制数组为浅拷贝')
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test('spread 合并数组', () => {
|
|
65
|
-
const merged = [...[1, 2], ...[3, 4], ...[5]]
|
|
66
|
-
assert(merged.join(',') === '1,2,3,4,5', 'spread 合并数组')
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('spread 传入函数参数', () => {
|
|
70
|
-
const nums = [1, 2, 3]
|
|
71
|
-
assert(Math.max(...nums) === 3, 'spread 传入函数参数')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
test('spread 展开对象', () => {
|
|
75
|
-
const obj1 = { a: 1, b: 2 }
|
|
76
|
-
const obj2 = { ...obj1, c: 3 }
|
|
77
|
-
assert(obj2.a === 1 && obj2.b === 2 && obj2.c === 3, 'spread 展开对象')
|
|
78
|
-
})
|
|
79
|
-
|
|
80
6
|
test('spread 对象覆盖属性', () => {
|
|
81
7
|
const base = { a: 1, b: 2 }
|
|
82
8
|
const extended = { ...base, b: 99 }
|
|
@@ -9,77 +9,6 @@ export function testSymbols() {
|
|
|
9
9
|
assert(s1 !== s2, '相同描述的 Symbol 不相等')
|
|
10
10
|
})
|
|
11
11
|
|
|
12
|
-
test('Symbol 描述属性', () => {
|
|
13
|
-
const s = Symbol('my-symbol')
|
|
14
|
-
assert(s.description === 'my-symbol', 'Symbol.description 应返回描述字符串')
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
test('Symbol 作为对象属性键', () => {
|
|
18
|
-
const key = Symbol('key')
|
|
19
|
-
const obj = { [key]: 'value' }
|
|
20
|
-
assert(obj[key] === 'value', 'Symbol 可作为对象属性键')
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('Symbol 属性不被普通枚举', () => {
|
|
24
|
-
const sym = Symbol('hidden')
|
|
25
|
-
const obj = { [sym]: 1, visible: 2 }
|
|
26
|
-
assert(!Object.keys(obj).includes(sym.toString()), 'Symbol 属性不出现在 Object.keys 中')
|
|
27
|
-
assert(Object.getOwnPropertySymbols(obj).length === 1, 'getOwnPropertySymbols 可获取 Symbol 属性')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('Symbol.for 全局注册', () => {
|
|
31
|
-
const s1 = Symbol.for('shared')
|
|
32
|
-
const s2 = Symbol.for('shared')
|
|
33
|
-
assert(s1 === s2, 'Symbol.for 应返回同一个 Symbol')
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test('Symbol.keyFor 获取注册键', () => {
|
|
37
|
-
const s = Symbol.for('test-key')
|
|
38
|
-
assert(Symbol.keyFor(s) === 'test-key', 'Symbol.keyFor 应返回注册键')
|
|
39
|
-
const local = Symbol('local')
|
|
40
|
-
assert(Symbol.keyFor(local) === undefined, '未注册的 Symbol 返回 undefined')
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('内置 Symbol - Symbol.iterator', () => {
|
|
44
|
-
class Range {
|
|
45
|
-
constructor(start, end) { this.start = start; this.end = end }
|
|
46
|
-
[Symbol.iterator]() {
|
|
47
|
-
let current = this.start
|
|
48
|
-
const end = this.end
|
|
49
|
-
return {
|
|
50
|
-
next() {
|
|
51
|
-
return current <= end
|
|
52
|
-
? { value: current++, done: false }
|
|
53
|
-
: { done: true }
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const result = [...new Range(1, 3)]
|
|
59
|
-
assert(result.join(',') === '1,2,3', 'Symbol.iterator 自定义迭代器')
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test('内置 Symbol - Symbol.toPrimitive', () => {
|
|
63
|
-
const obj = {
|
|
64
|
-
[Symbol.toPrimitive](hint) {
|
|
65
|
-
if (hint === 'number') return 42
|
|
66
|
-
if (hint === 'string') return 'forty-two'
|
|
67
|
-
return true
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
assert(+obj === 42, 'Symbol.toPrimitive number')
|
|
71
|
-
assert(`${obj}` === 'forty-two', 'Symbol.toPrimitive string')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
test('Symbol.hasInstance', () => {
|
|
75
|
-
class EvenNumber {
|
|
76
|
-
static [Symbol.hasInstance](num) {
|
|
77
|
-
return Number.isInteger(num) && num % 2 === 0
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
assert(2 instanceof EvenNumber, '2 应为 EvenNumber 实例')
|
|
81
|
-
assert(!(3 instanceof EvenNumber), '3 不应为 EvenNumber 实例')
|
|
82
|
-
})
|
|
83
12
|
|
|
84
13
|
return getResults()
|
|
85
14
|
}
|
|
@@ -29,76 +29,5 @@ export function testIteratorsGenerators() {
|
|
|
29
29
|
assert(result.join(',') === '10,20,30', 'for...of 迭代数组')
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
test('字符串是可迭代的', () => {
|
|
33
|
-
const chars = [...'hello']
|
|
34
|
-
assert(chars.length === 5 && chars[0] === 'h', '字符串可用 for...of 迭代')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('基本生成器函数', () => {
|
|
38
|
-
function* gen() {
|
|
39
|
-
yield 1
|
|
40
|
-
yield 2
|
|
41
|
-
yield 3
|
|
42
|
-
}
|
|
43
|
-
const g = gen()
|
|
44
|
-
assert(g.next().value === 1, '生成器第一个 yield')
|
|
45
|
-
assert(g.next().value === 2, '生成器第二个 yield')
|
|
46
|
-
assert(g.next().value === 3, '生成器第三个 yield')
|
|
47
|
-
assert(g.next().done === true, '生成器结束')
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('生成器可作为可迭代对象', () => {
|
|
51
|
-
function* range(start, end) {
|
|
52
|
-
for (let i = start; i <= end; i++) yield i
|
|
53
|
-
}
|
|
54
|
-
const result = [...range(1, 5)]
|
|
55
|
-
assert(result.join(',') === '1,2,3,4,5', '生成器展开为数组')
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('生成器 yield* 委托', () => {
|
|
59
|
-
function* inner() { yield 'a'; yield 'b' }
|
|
60
|
-
function* outer() { yield 1; yield* inner(); yield 2 }
|
|
61
|
-
const result = [...outer()]
|
|
62
|
-
assert(result.join(',') === '1,a,b,2', 'yield* 委托生成器')
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
test('生成器双向通信', () => {
|
|
66
|
-
function* adder() {
|
|
67
|
-
let total = 0
|
|
68
|
-
while (true) {
|
|
69
|
-
const n = yield total
|
|
70
|
-
if (n === null) break
|
|
71
|
-
total += n
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const g = adder()
|
|
75
|
-
g.next() // 启动
|
|
76
|
-
g.next(5) // total = 5
|
|
77
|
-
g.next(3) // total = 8
|
|
78
|
-
const { value } = g.next(2) // total = 10
|
|
79
|
-
assert(value === 10, '生成器双向通信')
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('无限序列生成器', () => {
|
|
83
|
-
function* fibonacci() {
|
|
84
|
-
let [a, b] = [0, 1]
|
|
85
|
-
while (true) {
|
|
86
|
-
yield a;
|
|
87
|
-
[a, b] = [b, a + b]
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const fib = fibonacci()
|
|
91
|
-
const first8 = Array.from({ length: 8 }, () => fib.next().value)
|
|
92
|
-
assert(first8.join(',') === '0,1,1,2,3,5,8,13', '斐波那契生成器')
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test('生成器 return 方法提前结束', () => {
|
|
96
|
-
function* gen() { yield 1; yield 2; yield 3 }
|
|
97
|
-
const g = gen()
|
|
98
|
-
assert(g.next().value === 1, '第一个值')
|
|
99
|
-
assert(g.return('done').value === 'done', 'return 方法')
|
|
100
|
-
assert(g.next().done === true, '提前结束后 done 为 true')
|
|
101
|
-
})
|
|
102
|
-
|
|
103
32
|
return getResults()
|
|
104
33
|
}
|
|
@@ -15,92 +15,7 @@ export function testMapSet() {
|
|
|
15
15
|
assert(m.size === 1, '删除后 size 应为 1')
|
|
16
16
|
})
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
const m = new Map()
|
|
20
|
-
const obj = {}
|
|
21
|
-
const fn = () => {}
|
|
22
|
-
m.set(obj, 'object-value')
|
|
23
|
-
m.set(fn, 'function-value')
|
|
24
|
-
m.set(42, 'number-value')
|
|
25
|
-
assert(m.get(obj) === 'object-value', '对象作为键')
|
|
26
|
-
assert(m.get(fn) === 'function-value', '函数作为键')
|
|
27
|
-
assert(m.get(42) === 'number-value', '数字作为键')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('Map 从数组初始化', () => {
|
|
31
|
-
const m = new Map([['x', 10], ['y', 20]])
|
|
32
|
-
assert(m.get('x') === 10 && m.get('y') === 20, 'Map 从数组初始化')
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('Map 迭代', () => {
|
|
36
|
-
const m = new Map([['a', 1], ['b', 2], ['c', 3]])
|
|
37
|
-
const keys = [...m.keys()]
|
|
38
|
-
const values = [...m.values()]
|
|
39
|
-
const entries = [...m.entries()]
|
|
40
|
-
assert(keys.join(',') === 'a,b,c', 'Map.keys 迭代')
|
|
41
|
-
assert(values.join(',') === '1,2,3', 'Map.values 迭代')
|
|
42
|
-
assert(entries.length === 3, 'Map.entries 迭代')
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test('Map forEach', () => {
|
|
46
|
-
const m = new Map([['a', 1], ['b', 2]])
|
|
47
|
-
let result = ''
|
|
48
|
-
m.forEach((v, k) => { result += `${k}=${v} ` })
|
|
49
|
-
assert(result.trim() === 'a=1 b=2', 'Map.forEach 遍历')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// Set
|
|
53
|
-
test('Set 基本操作', () => {
|
|
54
|
-
const s = new Set([1, 2, 3, 2, 1])
|
|
55
|
-
assert(s.size === 3, 'Set 自动去重,size 应为 3')
|
|
56
|
-
assert(s.has(2) === true, 'Set.has 检查元素')
|
|
57
|
-
s.delete(2)
|
|
58
|
-
assert(s.has(2) === false, 'Set.delete 删除元素')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
test('Set 数组去重', () => {
|
|
62
|
-
const arr = [1, 2, 2, 3, 3, 4]
|
|
63
|
-
const unique = [...new Set(arr)]
|
|
64
|
-
assert(unique.join(',') === '1,2,3,4', 'Set 用于数组去重')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('Set 迭代', () => {
|
|
68
|
-
const s = new Set(['a', 'b', 'c'])
|
|
69
|
-
const result = []
|
|
70
|
-
for (const val of s) result.push(val)
|
|
71
|
-
assert(result.join(',') === 'a,b,c', 'Set for...of 迭代')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
test('Set 集合运算', () => {
|
|
75
|
-
const a = new Set([1, 2, 3, 4])
|
|
76
|
-
const b = new Set([3, 4, 5, 6])
|
|
77
|
-
const union = new Set([...a, ...b])
|
|
78
|
-
const intersection = new Set([...a].filter(x => b.has(x)))
|
|
79
|
-
const difference = new Set([...a].filter(x => !b.has(x)))
|
|
80
|
-
assert([...union].join(',') === '1,2,3,4,5,6', 'Set 并集')
|
|
81
|
-
assert([...intersection].join(',') === '3,4', 'Set 交集')
|
|
82
|
-
assert([...difference].join(',') === '1,2', 'Set 差集')
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
// WeakMap & WeakSet
|
|
86
|
-
test('WeakMap 基本操作', () => {
|
|
87
|
-
const wm = new WeakMap()
|
|
88
|
-
const key = {}
|
|
89
|
-
wm.set(key, 'value')
|
|
90
|
-
assert(wm.has(key) === true, 'WeakMap.has 应返回 true')
|
|
91
|
-
assert(wm.get(key) === 'value', 'WeakMap.get 应返回正确值')
|
|
92
|
-
wm.delete(key)
|
|
93
|
-
assert(wm.has(key) === false, 'WeakMap.delete 删除成功')
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
test('WeakSet 基本操作', () => {
|
|
97
|
-
const ws = new WeakSet()
|
|
98
|
-
const obj = {}
|
|
99
|
-
ws.add(obj)
|
|
100
|
-
assert(ws.has(obj) === true, 'WeakSet.has 应返回 true')
|
|
101
|
-
ws.delete(obj)
|
|
102
|
-
assert(ws.has(obj) === false, 'WeakSet.delete 删除成功')
|
|
103
|
-
})
|
|
18
|
+
|
|
104
19
|
|
|
105
20
|
return getResults()
|
|
106
21
|
}
|
|
@@ -33,90 +33,7 @@ export function testProxyReflect() {
|
|
|
33
33
|
}
|
|
34
34
|
})
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
const range = { min: 1, max: 10 }
|
|
38
|
-
const proxy = new Proxy(range, {
|
|
39
|
-
has(target, key) {
|
|
40
|
-
const num = Number(key)
|
|
41
|
-
return num >= target.min && num <= target.max
|
|
42
|
-
}
|
|
43
|
-
})
|
|
44
|
-
assert(5 in proxy, '5 在范围内')
|
|
45
|
-
assert(!(11 in proxy), '11 不在范围内')
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test('Proxy deleteProperty 拦截', () => {
|
|
49
|
-
const proxy = new Proxy({ a: 1, b: 2 }, {
|
|
50
|
-
deleteProperty(target, key) {
|
|
51
|
-
if (key === 'b') throw new Error('b 不可删除')
|
|
52
|
-
delete target[key]
|
|
53
|
-
return true
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
delete proxy.a
|
|
57
|
-
assert(!('a' in proxy), 'a 已删除')
|
|
58
|
-
try {
|
|
59
|
-
delete proxy.b
|
|
60
|
-
assert(false, '应抛出错误')
|
|
61
|
-
} catch (e) {
|
|
62
|
-
assert(e.message === 'b 不可删除', 'b 删除被拦截')
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
test('Proxy apply 拦截函数调用', () => {
|
|
67
|
-
function sum(a, b) { return a + b }
|
|
68
|
-
const proxy = new Proxy(sum, {
|
|
69
|
-
apply(target, thisArg, args) {
|
|
70
|
-
return target(...args) * 2
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
assert(proxy(3, 4) === 14, 'Proxy apply 拦截函数调用')
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('Proxy construct 拦截 new', () => {
|
|
77
|
-
class Animal {
|
|
78
|
-
constructor(name) { this.name = name }
|
|
79
|
-
}
|
|
80
|
-
const proxy = new Proxy(Animal, {
|
|
81
|
-
construct(target, args) {
|
|
82
|
-
const instance = new target(...args)
|
|
83
|
-
instance.created = true
|
|
84
|
-
return instance
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
const a = new proxy('Cat')
|
|
88
|
-
assert(a.name === 'Cat' && a.created === true, 'Proxy construct 拦截')
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// Reflect
|
|
92
|
-
test('Reflect.get', () => {
|
|
93
|
-
const obj = { x: 42 }
|
|
94
|
-
assert(Reflect.get(obj, 'x') === 42, 'Reflect.get 获取属性')
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
test('Reflect.set', () => {
|
|
98
|
-
const obj = {}
|
|
99
|
-
Reflect.set(obj, 'y', 100)
|
|
100
|
-
assert(obj.y === 100, 'Reflect.set 设置属性')
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
test('Reflect.has', () => {
|
|
104
|
-
const obj = { a: 1 }
|
|
105
|
-
assert(Reflect.has(obj, 'a') === true, 'Reflect.has 检查属性')
|
|
106
|
-
assert(Reflect.has(obj, 'z') === false, 'Reflect.has 不存在属性')
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
test('Reflect.ownKeys', () => {
|
|
110
|
-
const sym = Symbol('s')
|
|
111
|
-
const obj = { a: 1, [sym]: 2 }
|
|
112
|
-
const keys = Reflect.ownKeys(obj)
|
|
113
|
-
assert(keys.includes('a') && keys.includes(sym), 'Reflect.ownKeys 返回所有键含 Symbol')
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('Reflect.apply', () => {
|
|
117
|
-
const result = Reflect.apply(Math.max, null, [1, 2, 3])
|
|
118
|
-
assert(result === 3, 'Reflect.apply 调用函数')
|
|
119
|
-
})
|
|
36
|
+
|
|
120
37
|
|
|
121
38
|
return getResults()
|
|
122
39
|
}
|