es6-08 新提案
ES2020
可选链:?
之前:obj.a.b 当找不到a再找b,报错
现在:obj.a?.b 找不到a就不找b
jsobj?.prop obj?.[expr] arr?.[index] func?.(args)
双问号:??,false、0、""都为真;
js0 ?? 1 // 0
动态import
jsconst loadHeader = () => { import('./header').then(module => {}) }
promise.allSettled
解决promise.all其中reject时就返回了,allSettled则会请求完所有的接口,最终返回resolve,里面为所有结果,包括成功和失败;
globalThis
:解决node环境没有window,需要用global,现在会根据环境判断使用window或global;BigInt
:整数类型String.matchall
:正则匹配将所有的字符串都返回回来,为一个数组
可选链
配置babel解析:https://www.jianshu.com/p/bca4ce835caf
es6教程:https://es6.ruanyifeng.com/#docs/object#%E9%93%BE%E5%88%A4%E6%96%AD%E8%BF%90%E7%AE%97%E7%AC%A6
do表达式
由于块级作用域只是一个语句,没有返回值,do表达式增加了返回值
let x = do {
let t = f();
t * t + 1;
} // 变量中的x为最终 t * t +1的值
do的表达式的好处是可以封装多个语句
let x = do {
if (foo()) { f() }
else if (bar()) { g() }
else { h() }
};
// 哪个函数执行,就会将哪个函数的结果赋值给x
do可以用在jsx中,比三元运算符更好用
return (
<nav>
{
do {
if(true) {
<Logout />
} else {
<LoginButton />
}
}
}
</nav>
)
throw 表达式
js规定throw只是一个命令,用来抛出错误,不能用于表达式中
console.log(throw new Error()) // 报错
console.log的参数必须是表达式,否则就报错
新的提案支持throw用于表达式了
function save(name = throw new TypeError('Argument required')) {};
function set(value) {
let a = value || throw new Error('Invalid value')
}
函数的部分执行
以前使用bind来生成新的函数
function add(x, y) {return x + y}
var add7 = add.bind(null, 7)
add7(3) // 10
现在
var add7 = add(?, 7)
add7(3) // 10
新提案中,?
表示单个参数的占位符,...
是多个参数的占位符
const f = (x, ...y) => [x, ...y]
const g = f(x, ?);
g(2,3,4) //
// 当g的值为不同的参数调用时
f(x, ?) // [x, 2]
f(x, ...) // [x, 2,3,4]
f(?, x) // [2, x]
f(..., x) // [2,3,4,x]
f(?, x, ?) // [2, x, 3]
f(..., x, ...) // [2,3,4,x,2,3,4]
注意点
原函数发生变化,执行的结果也会不同
jslet f = (x, y) => x + y; const g = f(?, 3); g(1); // 4 // 替换函数 f f = (x, y) => x * y; g(1); // 3
如果传入的值是表达式,每次调用时会重新求值
jslet a = 3; const f = (x, y) => x + y; const g = f(?, a); g(1); // 4 // 改变 a 的值 a = 10; g(1); // 11
管道运算符
管道是一个运算符,写作|>
,左边是一个表达式,右边是一个函数,管道最大的好处是可以嵌套函数,写从左到右的链式表达式
function doubleSay (str) {
return str + ", " + str;
}
function capitalize (str) {
return str[0].toUpperCase() + str.substring(1);
}
function exclaim (str) {
return str + '!';
}
// 以前的写法
exclaim(capitalize(doubleSay('hello')))
// "Hello, hello!"
// 管道的写法
'hello'
|> doubleSay
|> capitalize
|> exclaim
// 'Hello, hello!'
管道运算符只能传递一个值,如果多个参数可以进行柯里化
function double (x) { return x + x; }
function add (x, y) { return x + y; }
let person = { score: 25 };
person.score
|> double
|> (_ => add(7, _))
// 57
管道运算符也可以用于await函数
x |> await f
// 等同于
await f(x)
const userAge = userId |> await fetchUserById |> getAgeFromUser;
// 等同于
const userAge = getAgeFromUser(await fetchUserById(userId));
Math.signbit()
用来判断一个值的正负,可以正确判断0是否是-0;
Math.signbit(0) // false
Math.signbit(-0) // true
双冒号运算符
函数绑定运算符::
,双冒号左边是一个对象,右边是一个函数;
foo::bar
// 等同于
bar.bind(foo);
foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
如果左边为空,右边是一个对象的方法,则绑定在该对象上面
var method = obj::obj.foo;
// 等同于
var method = ::obj.foo;
let log = ::console.log;
// 等同于
var log = console.log.bind(console);
如果运算符的结果还是一个对象,可以采用链式写法
import { map, takeWhile, forEach } from "iterlib";
getPlayers()
::map(x => x.character())
::takeWhile(x => x.strength > 100)
::forEach(x => console.log(x));
Realm
创建一个window对象的副本,可以前往官网查看https://es6.ruanyifeng.com/#docs/proposals#Realm-API
#!命令
支持在脚本之前添加一行命令
#!/usr/bin/env node
之后执行时
# 以前执行脚本的方式
$ node hello.js
# hashbang 的方式
$ ./hello.js
import.meta
返回引入模块的元信息
import.meta.url 返回当前的url路径
import.meta.scriptElement 返回加载script的元素
js// HTML 代码为 // <script type="module" src="my-module.js" data-foo="abc"></script> // my-module.js 内部执行下面的代码 import.meta.scriptElement.dataset.foo // "abc"