对象是 ECMAScript 国际化 API 的一个命名空间,它提供了精确的字符串对比、数字格式化,和日期时间格式化。
日期格式化
// 例如我们希望出现的日期信息格式是:“xxxx年xx月xx日 xx:xx:xx”。
const res = new Intl.DateTimeFormat("zh", {
year: "numeric",
/*
'2-digit'表示一定使用2位数字表示,
因此,如果数值不超过10,会自动在前面加0
*/
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
// 设置为false表示我们采用24小时制
hour12: false,
}).format(new Date());
// IE11浏览器下的效果 完全符合我们的预期, - 2021年05月29日 10:15:27
// 但是在Chrome浏览器和Firefox浏览器下,却不是中文的年月日而是斜杠-2021/05/29 10:15:27, 还需要进一步字符处理下
console.log(res);
数字格式化,
new Intl.NumberFormat().format(12345.6789);
// 结果是:"12,345.679"
new Intl.NumberFormat(undefined, {
minimumIntegerDigits: 2,
}).format(8);
// 结果是:"08"
new Intl.NumberFormat("zh", {
style: "currency",
currency: "CNY",
currencyDisplay: "name",
}).format(12345.6789);
// 结果是:"12,345.68 人民币"
new Intl.NumberFormat("zh", {
style: "currency",
currency: "CNY",
}).format(12345.6789);
// 结果是:"¥12,345.68 "
const res = `星期${new Intl.NumberFormat("zh-Hans-CN-u-nu-hanidec").format(
new Date().getDay(),
)}`;
// 结果是:"星期五"
模块中顶层的 this 等于 undefined
const isModuleScript = this === undefined
Number.EPSILON 属性表示 1 与Number可表示的大于 1 的最小的浮点数之间的差值。
判断数值是否相等
const isEqual = (target, origin) => Math.abs(origin - target) < Number.EPSILON
计算两数平方开方Math.hypot(3,4) === 5
// 2的平方
let squared = 2 ** 2;
// same as: 2 * 2 Math.Pow(2,2)
// 2的三次方
let cubed = 2 ** 3;
// same as: 2 * 2 * 2 Math.Pow(2,3)
如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
"1".padStart(10, "0"); // "0000000001"
"12".padStart(10, "0"); // "0000000012"
"123456".padStart(10, "0"); // "0000123456"
// 格式提示
"12".padStart(10, "YYYY-MM-DD"); // "YYYY-MM-12"
"09-12".padStart(10, "YYYY-MM-DD"); // "YYYY-09-12"
const shallowClone = (object) =>
// 创建一个新对象
Object.create(
// 返回指定对象的原型
Object.getPrototypeOf(object),
// 返回指定对象所有自身属性
Object.getOwnPropertyDescriptors(object),
);
// 或者
const shallowMerge = (target, source) =>
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
Atomics 对象提供了一组静态方法对 SharedArrayBuffer 和 ArrayBuffer 对象进行原子操作。多线程之间操作数据不会引起混乱的api
ES6 对正则表达式添加了u修饰符,含义为“Unicode 模式”,用来正确处理大于\uFFFF的 Unicode 字符。也就是说,会正确处理四个字节的 UTF-16 编码。
/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
var s = '𠮷';
/^.$/.test(s) // false
/^.$/u.test(s) // true
// 新增大括号在u模式下标识一个字符 内放置16进制数
/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('𠮷') // true
/a{2}/.test('aa') // true
/a{2}/u.test('aa') // true
/𠮷{2}/.test('𠮷𠮷') // false
/𠮷{2}/u.test('𠮷𠮷') // true
/^\S$/.test('𠮷') // false
/^\S$/u.test('𠮷') // true
function codePointLength(text) {
var result = text.match(/[\s\S]/gu);
return result ? result.length : 0;
}
var s = '𠮷𠮷';
s.length // 4
codePointLength(s) // 2
除了u修饰符,ES6 还为正则表达式添加了y修饰符,叫做“粘连”(sticky)修饰符。
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null
const REGEX = /a/y;
// 指定从2号位置开始匹配
REGEX.lastIndex = 2;
// 不是粘连,匹配失败
REGEX.exec('xaya') // null
// 指定从3号位置开始匹配
REGEX.lastIndex = 3;
// 3号位置是粘连,匹配成功
const match = REGEX.exec('xaya');
match.index // 3
REGEX.lastIndex // 4
const TOKEN_Y = /\s*(\+|[0-9]+)\s*/y;
const TOKEN_G = /\s*(\+|[0-9]+)\s*/g;
tokenize(TOKEN_Y, '3 + 4')
// [ '3', '+', '4' ]
tokenize(TOKEN_G, '3 + 4')
// [ '3', '+', '4' ]
tokenize(TOKEN_Y, '3x + 4')
// [ '3' ]
tokenize(TOKEN_G, '3x + 4')
// [ '3', '+', '4' ]
function tokenize(TOKEN_REGEX, str) {
let result = [];
let match;
while (match = TOKEN_REGEX.exec(str)) {
result.push(match[1]);
}
return result;
}
正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;另一个是行终止符
/foo.bar/.test('foo\nbar')
// false
// es5
/foo[^]bar/.test('foo\nbar')
// true
// ES2018 引入s修饰符,使得.可以匹配任意单个字符。
/foo.bar/s.test('foo\nbar') // true
/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill') // ["100"]
/(?<!\$)\d+/.exec('it’s is worth about €90') // ["90"]
const RE_DOLLAR_PREFIX = /(?<=\$)foo/g;
'$foo %foo foo'.replace(RE_DOLLAR_PREFIX, 'bar');
/(?<=(\d+)(\d+))$/.exec('1053') // ["", "1", "053"]
/^(\d+)(\d+)$/.exec('1053') // ["1053", "105", "3"]
// 后行断言引用必须在之前
/(?<=(o)d\1)r/.exec('hodor') // null
/(?<=\1d(o))r/.exec('hodor') // ["r", "o"]
// es5
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31
// es6
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // "1999"
const month = matchObj.groups.month; // "12"
const day = matchObj.groups.day; // "31"
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
'2015-01-02'.replace(re, '$<day>/$<month>/$<year>')
// '02/01/2015'
'2015-01-02'.replace(re, (
matched, // 整个匹配结果 2015-01-02
capture1, // 第一个组匹配 2015
capture2, // 第二个组匹配 01
capture3, // 第三个组匹配 02
position, // 匹配开始的位置 0
S, // 原字符串 2015-01-02
groups // 具名组构成的一个对象 {year, month, day}
) => {
let {day, month, year} = groups;
return `${day}/${month}/${year}`;
});
// 引用
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false
const RE_TWICE = /^(?<word>[a-z]+)!\1$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>!\1$/;
RE_TWICE.test('abc!abc!abc') // true
RE_TWICE.test('abc!abc!ab') // false
const text = 'zabbcdef';
const re = /ab/;
const result = re.exec(text);
result.index // 1
result.indices // [ [1, 3] ]
const text = 'zabbcdef';
const re = /ab+(cd)/;
const result = re.exec(text);
result.indices // [ [ 1, 6 ], [ 4, 6 ] ]
const text = 'zabbcdef';
const re = /ab+(cd(ef))/;
const result = re.exec(text);
result.indices // [ [1, 8], [4, 8], [6, 8] ]
const text = 'zabbcdef';
const re = /ab+(?<Z>cd)/;
const result = re.exec(text);
result.indices.groups // { Z: [ 4, 6 ] }
function TimeOut(time) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for await (let item of arr) {
console.log(Date.now(), item)
}
}
test()
// 1560092345730 2000
// 1560092345730 1000
// 1560092346336 3000
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat());
// expected output: [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2));
// expected output: [0, 1, 2, [3, 4]]
[1, 2, 3, 4].flatMap((x) => [[x * 2]]);
// [[2], [4], [6], [8]]
Object.fromEntries([
['foo', 'bar'],
['baz', 41]
])
// { foo: bar, baz: 41 }
const entries = new Map([
['foo', 'bar'],
['baz', 41]
])
Object.fromEntries(entries)
// { foo: bar, baz: 41 }
const map = new Map().set("foo", true).set("bar", false);
Object.fromEntries(map);
// { foo: true, bar: false }
const arr = [
["0", "a"],
["1", "b"],
["2", "c"],
];
const obj = Object.fromEntries(arr);
// { 0: "a", 1: "b", 2: "c" }
let query = Object.fromEntries(new URLSearchParams("foo=bar&baz=qux"));
// {foo: "bar", baz: "qux"}
console.log(query);
let arr = [
{ name: "Alice", age: 40 },
{ name: "Bob", age: 36 },
];
let obj = Object.fromEntries(arr.map(({ name, age }) => [name, age]));
// {Alice: 40, Bob: 36}
console.log(obj);
const sym = Symbol('foo')
String(sym); // "Symbol(foo)"
sym.toString(); // "Symbol(foo)"
sym.description // foo
String.prototype.matchAll
返回一个正则表达式在当前字符串的所有匹配
const string = "test1test2test3";
const regex = /t(e)(st(\d?))/g;
const newdata = string.matchAll(regex);
for (const match of newdata) {
console.log(match);
}
// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]
// 转为数组的方法一
[...newdata];
// 转为数组的方法二
Array.from(newdata);
Promise
静态方法
Promise.race
只要任意一个 promise 的状态改变(不管成功 or 失败),那么就返回那个 promisePromise.allSettled
只有等到所有实例都返回结果,不管是fulfilled还是rejected,实例才会结束Promise.any
只要其中任意一个 promise 成功,就返回那个已经成功的 promise。Promise
实例属性status
可以反应成功与否成功为fulfilled
,失败为rejected
,实例中有finally
无论成功与否
async function test() {
const promises = [fetch("./index.html"), fetch("https://does-not-exist/")];
const results = await Promise.allSettled(promises);
// 过滤出成功的请求
const successfulPromises = results
.filter((p) => p.status === "fulfilled")
.map((p) => p.value);
// 过滤出失败的请求,并输出原因
const errors = results
.filter((p) => p.status === "rejected")
.map((p) => p.reason);
console.log(errors);
}
Promise.allSettled(requests).finally(() => {
console.log("所有请求已结束,并且我不关心是成功还是失败");
// 关闭loading状态
removeLoadingIndicator();
});
globalThis 提供了一个标准的方式来获取不同环境下的全局 this 对象(也就是全局对象自身)
// 以前:
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
var globals = getGlobal();
// 现在
globalThis
空值合并操作符(??)只有当左侧为null|undefined
事会返回右侧的值
const a = null ?? 1 // 1
const a = undefined ?? 1 // 1
const a = '' ?? 1 // ''
const a = NaN ?? 1 // NaN
const a = 0 ?? 1 // 0
?. 也叫链判断运算符。它允许开发人员读取深度嵌套在对象链中的属性值,而不必验证每个引用。当引用为空时,表达式停止计算并返回 undefined。
var travelPlans = {
destination: "DC",
monday: {
location: "National Mall",
budget: 200,
},
};
// new
console.log(travelPlans.tuesday?.location); // => undefined
// 可选链不能用于赋值
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
// old
const res = travelPlans.tuesday && travelPlans.tuesday.location
旧版本的 JS 标准最大的整数只能是 2^53-- 即Number.MAX_SAFE_INTEGER或Math.pow(2, 53)
如果无法准确计算大于2^53的数字的
现在使用BigInt 用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
const theBiggestInt = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);
// old
const str = "a+b+c+";
const newStr = str.replace(/\+/g, "🤣");
console.log(newStr); //a🤣b🤣c🤣
// 获取使用 split,join进行字符串分割
const queryString = "q=query+string+parameters";
const withSpaces = queryString.split("+").join(" ");
// new
const str = "a+b+c+";
const newStr = str.replaceAll("+", "🤣");
console.log(newStr); //a🤣b🤣c🤣
const queryString = "q=query+string+parameters";
const withSpaces = queryString.replaceAll("+", " ");
WeakRef 提案主要包含两个新功能:
可以通过 WeakRef 类来给某个对象创建一个弱引用
可以通过 FinalizationRegistry 类,在某个对象被垃圾回收之后,执行一些自定义方法
WeakRef 主要用来缓存和映射一些大型对象,当你希望某个对象在不被其它地方引用的情况下及时地被垃圾回收,那么你就可以使用它。
const cache = new Map();
const finalizationGroup = new FinalizationGroup((iterator) => {
for (const name of iterator) {
const ref = cache.get(name);
// WeakRef 通过 deref方法返回引用对象, 如果被收回则为空
if (ref !== undefined && ref.deref() === undefined) {
cache.delete(name);
}
}
});
function getImageCached(name) {
const ref = cache.get(name); // 1
if (ref !== undefined) { // 2
// 查看弱引用是否有对象
const deref = ref.deref();
if (deref !== undefined) return deref;
}
const image = performExpensiveOperation(name); // 3
// 创建weakRef
const wr = new WeakRef(image); // 4
cache.set(name, wr); // 5
// image 注册垃圾回收 传入回调参数
finalizationGroup.register(image, name); // 6
return image; // 7
}
// better 👶
function example(opts) {
// Setters are not needlessly called.
opts.foo ??= "bar";
// No repetition of `opts.baz`.
opts.baz ??= "qux";
}
// 默认参数值
function example(opts = { foo: "foo", baz: "baz" }) {
return opts;
}
const giveKey = () => {
return "somekey";
};
let userDetails = { name: "chika", age: 5, room: 10, key: "" };
// userDetails.key = userDetails.key || giveKey();
userDetails.key ||= giveKey();
console.log(userDetails.key);
//output : somekey
const deleteKey = () => {
return " ";
};
let userDetails = { name: "chika", age: 5, room: 10, key: "990000" };
// userDetails.key = userDetails.key && deleteKey();
userDetails.key &&= deleteKey();
console.log(userDetails.key);
//output : ""
var x = null;
var y = 5;
// x = x ?? y;
console.log((x ??= y)); // => 5
function gameSettingsWithNullish(options) {
options.gameSpeed ??= 1;
options.gameDiff ??= "easy";
return options;
}
function gameSettingsWithDefaultParams(gameSpeed = 1, gameDiff = "easy") {
return { gameSpeed, gameDiff };
}
gameSettingsWithNullish({ gameSpeed: null, gameDiff: null }); // => {gameSpeed: 1, gameDiff: 'easy'}
gameSettingsWithDefaultParams(undefined, null); // => {gameSpeed: 1, gameDiff: null}
const getKey = () => {
return "somekey";
};
let userDetails = { name: "chika", age: 5, room: 10 };
userDetails.key ??= getKey();
console.log(userDetails.key);
//output : "somekey"
此功能使开发人员可以通过在数字组之间创建视觉分隔来使其数字文字更具可读性。
1_000_000_000; // 十亿
101_475_938.38; // 亿万
const amount = 12345_00; // 1234500
const amount = 123_4500; // 1234500
const amount = 1_234_500; // 1,234,500
0.000_001; // 百万分之一
1e10_000; // 10^10000
//
const binary_literals = 0b1010_0001_1000_0101;
const hex_literals = 0xa0_b0_c0;
//
const bigInt_literals = 1_000_000_000_000n;
//
const octal_literal = 0o1234_5670;
// 可以使用声明式的类字段
class Pokemon {
name = "Pikachu";
attack() {}
static starter() {}
}
// 私有属性/私有方法 我们将使用# 符号表示类的私有变量
class Student {
#name = "something";
#name2 = "name2";
// 实例私有方法-只能在此Class内部使用
#instancePrivateMethod() {
console.log("实例私有方法");
}
}
// static字段
class Student {
// 静态私有字段声明-只能在此Class内部使用
static #staticFieldPrivateName = "静态私有字段声明:真名-王撕葱";
// 静态公有字段声明
static staticFieldPublicName = "静态公有字段声明:名-撕葱";
// 静态公有方法-ES6已支持
static staticPublicMethod() {
console.log("静态公有方法");
}
// 静态私有方法-只能在此Class内部使用
static #staticPrivateMethod() {
console.log("#staticPrivateMethod:", "静态私有方法");
}
}
// 私有属性也可以设置 getter 和 setter 方法
class Student {
#name = "something";
#name2 = "name2";
// 只能在此Class内部使用
get #privateGet() {
return this.#name;
}
// 只能在此Class内部使用
set #privateSet(value) {
this.#name = value;
}
get publicGet() {
return this.#name2;
}
set publicSet(value) {
this.#name2 = value;
}
}
// 静态公有/私有字段
class ColorFinder {
static #red = "#ff0000";
static #green = "#00ff00";
static #blue = "#0000ff";
static colorName(name) {
switch (name) {
case "red":
return ColorFinder.#red;
case "blue":
return ColorFinder.#blue;
case "green":
return ColorFinder.#green;
default:
throw new RangeError("unknown color");
}
}
// Somehow use colorName
}
// awaiting.mjs
import { process } from "./some-module.mjs";
const dynamic = import(computedModuleSpecifier);
const data = fetch(url);
export const output = process((await dynamic).default, await data);
// usage.mjs
import { output } from "./awaiting.mjs";
export function outputPlusValue(value) { return output + value }
console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100), 1000);
©2021 - bill-lai 的小站 -站点源码