一、支持大部分 ES6 特性

1.class

下面是关于 ES6 引入的经典类的试验代码:

  1. /*参数类型异常 :用于封装参数类型异常信息*/
  2. class ParameterTypeError extends Error {
  3. constructor(paramName, paramType) {
  4. if (!(typeof paramName == 'string'))
  5. throw new ParameterTypeError('paramName', String);
  6. if (!(paramType instanceof Function))
  7. throw new ParameterTypeError('paramType', Function);
  8. let msg = 'Parameter "' + paramName +
  9. '" must be a ' + paramType.name +
  10. ' object.';
  11. super(msg);
  12. this.ParameterName = paramName;
  13. this.ParameterType = paramType;
  14. }
  15. toString() {
  16. return ParameterTypeError.name + ' : ' + this.message;
  17. }
  18. static check(param, paramName, paramType) {
  19. if (!((param instanceof paramType) ||
  20. (typeof param == paramType.name.toLowerCase())))
  21. throw new ParameterTypeError(paramName, paramType);
  22. }
  23. }
  24. /*经典类
  25. 它只支持如下形式:
  26. class ClassName {
  27. //现行(ES6)支持的类成员类型如下:
  28. InstanceMethod() {...}
  29. static StaticMethod() {...}
  30. get InstanceProperty() {...}
  31. set InstanceProperty(value) {...}
  32. static get StaticProperty() {...}
  33. static set StaticProperty(value) {...}
  34. //ES2022 state4(finished) 提案增补类成员类型如下:
  35. InstanceField //公有实例字段
  36. #PrivateInstanceField
  37. #PrivateInstanceMethod() {...}
  38. get #PrivateInstanceProperty {...}
  39. set #PrivateInstanceProperty {...}
  40. static StaticField //公有静态字段
  41. static #PrivateStaticField
  42. static #PrivateStaticMethod {...}
  43. //暂缺提案支持的成员类型如下:
  44. static get #PrivateStaticProperty {...}
  45. static set #PrivateStaticProperty {...}
  46. //TC39 state3 阶段提案支持
  47. static {...} //静态构造函数
  48. }*/
  49. class Point {
  50. constructor(x, y) {
  51. ParameterTypeError.check(x, 'x', Number);
  52. ParameterTypeError.check(y, 'y', Number);
  53. this.x = x;
  54. this.y = y;
  55. Point.count++;
  56. }
  57. static get count() {
  58. if (Point._count == undefined)
  59. Point._count = 0;
  60. return Point._count;
  61. }
  62. static set count(value) {
  63. if (Point._count == undefined)
  64. Point._count = 0;
  65. Point._count = value;
  66. }
  67. static get Version() {
  68. return '2D';
  69. }
  70. toString() {
  71. return '(' + this.x + ', ' + this.y + ')';
  72. }
  73. distanceTo(p) {
  74. ParameterTypeError.check(p, 'p', Point);
  75. return Math.sqrt(
  76. Math.pow(this.x - p.x, 2) +
  77. Math.pow(this.y - p.y, 2));
  78. }
  79. static distanceBetween(p1, p2) {
  80. ParameterTypeError.check(p1, 'p1', Point);
  81. ParameterTypeError.check(p2, 'p2', Point);
  82. return Math.sqrt(
  83. Math.pow(p1.x - p2.x, 2) +
  84. Math.pow(p1.y - p2.y, 2));
  85. }
  86. }
  87. class NamedPoint extends Point {
  88. constructor(name, x, y) {
  89. ParameterTypeError.check(name, 'name', String);
  90. super(x, y);
  91. this._name = name;
  92. }
  93. get name() {
  94. return this._name;
  95. }
  96. toString() {
  97. return this._name + super.toString();
  98. }
  99. }
  100. function classTest() {
  101. let p = new Point(3, 4);
  102. Console.log('p = ' + p);
  103. let np = new NamedPoint("ShotTarget", 6, 8);
  104. Console.log('np = ' + np);
  105. //为只读属性赋值是无效的,但也不报错
  106. np.name = "WTF";
  107. Console.log('np = ' + np);
  108. Console.log('np.name = ' + np.name);
  109. Console.log('p.distanceTo(np) = ' + p.distanceTo(np));
  110. Console.log('instance count : ' + Point.count);
  111. //静态方法,会被子类继承
  112. Console.log(NamedPoint.distanceBetween(np, p));
  113. //实例方法,会被子类继承
  114. Console.log(np.distanceTo(p));
  115. //静态属性
  116. Console.log('static property Version : ' + Point.Version);
  117. //静态属性,会被子类继承
  118. Console.log(NamedPoint.count);
  119. //自定义异常
  120. try {
  121. p.distanceTo(33);
  122. } catch(e) {
  123. Console.log(e.message);
  124. Console.log(e);
  125. }
  126. }

其输出如下:

  1. p = (3, 4)
  2. np = ShotTarget(6, 8)
  3. np = ShotTarget(6, 8)
  4. np.name = ShotTarget
  5. p.distanceTo(np) = 5
  6. instance count : 2
  7. 5
  8. 5
  9. static property Version : 2D
  10. 2
  11. Parameter "p" must be a Point object.
  12. ParameterTypeError : Parameter "p" must be a Point object.

2.Proxy

  1. //居中填充
  2. String.prototype.padCenter =
  3. function(targetLength, padString = ' ') {
  4. if (typeof targetLength != 'number')
  5. throw new TypeError('Parameter "targetLength" ' +
  6. 'must be a number object.');
  7. if (typeof padString != 'string') {
  8. if (padString === null)
  9. padString = 'null';
  10. else
  11. padString = padString.toString();
  12. }
  13. let padStrWidth = padString.length;
  14. if (padStrWidth == 0) return this;
  15. let restWidth = targetLength - this.length;
  16. if (restWidth <= 0) return this;
  17. let leftWidth = Math.trunc(restWidth / 2);
  18. let rightWidth = leftWidth + restWidth % 2;
  19. if (padString.length == 1) {
  20. return padString.repeat(leftWidth) + this +
  21. padString.repeat(rightWidth);
  22. } else {
  23. if (leftWidth == 0)
  24. return this + padString[0];
  25. else {
  26. //leftPart
  27. let leftRepeat = Math.trunc(leftWidth / padStrWidth);
  28. let leftRest = leftWidth - leftRepeat * padStrWidth;
  29. let leftStr = padString.repeat(leftRepeat) +
  30. padString.substr(0, leftRest);
  31. //rightPart
  32. let rightRepeat = Math.trunc(rightWidth / padStrWidth);
  33. let rightRest = rightWidth - rightRepeat * padStrWidth;
  34. let rightStr = padString.repeat(rightRepeat) +
  35. padString.substr(0, rightRest);
  36. return leftStr + this + rightStr;
  37. }
  38. }
  39. }
  40. /*Proxy handler 可对应于
  41. Reflect.apply()
  42. Reflect.construct()
  43. Reflect.defineProperty()
  44. Reflect.deleteProperty()
  45. Reflect.get()
  46. Reflect.getOwnPropertyDescriptor()
  47. Reflect.getPrototypeOf()
  48. Reflect.has()
  49. Reflect.isExtensible()
  50. Reflect.ownKeys()
  51. Reflect.preventExtensions()
  52. Reflect.set()
  53. Reflect.setPrototypeOf()
  54. 实现想要的代理
  55. */
  56. class ES6ProxyTest {
  57. //既然 Reflect.set(target, key, value[, receiver]) 有
  58. //要设置的属性的键和值,我们就可以通过 set 代理,在一个
  59. //对象的定义的外部:
  60. //1.通过键,拦截对某些属性的写入
  61. //2.通过值,检验类型,拦截非法写入
  62. //3.通过键,重定向属性的写入,就像为属性设置一些假名一样
  63. static SetProxy() {
  64. let p = new Point(3, 8);
  65. let pp = new Proxy(p, {
  66. set:function(target, key, value, receiver){
  67. //Reflect.set(target, key, value[, receiver])
  68. //target : 用于接收属性(被代理的对象)的对象
  69. //key : 要写入的属性的键(字符串或Symbol类型)
  70. //value : 要写入的属性新值
  71. //receiver : 如果 target 对象的 key 属性有 setter,
  72. // receiver 则为 setter 调用时的 this 值。
  73. //return : 返回一个 Boolean 值,表明操作的成败
  74. let success = Reflect.set(target, key, value, receiver);
  75. if (success) {
  76. //Console 在此不可用
  77. Debug.Print('property '+ key +' on '+
  78. target + ' set to '+ value);
  79. }
  80. //必须返回操作成败状态,否则报错
  81. return success;
  82. }
  83. });
  84. pp.xxx = 13;
  85. Console.log(p.xxx);
  86. }
  87. //既然 Reflect.get(target, key[, receiver]) 提供了要读取
  88. //的属性的键,我们就可以通过 get 代理,在对象的定义的外部:
  89. //1.通过键,拦截对某些属性的读取
  90. //2.通过键,伪造一些不存在的属性
  91. //3.通过键,实现类同假名的属性
  92. static GetProxy() {
  93. var obj = new Proxy({}, {
  94. get: function (target, key, receiver) {
  95. //Console 在此不可用
  96. Debug.Print(`getting ${key}!`);
  97. //Reflect.get(target, key[, receiver])
  98. //target : 被代理的对象
  99. //key : 要读取的属性的键(字符串或Symbol类型)
  100. //receiver : 如果 target 对象的 key 属性有 getter,
  101. // receiver 则为 getter 调用时的 this 值。
  102. //return : 属性的值。
  103. return Reflect.get(target, key, receiver);
  104. }
  105. });
  106. obj.count = 1;
  107. ++obj.count;
  108. }
  109. /*Reflect.apply(target, thisArg, argsList)
  110. target : 被代理对象,请确保它是一个 Function 对象
  111. thisArg : 函数调用时绑定的对象
  112. argsList : 函数调用时传入的实参列表,该参数应该是一个类数组的对象。
  113. return : 调用函数返回的结果
  114. 通过这种代理:
  115. 1.检验调用时传入的参数
  116. 2.阻止函数被调用
  117. */
  118. static ApplyProxy() {
  119. function sum (...values){
  120. return values.reduce((pre, cur) => pre + cur, 0);
  121. }
  122. let sumProxy = new Proxy(sum, {
  123. apply : function(target, thisArg, argsList){
  124. argsList.forEach(arg => {
  125. if(typeof arg !== "number")
  126. throw new TypeError("所有参数必须是数字,亲!");
  127. });
  128. return Reflect.apply(target, thisArg, argsList);
  129. }
  130. });
  131. try {
  132. let r = sumProxy(3, 5, 'hello');
  133. Console.log(r);
  134. } catch(e) {
  135. Console.log(e.message);
  136. }
  137. Console.log(sumProxy(3, 8, 5));
  138. }
  139. /*Reflect.construct(target, argsList[, newTarget])
  140. target : 被运行的目标构造函数
  141. argsList : 类数组,目标构造函数调用时的参数。
  142. newTarget : 可选,作为新创建对象的原型对象的 constructor 属性,
  143. 参考 new.target 操作符,默认值为 target。
  144. */
  145. static ConstructProxy() {
  146. function sum (...values){
  147. return values.reduce((pre, cur) => pre + cur, 0);
  148. }
  149. let sumProxy = new Proxy(sum, {
  150. construct:function(target, argsList){
  151. throw new TypeError("亲,该函数不能通过 new 调用。");
  152. }
  153. });
  154. try {
  155. let x = new sumProxy(3, 5, 7);
  156. } catch(e) {
  157. Console.log(e.message);
  158. }
  159. }
  160. //禁止向指定单元格区域写入数据
  161. static ForbidSetValue() {
  162. let rng = new Range('B1:D3');
  163. rng.Value2 = 32;
  164. let rngProxy = new Proxy(rng, {
  165. set : function(target, key, value, receiver) {
  166. if (key === 'Value2') {
  167. throw new Error('无法设置属性')
  168. } else
  169. return Reflect.set(target, key, value, receiver);
  170. }
  171. });
  172. try {
  173. rngProxy.Value2 = 168;
  174. } catch(e) {
  175. Console.log(e.message);
  176. }
  177. Console.log(rngProxy.Text);
  178. }
  179. //运行所有测试用例
  180. static RunAll() {
  181. let members = Object.getOwnPropertyNames(ES6ProxyTest);
  182. let notCall = ['length', 'prototype', 'name', 'RunAll'];
  183. for (let member of members) {
  184. if (!notCall.includes(member)) {
  185. Console.log(member.padCenter(56, '-'));
  186. eval(`ES6ProxyTest.${member}()`);
  187. }
  188. }
  189. }
  190. }

在立即窗口中输入 ES6ProxyTest.RunAll(); ,然后回车,其输出如下:

  1. ------------------------SetProxy------------------------
  2. property xxx on (3, 8) set to 13
  3. 13
  4. ------------------------GetProxy------------------------
  5. getting count!
  6. -----------------------ApplyProxy-----------------------
  7. 所有参数必须是数字,亲!
  8. 16
  9. ---------------------ConstructProxy---------------------
  10. 亲,该函数不能通过 new 调用。
  11. ---------------------ForbidSetValue---------------------
  12. 无法设置属性
  13. 32

二、实测支持到 ES2019

0.示例代码运行环境的设置代码

因为使用了全局表达式,请将【工具】》【选项】》【编译】》【禁止全局作用域表达式】取消勾选

  1. //获取字符串位宽(即字符串占的字符宽度)
  2. String.prototype.byteWidth = function() {
  3. var length = 0;
  4. Array.from(this).map(function(char){
  5. //字符编码大于255,说明是双字节字符
  6. if (char.charCodeAt(0) > 255) {
  7. length += 2;
  8. } else {
  9. length++;
  10. }
  11. });
  12. return length;
  13. };
  14. {/*Console 对象的增强*/
  15. //控制台默认分隔线字符
  16. Console.__proto__.DefaultSepLineSepChar = '-';
  17. //控制台默认的分隔线宽度
  18. Console.__proto__.DefaultSepLineWidth = 56;
  19. //向控制台输出分隔线
  20. Console.__proto__.PrintSepLine =
  21. function(byteWidth, sepChar) {
  22. if (sepChar == undefined)
  23. sepChar = this.DefaultSepLineSepChar;
  24. else
  25. sepChar = sepChar.toString()[0];
  26. if (byteWidth == undefined)
  27. byteWidth = this.DefaultSepLineWidth;
  28. if (typeof byteWidth != 'number' ||
  29. byteWidth < 0)
  30. throw new Error('byteWidth 必须是非负数');
  31. else
  32. byteWidth = Math.floor(byteWidth);
  33. let sepLine;
  34. if (sepChar.byteWidth() == 1)
  35. sepLine = sepChar.repeat(byteWidth);
  36. else
  37. sepLine = sepChar.repeat(byteWidth / 2);
  38. Console.log(sepLine);
  39. };
  40. //向控制台输出分隔线
  41. Console.__proto__.PrintNamedSepLine =
  42. function(name, byteWidth, sepChar) {
  43. if (name == undefined)
  44. throw new Error('必须提供 name 参数');
  45. else
  46. name = name.toString()
  47. .replace('\n', '')
  48. .replace('\r', '');
  49. if (sepChar == undefined)
  50. sepChar = this.DefaultSepLineSepChar;
  51. else
  52. sepChar = sepChar.toString()[0];
  53. if (byteWidth == undefined)
  54. byteWidth = this.DefaultSepLineWidth;
  55. if (typeof byteWidth != 'number' ||
  56. byteWidth < 0)
  57. throw new Error('byteWidth 必须是非负数');
  58. else
  59. byteWidth = Math.floor(byteWidth);
  60. let sepLine = name;
  61. let selfWidth = name.byteWidth();
  62. if (byteWidth > selfWidth) {
  63. let restWidth = byteWidth - selfWidth;
  64. let leftPadWidth = Math.floor(restWidth / 2);
  65. let rightWidth = Math.floor(restWidth / 2) +
  66. restWidth % 2;
  67. if (sepChar.byteWidth() == 1)
  68. sepLine = sepChar.repeat(leftPadWidth) +
  69. sepLine + sepChar.repeat(rightWidth);
  70. else
  71. sepLine = sepChar.repeat(leftPadWidth / 2) +
  72. sepLine + sepChar.repeat(rightWidth /2);
  73. }
  74. Console.log(sepLine);
  75. };
  76. //向控制台一次输出多个值,避免手动拼接字符串
  77. Console.__proto__.WriteAll = function() {
  78. if (arguments.length == 0) return;
  79. let info = Array.prototype.map
  80. .call(arguments, v => {
  81. if (v === null)
  82. return 'null';
  83. else if(v === undefined)
  84. return 'undefined';
  85. else
  86. return v.toString();
  87. })
  88. .join('; ');
  89. Console.log(info);
  90. };
  91. //向控制台作讲述式输出
  92. Console.__proto__.Tell = function(description, value) {
  93. if (value === null)
  94. Console.log(description + ' : null');
  95. else if (value === undefined)
  96. Console.log(description + ' : undefined');
  97. else
  98. Console.log(description + ' : ' + value.toString());
  99. };
  100. }

1.ES2016_ES7 特性测试

  1. function ES2016_ES7() {
  2. //ES2016 只添加了两个功能:
  3. let arr = [1, 2, 3];
  4. //1. Array.prototype.includes()
  5. if (typeof arr.includes == 'function') {
  6. Console.Tell('arr.includes(2)', arr.includes(2));
  7. Console.Tell('arr.includes(31)', arr.includes(31));
  8. }
  9. //2. 指数运算符
  10. Console.Tell('3**3', 3**3);
  11. }

2.ES2017_ES8 特性测试

  1. function ES2017_ES8() {
  2. let obj = { one : 1, two : 2, three : 3 };
  3. //1.Object.values() 获取对象的所有属性值
  4. Console.PrintNamedSepLine('Object.values(obj)');
  5. if (typeof Object.values == 'function') {
  6. let values = Object.values(obj);
  7. Console.log(values instanceof Array);
  8. Console.log(values.toString());
  9. }
  10. //2.Object.entries() 获取对象的属性名-值对
  11. Console.PrintNamedSepLine('Object.entries(obj)');
  12. if (typeof Object.entries == 'function') {
  13. let entries = Object.entries(obj);
  14. Console.log(entries instanceof Array);
  15. Console.log(entries[0] instanceof Array);
  16. Console.log(entries[0][0] + ' : ' + entries[0][1]);
  17. for (let [k, v] of entries)
  18. Console.log(k + ' => ' + v);
  19. }
  20. //3.Object.getOwnPropertyDescriptors() 获取一个对象的所有自身属性的
  21. // 描述符。属性描述符(property descriptor)对象:
  22. //value:就是属性的值,默认 undefined
  23. //writable:决定属性能否被赋值
  24. //get:访问器函数(getter),函数或 undefined,在取属性值时被调用
  25. //set:设置器函数(setter),函数或 undefined,在设置属性值时被调用
  26. //enumerable:决定 for in 或 Object.keys 能否枚举该属性
  27. //configurable:决定该属性能否被删除,以及除 value 和 writable 外的
  28. // 其他特性是否可以被修改
  29. Console.PrintNamedSepLine('Object.getOwnPropertyDescriptors(obj)');
  30. if (typeof Object.getOwnPropertyDescriptors == 'function') {
  31. let x = Object.getOwnPropertyDescriptors(obj);
  32. Console.Tell('Object.getOwnPropertyDescriptors(obj)', x);
  33. }
  34. //4.String.prototype.padStart()/padEnd() 字符串左/右填充
  35. Console.PrintNamedSepLine('String.padStart/padEnd');
  36. if (typeof String.prototype.padStart === 'function' &&
  37. typeof String.prototype.padEnd == 'function') {
  38. let str = 'hello';
  39. Console.log(str.padStart(10, '+'));
  40. Console.log(str.padEnd(10, '-'));
  41. }
  42. //5.结尾逗号,对象定义、数组定义和函数参数列表等等
  43. Console.PrintNamedSepLine('尾逗号');
  44. {
  45. let gift = {
  46. Name : 'Computer',
  47. Price : 5000,
  48. Color : 'black',
  49. };
  50. Console.log(JSON.stringify(gift));
  51. let exGrilFriends = [
  52. 'Lily Morgen',
  53. 'John Smith',
  54. 'Kate William',
  55. ];
  56. Console.log(exGrilFriends.toString());
  57. let func = function(
  58. firstPartNumber,
  59. secondPartNumber,
  60. ) { Console.log(firstPartNumber + '/' + secondPartNumber); }
  61. func(321, 123);
  62. }
  63. //6.ShareArrayBuffer ...
  64. }

3.ES2018_ES9 特性测试

  1. function ES2018_ES9() {
  2. {//1.剩余参数
  3. Console.PrintNamedSepLine('剩余参数');
  4. let func = function(a, b, ...rest) {
  5. let sum = a + b;
  6. if (rest.length == 0)
  7. return sum;
  8. else {
  9. for (let x of rest)
  10. sum += x;
  11. return sum;
  12. }
  13. };
  14. Console.log(func(1, 2));
  15. Console.log(func(1, 2, 3));
  16. Console.log(func(1, 2, 3, 4));
  17. }
  18. {//2.正则表达式 s 模式,dotAll,即包含换行符
  19. Console.PrintNamedSepLine('正则表达式 s 模式');
  20. let isMatch = /hello.es9/.test('hello\nes9');
  21. Console.log(isMatch);
  22. isMatch = /hello.es9/s.test('hello\nes9');
  23. Console.log(isMatch);
  24. }
  25. {//3.正则之命名捕获组
  26. Console.PrintNamedSepLine('正则之命名捕获组');
  27. let str = "Jim is 12.";
  28. let re = /(?<name>\w+) is (?<age>\d+)/;
  29. let matches = re.exec(str);
  30. Console.log(matches.toString());
  31. for (let ppt in matches)
  32. Console.log(ppt);
  33. Console.log(matches.groups);
  34. for (let ppt in matches.groups)
  35. Console.log(ppt);
  36. Console.log('age is ' + matches.groups['age']);
  37. }
  38. {//4.正则表达式之反向断言
  39. Console.PrintNamedSepLine('正则表达式之反向断言');
  40. let s = 'he is 12 years old. he has 3 cars.';
  41. //4.1.右匹配断言 : (?=...)
  42. Console.log('4.1 => ' + s.match(/\d+(?= cars)/));
  43. //4.2.右不匹配断言 : (?!...)
  44. Console.log('4.2 => ' + s.match(/\d+(?! cars)/));
  45. //4.3.左匹配断言 : (?<=...)
  46. Console.log('4.3 => ' + s.match(/(?<=has )\d+/));
  47. //4.2.左不匹配断言 : (?<!...)
  48. Console.log('4.4 => ' + s.match(/(?<!has )\d+/));
  49. }
  50. {//5.正则表达式 u 模式,即字符集模式,支持\p{字符集名},
  51. // 或\P{字符集名}形式匹配...
  52. Console.PrintNamedSepLine('正则表达式 u 模式')
  53. let re = /\p{White_Space}+/u;
  54. let wsStrs = ['\n', '\r', ' ', '\n\r'];
  55. wsStrs.forEach(x => Console.log(re.test(x)));
  56. }
  57. //6.async/await...
  58. //7.promise.finally...
  59. }

4.ES2019_ES10 特性测试

  1. function ES2019_ES10 () {
  2. //1.Object.fromEntries() 从对象的属性名值对数组转换回对象,
  3. // 与 Object.entries() 功能相反;NA
  4. Console.PrintNamedSepLine('Object.fromEntries');
  5. if (typeof Object.fromEntries == 'function') {
  6. let obj = { one : 1, two : 2, three : 3 };
  7. let entries = Object.entries(obj);
  8. let objSame = Object.fromEntries(entries);
  9. Console.log(objSame);
  10. }
  11. //2.Array.prototype.flat 将数组打平
  12. Console.PrintNamedSepLine('Array.prototype.flat([depth])');
  13. if (typeof Array.prototype.flat === 'function') {
  14. Console.Tell('[1, [2, 3]].flat()', JSON.stringify(
  15. [1, [2, 3]].flat()));
  16. Console.Tell('[1, [2, 3, [1]]].flat()', JSON.stringify(
  17. [1, [2, 3, [1]]].flat()));
  18. Console.Tell('[1, [2, 3, [1]]].flat(2)', JSON.stringify(
  19. [1, [2, 3, [1]]].flat(2)));
  20. }
  21. //3.Array.prototype.flatMap 类同于 Linq-SelectMany
  22. Console.PrintNamedSepLine('Array.prototype.flatMap');
  23. if (typeof Array.prototype.flatMap === 'function') {
  24. Console.Tell('[1, [2, 3]].flatMap(x => x)', JSON
  25. .stringify([1, [2, 3]].flatMap(x => x)));
  26. let strs = ['Jobs Steven', 'is', 'great'];
  27. let elementProcessor = x => x.split(' ');
  28. Console.log(JSON.stringify(strs) + '.flatMap(' +
  29. elementProcessor.toString() + ') :\n' +
  30. JSON.stringify(strs.flatMap(elementProcessor)));
  31. Console.log('[1, 2, 3].map(x => [x * 2]) :\n' +
  32. JSON.stringify([1, 2, 3].map(x => [x * 2])));
  33. Console.log('[1, 2, 3].flatMap(x => [x * 2]) :\n' +
  34. JSON.stringify([1, 2, 3].flatMap(x => [x * 2])));
  35. }
  36. //4.String.prototype.trimStart/trimEnd
  37. Console.PrintNamedSepLine('String.prototype.trimStart/trimEnd');
  38. if (typeof String.prototype.trimStart === 'function' &&
  39. typeof String.prototype.trimEnd === 'function') {
  40. let s = ' yes ';
  41. Console.log(JSON.stringify(s) + '.trimStart() = ' +
  42. JSON.stringify(s.trimStart()));
  43. Console.log(JSON.stringify(s) + '.trimEnd() = ' +
  44. JSON.stringify(s.trimEnd()));
  45. }
  46. //5.Symbol.protoype.description
  47. Console.PrintNamedSepLine('Symbol.protoype.description');
  48. if (Symbol.iterator.description != undefined) {
  49. Console.log('Symbol.iterator.description = ' +
  50. Symbol.iterator.description);
  51. }
  52. //6.Array.prototype.sort([compareFunction]) : 增加了一个参数
  53. // 可以按照指定规则排序,而不是默认的将元素字符串化后排序
  54. Console.PrintNamedSepLine('Array.prototype.sort([compareFunction])');
  55. {
  56. let names = ['Joe Smith', 'Jobs Steven', 'Bill Gates'];
  57. let compFunc = (a, b) => a.length - b.length;
  58. Console.log(JSON.stringify(names));
  59. names.sort(compFunc);
  60. Console.log(JSON.stringify(names));
  61. }
  62. }

5.ES2020_ES11 特性测试

  1. function ES2020_ES11() {
  2. //1.链式判断运算符;NA
  3. Console.PrintNamedSepLine('链式判断运算符');
  4. try {
  5. let obj = { one : 1, two : 2, three : 3 };
  6. //直接写下面这句会编译不过,所以在这儿用 eval
  7. //Console.log(obj?.yes?.toExponential());
  8. eval('Console.log(Math?.dk?.good == undefined)');
  9. } catch { Console.log('Nonsupport'); }
  10. //2.String.prototype.matchAll
  11. Console.PrintNamedSepLine('String.prototype.matchAll')
  12. if (typeof String.prototype.matchAll == 'function') {
  13. let regex = /t(e)(st(\d?))/g;
  14. let string = 'test1test2test3';
  15. let allMatches = [...string.matchAll(regex)];
  16. Console.log(allMatches.toString());
  17. }
  18. //3.Null判断运算符 : 如果左值是 null/undefined,使用右值
  19. Console.PrintNamedSepLine('Null判断运算符');
  20. try {
  21. let x = eval('ksdfksk ?? false');
  22. Console.log(x);
  23. } catch { Console.log('Nonsupport'); }
  24. //4.Bigint : 新增类型
  25. Console.PrintNamedSepLine('Bigint 类型');
  26. Console.log('是否支持 Bigint 类型?:' +
  27. (typeof Bigint != 'undefined'));
  28. //5.Promise.*...
  29. //6.import ...
  30. //7.export ...
  31. }

6.ES2021_ES12 特性测试

  1. function ES2021_ES12() {
  2. //1.复合逻辑赋值运算符:??=/&&=/||=
  3. Console.PrintNamedSepLine('复合逻辑赋值运算符');
  4. try {
  5. //以下相当于 let xx = xx ?? 1;
  6. //即,如果 xx == null/undefined, 赋值为 1
  7. let x = eval('let xx ??= 1; xx;');
  8. Console.log(x);
  9. } catch { Console.log('Nonsupport'); }
  10. try {
  11. //以下相当于 let yy = yy && true;
  12. let y = eval('let yy &&= true; yy;');
  13. Console.log(y);
  14. } catch { Console.log('Nonsupport'); }
  15. try {
  16. //以下相当于 let zz = zz || true;
  17. let z = eval('let zz ||= true; zz;');
  18. Console.log(z);
  19. } catch { Console.log('Nonsupport'); }
  20. //2.数字分隔符
  21. Console.PrintNamedSepLine('数字分隔符');
  22. try {
  23. let num = eval('1_5000');
  24. Console.log(num);
  25. } catch { Console.log('Nonsupport'); }
  26. //3.String.prototype.replaceAll
  27. Console.PrintNamedSepLine('String.prototype.replaceAll');
  28. if (typeof String.prototype.replaceAll === 'function') {
  29. Console.log("'hello world'.replaceAll('o', '_') :" +
  30. 'hello world'.replaceAll('o', '_'));
  31. }
  32. //4.WeakRefs & FinalizationRegistry对象 ...
  33. //5.Promise.any & AggregateError ...
  34. }