Skip to main content

译-ECMAScript2020

是时候对JavaScipt进行更新。本文我们一起回顾来自ES2020的最新的和最伟大的功能。

安装#

因为很多人不以为更新浏览器可以减轻开发者的工作, 我们需要借助babel来使得用户可以使用不发使用的功能。为了这个简单的目标,我们使用Parcel bundler让一切尽可能快的运行起来。

$ yarn add parcel-bundler

package.json

"script": {
"start": "parcel index.html"
}

可惜的是, 因为此时我们写的东西超前所以没有关于ES2020的预解析。如果你把以下内容保存到.babelrc文件, Parcel会帮你进行相关安装。

.babelrc

{
"plugins": [
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-private-methods",
"@babel/plugin-syntax-bigint"
]
}

class的私有变量#

class主要目的之一是将代码包含到更多可重复使用的模块中去。我们创建一个class使用在很多不同的地方, 但是你可能并不希望他全部的内部东西全局可用。

现在, 通过在变量和函数前添加一个简单的hash标志(#), 这个标志可以全部保留到class内部使用。

class Message {
#message = "Howdy"
greet() { console.log(this.#message) }
}
const greeting = new Message()
greeting.greet() // Howdy
console.log(greeting.#message) // Private name #message is not defined

Promise.allSettled#

当和多个promise同时工作的时候, 尤其他们相互依赖时, 记录调试错误发生了什么是很有用的。借助Promise.allSettled 我们可以创建一个当所有promise都完成时才返回的promise。我们可以访问包含每个promise数据的数组。

const p1 = new Promise((res, rej) => setTimeout(res, 1000));
const p2 = new Promise((res, rej) => setTimeout(rej, 1000));
Promise.allSettled([p1, p2]).then(data => console.log(data));
// [
// Object { status: "fulfilled", value: undefined},
// Object { status: "rejected", reason: undefined}
// ]

Nullish Coalescing Operator(空合并运算符)#

因为JavaScript是动态类型, 在分配变量时, 我们需要记住JavaScript对真/假值的处理。假如我们有一个具有多个变量的对象, 有时我们允许想空对象或者数组0这样的假值。设置默认值很快会变得很烦人, 因为他会覆盖应该是有效的值。

let person = {
profile: {
name: "",
age: 0
}
};
console.log(person.profile.name || "Anonymous"); // Anonymous
console.log(person.profile.age || 18); // 18

我们使用两个问号(空合并运算符)替代逻辑与运算符使类型更加严格, 这样做仅允许null或者undefined设置默认值。

console.log(person.profile.name ?? "Anonymous"); // ""
console.log(person.profile.age ?? 18); // 0

Optional Chaining Operator#

与前一个运算相似, JavaScript在假值处理时, 可能不会按照我们的预期进行操作。如果是undefined则返回一个值, 但是如果得到这个值之前出现undefined怎么办?

我们在.之前加问号可以使路径的任何部分变为可选, 以至于可以进行交互。

let person = {};
console.log(person.profile.name ?? "Anonymous"); // person.profile is undefined
console.log(person?.profile?.name ?? "Anonymous");
console.log(person?.profile?.age ?? 18);

BigInt#

我们不想探究JavaScript如何操作数字的技术细节, 但是当数字足够大时变得不稳定。JavaScript中可操作的最大值是2^53, 即MAX_SAFE_INTEGER。

const max = Number.MAX_SAFE_INTEGER;
console.log(max); // 9007199254740991

上边的事情开始变得有点不可思议...

console.log(max + 1); // 9007199254740992
console.log(max + 2); // 9007199254740992
console.log(max + 3); // 9007199254740994
console.log(Math.pow(2, 53) == Math.pow(2, 53) + 1); // true

我们用一个新的new BigInt来回避这个问题。通过在尾部加n对超级大的数字进行操作。我们无法把标准数字和BIgInt进行混合, 因此需要运算的需要都是BigInt型。

const bigNum = 100000000000000000000000000000n;
console.log(bigNum * 2n); // 200000000000000000000000000000n

Dynamic Import#

假如你有一个全部是工具函数的文件, 文件中的大部分很少使用且全部导入他们的依赖浪费资源。现在我们使用async/await在需要的地方动态导入我们的依赖。

const add = (num1, num2) => num1 + num2;
export { add };
const doMath = async (num1, num2) => {
if (num1 && num2) {
const math = await import('./math.js');
console.log(math.add(5, 10));
};
};
doMath(4, 2);

测试工程

原文链接

ES6迭代器

迭代器由任意对象实现的接口,支持连续获取对象产出的每个值; 默认Symbol.iterator 属性。

消费方式#

  • 手动调用next()方法消费
  • for...of 循环自动消费(for( ; ; )、forEach)

迭代器模式, 可以支持迭代消费的数据结构(可迭代对象)

'12345'
[1, 2, 3, 4, 5]
new Map().set('a', 1).set('b', 2)
new Set().add(1).add(2).add(3)
arguments对象
NodeList等DOM集合类型

原生语言:for...of、数组结构、扩展操作符、Array.from()、创建集合、创建映射、Promise.all()、Promise.race()、yield*

let iter = [1, 2, 3, 4][Symbol.iterator]();
iter.next() // {done: false, value: 1}, 最后{value: undefined, done: true}

自定义迭代器#

class Counter {
constructor(limit) {
this.limit = limit
}
[Symbol.iterator]() {
let count = 1, limit = this.limit;
return {
next () {
if (count <= limit) {
return { done: false, value: count++ };
} else {
return { done: true, value: undefined };
}
}
}
}
}

考察点#

  1. 给出打印结果并说明原因
let arr = [1,2,3]
arr.name = 'Jack'
arr.length // 3
console.log(Object.keys(arr)) // ["0", "1", "2", "name"]
for(let i in arr) { console.log('in', i) } // 0, 1, 2, 3, name
for (let i of arr) { console.log(i) } // 1, 2, 3
  • for...in 是枚举全部属性
  • for...of 是迭代器
  1. 改造数据使得for...of可遍历出全部值

解决方法1:

let arr = [1,2,3]
arr.name = 'Jack'
// Symbol.iterator
arr[Symbol.iterator] = function () {
let index = 0;
const _this = this;
const keys = Object.keys(_this);
const len = keys.length;
return {
next() {
if (index < len) {
return {
value: _this[keys[index++]],
done: false
}
}
return {
value: null,
done: true
}
}
}
}
let iter = arr[Symbol.iterator]()
for (let i of arr) {
console.log(i)
}
// 1
// 2
// 3
// Jack

方式2: 生成器函数

let arr = [1,2,3]
arr.name = 'Jack'
// Symbol.iterator
arr[Symbol.iterator] = function* () {
const keys = Object.keys(this);
for (let i = 0; i < keys.length; i++) {
yield this[keys[i]]
}
}
let iter = arr[Symbol.iterator]()
for (let i of arr) {
console.log(i)
}
// 1
// 2
// 3
// Jack

https://gitee.com/daaasheng/my_code_block/commit/b589b41274619c291a7b711ddada1fb72bd65a0e

疑问#

  1. for (let item of arr) {iter.next()} 与 for(let item of iter) 区别?
  2. 提前终止, 出发迭代器是否重新开始

如何实现文本渐变

简介#

渐变 image.png

background: linear-gradient(0deg, red, blue);
background: linear-gradient(90deg, red, blue);
background: linear-gradient(180deg, red, blue);

1. css实现文本渐变#

单行渐变#

image.png 竖向渐变, display 必须是纯inline

display: inline;
background-image: linear-gradient(0deg,#67cff3,#fff);
-webkit-background-clip: text;
color: transparent;

意义:相比单色更加清晰

原理解释:

  • background-image: linear-gradient(0deg,#67cff3,#fff); 为文本提供渐变背景
  • -webkit-text-fill-color: transparent 或者  color: transparent;  透明色填充文本
  • -webkit-background-clip: text; 文本剪辑背景填充文本

注意: -webkit-background-clip 必须位于 background-image 之后

整体渐变#

image.png

display: 非inline 即可

2. svg实现文本渐变#

image.png

<div class="box svg_box">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="500" height="300" viewBox=""viewBoxs="0 0 500 300">
<defs>
<linearGradient id="g1" gradientUnits="userSpaceOnUse" x1="0" y1="10" x2="0" y2="50">
<stop offset="0" style="stop-color: blue"/>
<stop offset="0.7" style="stop-color: red"/>
</linearGradient>
</defs>
<text x="0" y="30" fill="url(#g1)">
新华社北京9月21日电 国家主席习近平21日在联合国成立75周年纪念峰会上发表重要讲话。
</text>
</svg>
</div>

缺点:

  • 文本换行需要手动借助标签
  • 渐变路径需要中自定义, 且id必须唯一

3. webkit 内核浏览器特有 -webkit-mask-image: -webkit-gradient()#

参考: 单行渐变:https://chaolucky.com/blog/05/25-98.html

SVG text文本换行和foreignObject换行对比 : [https://www.zhangxinxu.com/study/201708/svg-text-vs-svg-foreignobject.html](