我未曾见过的 JS 特性

我未曾见过的 JS 特性

大家好,又见面了,我是全栈君。

我未曾见过的 JS 特性

有一天我正在阅读 MDN 文档,发现了一些我之前压根没有意识到在 JS 中存在的特性和 API。这里我罗列了一些,不管它们是否有用,JS 的学习永无止境。

标记语句

有多少人知道在 JS 里你可以给 for 循环和语句块命名?反正我不知道…… 命名完新名称之后你可以在 for 循环中的 breakcontinue 之后、语句块中的 break 之后使用新名称。

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 之后使用新命名。

foo: {
  console.log('one');
  break foo;
  console.log('这句打印不会被执行');
}
console.log('two');

/*
 * # 输出
 * one
 * two
 */
复制代码

“void” 运算符

我一度以为我已经了解了所有的运算符,直到我看到了这一个。它从 1996 年 起就存在于 JS 了。所有的浏览器都支持,并且它也很容易理解,引用自 MDN:

void 运算符对给定的表达式进行求值,然后返回 undefined。

使用它,你可以换一种方式来写立即调用的函数表达式(IIFE),就像这样:

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

// 和下面等效

(function iife() {
    console.log('hello');
})()
复制代码

使用 void 的一个注意点是,无论给定的表达式返回结果是什么,void 运算符的整体结果都是空的(undefined)!

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

// word 是 `undefined`

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

// word 是 "hello"
复制代码

你也可以和 async 一起使用 void,这样你就能把函数作为异步代码的入口:

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 的引用:

逗号运算符对它的每个操作数求值(从左到右),并返回最后一个操作数的值。

function myFunc() {
  let x = 0;
  return (x += 1, x); // 等价于 return ++x;
}

y = false, true; // console 中得到 true
console.log(y); // false,逗号优先级低于赋值

z = (false, true); // console 中得到 true
console.log(z); // true,括号中整体返回 true
复制代码

配合 条件运算符

逗号运算符中的最后一个值作为返回给条件运算符的值,因此你可以在最后一个值前面放任意多个表达式。在下面的例子中,我在返回的布尔值之前放了打印语句。

const type = 'man';

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

console.log(`isMale is "${isMale}"`);
复制代码

国际化 API

即使在最有利的情况下,国际化还是很难做好。幸好还有一套大部分浏览器都支持得不错的 API。其中我最爱的一个特性就是日期格式化,见下面的例子:

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
复制代码

管道操作符

在此篇成文之时,该功能只有 Firefox 58 及以上版本通过传入启动参数来支持,不过 Babel 已经有一个针对它的 插件提议。它看起来应该是受到 bash 的启发,我觉得很棒!

const square = (n) => n * n;
const increment = (n) => n + 1;

// 不使用管道操作符
square(increment(square(2))); // 25

// 使用管道操作符
2 |> square |> increment |> square; // 25
复制代码

值得一提

Atomics

当数据被多个线程共享时,原子操作确保正在读和写的数据是符合预期的,即下一个原子操作一定会在上一个原子操作结束之后才会开始。这有利于保持不同线程间的数据同步(比如主线程和另一条 WebWorker 线程)。

我很喜欢如 Java 等其它语言中的原子性。我预感当越来越多的人使用 WebWorkers,将操作从主线程分离出来时,原子操作的使用会越来越广泛。

Array.prototype.reduceRight

好吧,我之前从未见过这个,因为它基本等同于 Array.prototype.reduce() + Array.prototype.reverse() 并且你很少需要这么做。但如果你有这需求的话,reduceRight 是最好的选择!

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

// flattened array is [4, 5, 2, 3, 0, 1]
复制代码

setTimeout() 参数

这个早就存在了,但如果我早点知道的话,我大概可以省去很多的 .bind(...)

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 中查询的时候允许你使用驼峰命名法(camelCase)来查询「减号-命名」(dash-case)的属性。所以属性名 data-birth-planet 在 JS 中就变成了 birthPlanet

<div id='person' data-name='john' data-birth-planet='earth'></div>
复制代码

查询:

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
复制代码

结束语

我希望你和我一样在这里学到了一些新知识。在此也赞一下 Mozila 新的 MDN 站点,看起来非常棒,我花了比想象中更多的时间来阅读文档。

修订: 修正几处命名并且为 async 函数添加 try, catch。感谢 Reddit!

2018 新年快乐!


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/107722.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 如何制作rootfs_linux常用文件系统类型

    如何制作rootfs_linux常用文件系统类型rootfs文件系统制作笔记环境:XC2440linux2.32.2红帽5根文件系统有一系列的目录组成,其中包括应用程序、C库、及相关的配置文件。制作根文件系统的步骤如下,下面步骤均在虚拟机终端上操作。一、创建文件系统总目录rootfs【mkdirrootfs】二、创建文件系统目录【cdrootfs】进入rootfs目录,创建下面目录/bin–放置…

  • system.out.println()里面_println的意思

    system.out.println()里面_println的意思1.第一次见到该表达式的感受&amp;nbsp;&amp;nbsp;第一此次见到该表达式的时候,我还不知道什么是方法引用,当时真是一脸蒙圈,然后问了好多同事,给我的解释也是五花八门,但我还是感觉莫名其妙,有段时间想着就当一个特例记住就好了,不要再去深究了!!!但是我这个人,在这种时候就是很难说服自己,于是有了上篇文章,再回过头来看这个问题,其实就变得非常简单了。2.揭开System.out::print…

  • Unity3D开发入门教程(一)——搭建开发环境[通俗易懂]

    Unity3D开发入门教程(一)——搭建开发环境[通俗易懂]五邑隐侠,本名关健昌,12年游戏生涯。本教程以Unity3D+VSCode+C#+xlua为例。一、安装Unity1、从官网下载UnityHub:https://uni

  • pycharm2.5 永久激活码破解方法

    pycharm2.5 永久激活码破解方法,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • idea企业开发之插件推荐

    idea企业开发之插件推荐推荐在企业开发中,使用IntelliJIDEA时常使用到的插件。

  • android之View的启动过程[通俗易懂]

    程序里调用了onSizeChanged方法进行了一些设置,不知道onSizeChanged是在什么时候启动的,所以研究了一下View的启动流程代码如下:public class TestView extends View { public TestView(Context context) { super(context); Log.d(“mDebug”, “TestV

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号