JS things I never knew existed JS里我从来不知道的东西(译)

原文:JS things I never knew existed

我正在阅读MDN文档,发现了一些我从来不知道的JS功能和API。所以这里是一篇简短的总结,无论是否有用——学习JS永无止境。

标签语句 Label Statements

你知道吗(反正我不知道),在JS中,你可以给for循环和代码块命名!然后,可以在for循环中,使用breakcontinue,操作指定命名的循环。break同样也可以用在代码块中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
loop1: // 命名为 "loop1"
for (let i = 0; i < 3; i++) { // "loop1"
loop2: // 命名为 "loop2"
for (let j = 0; j < 3; j++) { // "loop2"
if (i === 1) {
continue loop1; // 继续执行上面的 "loop1"
// break loop1; // 跳出上面的"loop1"
}
console.log(`i = ${i}, j = ${j}`);
}
}

/*
* # 输出
* i = 0, j = 0
* i = 0, j = 1
* i = 0, j = 2
* i = 2, j = 0
* i = 2, j = 1
* i = 2, j = 2
*/

这里有个给代码块命名的例子,在代码块中,你只能用break

1
2
3
4
5
6
7
8
9
10
11
12
foo: {
console.log('one');
break foo;
console.log('this log will not be executed');
}
console.log('two');

/*
* # 输出
* one
* two
*/

“void” 操作符

我以为我知道所有的操作符(operator),直到我看到这个自1996年以来,一直在JS中的操作。它被所有浏览器支持,并且很容易理解,引用MDN的一句话:

The void operator evaluates the given expression and then returns undefined.
void运算符执行给定的表达式,然后返回undefined。

借此,你可以像这样写IIFE(立即执行函数):

1
2
3
4
5
6
7
8
9
void function iife() {
console.log('hello');
}();

// 与下面效果相同

(function iife() {
console.log('hello');
})()

值得注意的是含void表达式的值是…void(undefined)

1
2
3
4
5
6
7
8
9
10
11
const word = void function iife() {
return 'hello';
}();

// word 值为 "undefined"

const word = (function iife() {
return 'hello';
})();

// word 值为 "hello"

你也可以将voidasync一起使用,作为代码的异步入口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void async function() {
try {
const response = await fetch('air.ghost.io');
const text = await response.text();
console.log(text);
} catch(e) {
console.error(e);
}
}()

// 或者还是坚持像以前这样写 :)

(async () => {
try {
const response = await fetch('air.ghost.io');
const text = await response.text();
console.log(text);
} catch(e) {
console.error(e);
}
})();

逗号操作符

在阅读了逗号运算符之后,我意识到我并没有完全意识到它是如何工作的。引自MDN:

The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
逗号运算符对每个操作数(从左到右)求值,并返回最后一个操作数的值

1
2
3
4
5
6
7
8
9
10
function myFunc() {
let x = 0;
return (x += 1, x); // 等同于 return ++x;
}

y = false, true; // 返回 true 在命令行中
console.log(y); // false (最左边的值)

z = (false, true); // 返回 true 在命令行中
console.log(z); // true (最右边的值)

配合三元运算符使用

逗号运算符的最后一个值,可以成为三元条件语句的返回值。所以你可以在它之前,放置任意数量的表达式,在下面的例子中,我把console log放在了返回的布尔值之前。

1
2
3
4
5
6
7
8
9
10
11
const type = 'man';

const isMale = type === 'man' ? (
console.log('Hi Man!'),
true
) : (
console.log('Hi Lady!'),
false
);

console.log(`isMale is "${isMale}"`);

国际化API

国际化很难达到,幸运的是,现在大多数浏览器都有一个支持良好的API。一个我最喜欢的特性就是时间格式化,看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
const date = new Date();

const options = {
year: 'numeric',
month: 'long',
day: 'numeric'
};

const formatter1 = new Intl.DateTimeFormat('es-es', options);
console.log(formatter1.format(date)); // 22 de diciembre de 2017

const formatter2 = new Intl.DateTimeFormat('en-us', options);
console.log(formatter2.format(date)); // December 22, 2017

管道操作符 Pipeline Operator

在写这篇文章的时候,只有Firefox 58+支持,但是Babel在这里应有一个提议插件了。它看起来非常bash,我很喜欢!

1
2
3
4
5
6
7
8
const square = (n) => n * n;
const increment = (n) => n + 1;

// 不用 pipeline
square(increment(square(2))); // 25

// 使用pipeline
2 |> square |> increment |> square; // 25

其他值得注意的

Atomics

在多个线程之间共享数据时,Atomic操作可以给出可预测的读取值和写入值,等待其他操作在下一个执行之前完成。用于保持数据在主线程和其他WebWorker之间同步。我非常喜欢Java等其他语言的Atomics。我觉得当更多人使用WebWorkers,将操作从主线程中移出,Atomics将会在JS中被更多的使用。

Array.prototype.reduceRight

好吧,我从来没有见过这个使用,因为它基本上是Array.prototype.reduce() + Array.prototype.reverse(),它很少需要你这样做。如果你这样做…reduceRight是完美的!

1
2
3
4
5
const flattened = [[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
return a.concat(b);
}, []);

// flattened 数组是 [4, 5, 2, 3, 0, 1]

setTimeout()的参数

我知道知道这点,可能让我减少使用.bind(...)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
setTimeout(alert, 1000, 'Hello world!');

/*
* # 输出 (alert)
* Hello World!
*/

function log(text, textTwo) {
console.log(text, textTwo);
}

setTimeout(log, 1000, 'Hello World!', 'And Mars!');

/*
* # 输出
* Hello World! And Mars!
*/

HTMLElement.dataset

我以前在HTML元素上使用过自定义数据属性data-*,但是我没有意识到,有一个API可以很容易地查询它们。 除了一些明明限制(看上面的链接),它本质上,通过短线格式为属性命名,用驼峰格式在JS中查询。因此,比如属性data-birth-planet会在JS中变为birthPlanet

1
<div id='person' data-name='john' data-birth-planet='earth'></div>

查询:

1
2
3
4
5
6
7
8
9
let personEl = document.querySelector('#person');

console.log(personEl.dataset) // DOMStringMap {name: "john", birthPlanet: "earth"}
console.log(personEl.dataset.name) // john
console.log(personEl.dataset.birthPlanet) // earth

// 你也可以在代码里添加更多属性
personEl.dataset.foo = 'bar';
console.log(personEl.dataset.foo); // bar

最后

希望你能像我之前一样,在文章里发现一些JS的新东西。为新的MDN网站而向Mozilla点赞👍。在我看来,MDN更棒了——我花在上面的时间超乎我的想象。

2018,新年快乐🎆!

本文完

0%