正文 4877字数 341,224阅读


标记语句

命名完新名称之后可以在 for 循环中的 break 和 continue 之后、语句块中的 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 */
Run code
Cut to clipboard


    下面是语句块命名的例子,在语句块中只能在 break 之后使用新命名。

    foo: { console.log('one'); break foo; console.log('这句打印不会被执行'); } console.log('two'); /* * # 输出 * one * two */
    Run code
    Cut to clipboard


      "void" 运算符

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

      使用它,可以换一种方式来写立即调用的函数表达式(IIFE),:
      void function iife() { console.log('hello'); }(); // 和下面等效 (function iife() { console.log('hello'); })()
      Run code
      Cut to clipboard

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

        const word = void function iife() { return 'hello'; }(); // word 是 `undefined` const word = (function iife() { return 'hello'; })(); // word 是 "hello"
        Run code
        Cut to clipboard


          也可以和 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); } })();
          Run code
          Cut to clipboard


            逗号运算符

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

            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
            Run code
            Cut to clipboard


              配合 条件运算符

              逗号运算符中的最后一个值作为返回给条件运算符的值,因此可以在最后一个值前面放任意多个表达式。

              在下面的例子中,在返回的布尔值之前放了打印语句

              const type = 'man'; const isMale = type === 'man' ? ( console.log('Hi Man!'), true ) : ( console.log('Hi Lady!'), false ); console.log(`isMale is "${isMale}"`);
              Run code
              Cut to clipboard


                国际化 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
                Run code
                Cut to clipboard


                  管道操作符

                  const square = (n) => n * n; const increment = (n) => n + 1; // 不使用管道操作符 square(increment(square(2))); // 25 // 使用管道操作符 2 |> square |> increment |> square; // 25
                  Run code
                  Cut to clipboard


                    值得一提

                    Atomics

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

                    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]
                    Run code
                    Cut to clipboard


                      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! */
                      Run code
                      Cut to clipboard


                        HTMLElement.dataset

                        在此之前我一直对 HTML 元素使用自定义数据属性 data-*,因为我不曾意识到存在一个 API 来方便地查询它们。除了个别的命名限制之外(见链接),它的作用基本就是在 JS 中查询的时候允许你使用驼峰命名法(camelCase)来查询「减号-命名」(dash-case)的属性。所以属性名 data-birth-planet 在 JS 中就变成了 birthPlanet。

                        <div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth>John Doe </div> var el = document.querySelector('#user'); // el.id == 'user' // el.dataset.id === '1234567890' // el.dataset.user === 'johndoe' // el.dataset.dateOfBirth === '' el.dataset.dateOfBirth = '1960-10-03'; // set the DOB. // 'someDataAttr' in el.dataset === false el.dataset.someDataAttr = 'mydata'; // 'someDataAttr' in el.dataset === true
                        Run code
                        Cut to clipboard


                          查询:
                          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
                          Run code
                          Cut to clipboard


                            原文地址:JS things I never knew existed
                            译文出自:我未曾见过的 JS 特性