ES6入門學習筆記

阮一峯老師-ECMAScript 6 入門的學習筆記

<!DOCTYPE HTML>
<html>
<head>
    <script type="text/javascript">
        // let 聲明的變量,只在命令所在的代碼塊內有效。

        {
            {
              let a = 10;
              var b = 1;
            }

            //a // ReferenceError: a is not defined.
            //b // 1

            // let不像var那樣會發生“變量提升”現象。所以,變量一定要在聲明後使用,否則報錯。
            {
                console.log(foo); // 輸出undefined
                //console.log(bar); // 報錯ReferenceError

                var foo = 2;
                let bar = 2;
            }

            // const 作用域與let相似,一旦聲明不能重新賦值
            {
                const PI = 3.1415;
                PI
            }
        }
        {
            {
                // es6中變量可以這樣聲明,這種方式稱爲解構(Destructuring)。
                let [c, d, e] = [1, 2, 3];

                console.log(c+","+d)
            }
            {
                let [foo, [[bar], baz]] = [1, [[2], 3]];
                foo // 1
                bar // 2
                baz // 3
            }
            {
                let [ , , third] = ["foo", "bar", "baz"];
                third // "baz"
            }
            {
                let [x, , y] = [1, 2, 3];
                x // 1
                y // 3
            }
            {
                let [head, ...tail] = [1, 2, 3, 4];
                head // 1
                tail // [2, 3, 4]
            }
            {
                let [x, y, ...z] = ['a'];
                x // "a"
                y // undefined
                z // []
            }
            {
                //let [foo] = 1;
                //let [foo] = false;
                //let [foo] = NaN;
                //let [foo] = undefined;
                //let [foo] = null;
                //let [foo] = {};
            }
            {   
                // 允許默認值 
                var [foo = true] = [];
                foo // true

                let [x, y = 'b'] = ['a']; // x='a', y='b'
                // [x, y = 'b'] = ['a', undefined]; // x='a', y='b' 
                console.log(x + "," + y);
            }
            {
                // 可以解構對象
                var { bar, foo } = { foo: "aaa",  sec: "bbb", bar: "bbb" };
                foo // "aaa"
                bar // "bbb"
                var { baz } = { foo: "aaa", bar: "bbb" };
                baz // undefined
            }
            {
                let { log, sin, cos } = Math;
            }
            {
                // 函數參數也可以解構
                function add([x, y]){
                  return x + y;
                }

                add([1, 2]); // 3
            }

            /* 解構實用功能 */
            {
                // 變換變量的值
                let [x, y] = [1, 2];
                [x, y] = [y, x];

                console.log(x + "," + y);
            }
            {
                // 函數返回多個值

                // 返回一個數組
                /*
                function example() {
                  return [1, 2, 3];
                }
                var [a, b, c] = example();
                */

                // 返回一個對象
                function example() {
                  return {
                    foo: 1,
                    bar: 2
                  };
                }
                var { foo, bar } = example();
            }
            {
                // 提取JSON數據
                var jsonData = {
                  id: 42,
                  status: "OK",
                  data: [867, 5309]
                };

                let { id, status, data: number } = jsonData;

                console.log(id, status, number);
                // 42, "OK", [867, 5309]
            }
            {
                // 遍歷map結構
                var map = new Map();
                map.set('first', 'hello');
                map.set('second', 'world');

                for (let [key, value] of map) {
                  console.log(key + " is " + value);
                }
                // first is hello
                // second is world
            }
            {
                // 加載模塊時,往往需要指定輸入那些方法。解構賦值使得輸入語句非常清晰。
                // const { SourceMapConsumer, SourceNode } = require("source-map");
            }
        }

        /* 字符串的擴展 */
        {
            // 如果直接在\u後面跟上超過0xFFFF的數值(比如\u20BB7),JavaScript會理解成\u20BB+7。由於\u20BB是一個不可打印字符
            // ES6 對這一點做出了改進,只要將碼點放入大括號,就能正確解讀該字符。
            {
                "\u{20BB7}"
                // "��"

                "\u{41}\u{42}\u{43}"
                // "ABC"

                let hello = 123;
                hell\u{6F} // 123

                '\u{1F680}' === '\uD83D\uDE80'
                // true
            }
            // codePointAt
            {
                var s = '��a';

                s.codePointAt(0) // 134071
                s.codePointAt(1) // 57271

                s.codePointAt(2) // 97
            }
            {
                String.fromCodePoint(0x20BB7)
                // "��"
                String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
                // true
            }
            // 除了遍歷字符串,這個遍歷器最大的優點是可以識別大於0xFFFF的碼點,傳統的for循環無法識別這樣的碼點。
            {
                var text = String.fromCodePoint(0x20BB7);

                for (let i = 0; i < text.length; i++) {
                  console.log(text[i]);
                }
                // " "
                // " "

                for (let i of text) {
                  console.log(i);
                }
                // "��"
            }
            // ES5對字符串對象提供charAt方法,返回字符串給定位置的字符。該方法不能識別碼點大於0xFFFF的字符。
            {
                // 'abc'.at(0) // "a"
                // '��'.at(0) // "��"
            }
            {
                var s = 'Hello world!';

                s.startsWith('Hello') // true
                s.endsWith('!') // true
                s.includes('o') // true

                console.log(s.startsWith('Hello'));
                console.log(s.endsWith('!'));
                console.log(s.includes('o'));
            }
            // repeat方法返回一個新字符串,表示將原字符串重複n次。
            {
                'x'.repeat(3) // "xxx"
                'hello'.repeat(2) // "hellohello"
                'na'.repeat(0) // 
                console.log('x'.repeat(3));
                console.log('x'.repeat(-0.5)); // "" (-1,0]

                //'na'.repeat(Infinity)
                // RangeError
                // 'na'.repeat(-1)
                // RangeError
            }
            // ES7推出了字符串補全長度的功能。
            // 如果某個字符串不夠指定長度,會在頭部或尾部補全。padStart用於頭部補全,padEnd用於尾部補全。
            {
                // 'x'.padStart(5, 'ab') // 'ababx'
                // 'x'.padStart(4, 'ab') // 'abax'

                // 'x'.padEnd(5, 'ab') // 'xabab'
                // 'x'.padEnd(4, 'ab') // 'xaba
            }
            {
                // 普通字符串
                `In JavaScr
                ipt '\n'is a line-feed.`

                console.log(`In JavaScript this is
                 not legal.`);

                // 多行字符串
                //`In JavaScript this is
                // not legal.`

                console.log(`string text line 1
                string text line 2`);

                // 字符串中嵌入變量
                var name = "Bob", time = "today";
                `Hello ${name}, how are you ${time}?`
                console.log(`Hello ${name}, how are you ${time}?`);
            }

            {
                var x = 1;
                var y = 2;

                `${x} + ${y} = ${x + y}`
                // "1 + 2 = 3"
                console.log(`${x} + ${y} = ${x + y}`);

                `${x} + ${y * 2} = ${x + y * 2}`
                // "1 + 4 = 5"
                console.log(`${x} + ${y * 2} = ${x + y * 2}`);

                var obj = {x: 1, y: 2};
                `${obj.x + obj.y}`
                // 3
            }
            // 模板之中還可以調用函數
            {
                function fn() {
                  return "Hello World";
                }

                `foo ${fn()} bar`
                // foo Hello World bar
            }

            {
                // 寫法一
                let str = 'return ' + '`Hello ${name}!`';
                let func = new Function('name', str);
                func('Jack') // "Hello Jack!"

                // 寫法二
                // let str = '(name) => `Hello ${name}!`';
                // let func = eval.call(null, str);
                // func('Jack') // "Hello Jack!"
            }
            // 模板嵌套
            {
                const tmpl = addrs => `
                  <table>
                  ${addrs.map(addr => `
                    <tr><td>${addr.first}</td></tr>
                    <tr><td>${addr.last}</td></tr>
                  `).join('')}
                  </table>
                `;

                const data = [
                    { first: '<Jane>', last: 'Bond' },
                    { first: 'Lars', last: '<Croft>' },
                ];

                console.log(tmpl(data));
            }
            {
                var template = `
                <ul>
                  <% for(var i=0; i < data.supplies.length; i++) { %>
                    <li><%= data.supplies[i] %></li>
                  <% } %>
                </ul>
                `;

                /*
                    echo('<ul>');
                    for(var i=0; i < data.supplies.length; i++) {
                      echo('<li>');
                      echo(data.supplies[i]);
                      echo('</li>');
                    };
                    echo('</ul>');
                */

                var evalExpr = /<%=(.+?)%>/g;
                var expr = /<%([\s\S]+?)%>/g;

                template = template
                  .replace(evalExpr, '`); \n  echo( $1 ); \n  echo(`')
                  .replace(expr, '`); \n $1 \n  echo(`');

                template = 'echo(`' + template + '`);';

                console.log(template);


                /*
                 // 封裝成一個方法返回
                var script =
                `(function parse(data){
                  var output = "";

                  function echo(html){
                    output += html;
                  }

                  ${ template }

                  return output;
                })`;

                return script;*/
            }
            // “標籤”指的就是函數,緊跟在後面的模板字符串就是它的參數。
            {
                // alert`123`
                // 等同於
                // alert(123);
            }
            // 如果模板字符裏面有變量,就不是簡單的調用了,而是會將模板字符串先處理成多個參數,再調用函數。
            {
                var a = 5;
                var b = 10;

                //tag`Hello ${ a + b } world ${ a * b }`;
                // 等同於
                //tag(['Hello ', ' world ', ''], 15, 50);


                /*
                 * tag函數的第一個參數是一個數組,
                 * 該數組的成員是模板字符串中那些沒有變量替換的部分,
                 * 也就是說,變量替換隻發生在數組的第一個成員與第二個成員之間、
                 * 第二個成員與第三個成員之間,以此類推。
                 */
                function tag(stringArr, value1, value2){
                  // ...
                }

                // 等同於

                function tag(stringArr, ...values){
                  // ...
                }
            }

            {
                var message =
                  SaferHTML`<p>& has sent you a message.</p>`;

                function SaferHTML(templateData) {
                  var s = templateData[0];
                  for (var i = 1; i < arguments.length; i++) {
                    var arg = String(arguments[i]);

                    // Escape special characters in the substitution.
                    s += arg.replace(/&/g, "&amp;")
                            .replace(/</g, "&lt;")
                            .replace(/>/g, "&gt;");

                    // Don't escape special characters in the template.
                    s += templateData[i];
                  }
                  return s;
                }

                console.log(message);
            }
            // String.raw方法可以作爲處理模板字符串的基本方法,
            // 它會將所有變量替換,而且對斜槓進行轉義,方便下一步作爲字符串來使用。
            {
                String.raw`Hi\n${2+3}!`;
                // "Hi\\n5!"

                String.raw`Hi\u000A!`;
                // 'Hi\\u000A!'
            }
        }
        {
            //返回的正則表達式會忽略原有的正則表達式的修飾符,只使用新指定的修飾符。
            {
                var regex = new RegExp(/xyz/, 'i');
            }
        }

        // Array.from方法用於將兩類對象轉爲真正的數組:
        // 類似數組的對象(array-like object)和可遍歷(iterable)的對象
        {
            let arrayLike = {
                '0': 'a',
                '1': 'b',
                '2': 'c',
                length: 3
            };

            // ES5的寫法
            var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

            // ES6的寫法
            let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
        }
        // 對於還沒有部署該方法的瀏覽器,可以用Array.prototype.slice方法替代。
        {
            const toArray = (() =>
              Array.from ? Array.from : obj => [].slice.call(obj)
            )();
        }
        {
            let spans = document.querySelectorAll('.name');

            // map()
            let names1 = Array.prototype.map.call(spans, s => s.textContent);

            // Array.from()
            let names2 = Array.from(spans, s => s.textContent)

            console.log(names1)
        }
        // 將數組中布爾值爲false的成員轉爲0。
        {
            Array.from([1, , 2, , 3], (n) => n || 0)
        }
        // Array.of方法用於將一組值,轉換爲數組
        {
            Array.of() // []
            Array.of(undefined) // [undefined]
            Array.of(1) // [1]
            Array.of(1, 2) // [1, 2]
        }
        /**
            target(必需):從該位置開始替換數據。
            start(可選):從該位置開始讀取數據,默認爲0。如果爲負值,表示倒數。
            end(可選):到該位置前停止讀取數據,默認等於數組長度。如果爲負值,表示倒數。
         */
        {
            // 將從3號位直到數組結束的成員(4和5),複製到從0號位開始的位置,結果覆蓋了原來的1和2
            [1, 2, 3, 4, 5].copyWithin(0, 3)
            // [4, 5, 3, 4, 5]
        }
        // 數組實例的find()和findIndex()
        {
            [1, 4, -5, 10].find((n) => n < 0)
            // -5

            /*[1, 5, 10, 15].find(function(value, index, arr) {
              return value > 9;
            }) // 10*/

            /*// 返回第一個符合條件的數組成員的位置,如果所有成員都不符合條件,則返回-1。
            [1, 5, 10, 15].findIndex(function(value, index, arr) {
              return value > 9;
            }) // 2*/
        }
        // 數組實例的fill() 
        {
            ['a', 'b', 'c'].fill(7)
            // [7, 7, 7]

            new Array(3).fill(7)
            // [7, 7, 7]

            // fill方法還可以接受第二個和第三個參數,用於指定填充的起始位置和結束位置
            //['a', 'b', 'c'].fill(7, 1, 2)
            // ['a', 7, 'c']
        }
        {
            for (let index of ['a', 'b'].keys()) {
              console.log(index);
            };
            // 0
            // 1

            /*for (let elem of ['a', 'b'].values()) {
              console.log(elem);
            }*/
            // 'a'
            // 'b'

            for (let [index, elem] of ['a', 'b'].entries()) {
              console.log(index, elem);
            };
            // 0 "a"
            // 1 "b"
        }
        // Array.prototype.includes方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的includes方法類似
        {
            [1, 2, 3].includes(2);     // true
            [1, 2, 3].includes(4);     // false
            [1, 2, NaN].includes(NaN); // true

            console.log([1, 2, 3].includes(6))
        }

        {

            // forEach方法
            [,'a'].forEach((x,i) => console.log(i)); // 1

            // filter方法
            ['a',,'b'].filter(x => true); // ['a','b']

            // every方法
            [,'a'].every(x => x==='a'); // true

            // some方法
            [,'a'].some(x => x !== 'a'); // false

            // map方法
            [,'a'].map(x => 1); // [,1]

            // join方法
            [,'a',undefined,null].join('#'); // "#a##"

            // toString方法
            [,'a',undefined,null].toString(); // ",a,,"

            //ES6 明確將空位轉爲undefined。
            Array.from(['a',,'b']);
            [ "a", undefined, "b" ];
        }
        // ES6 參數可以使用默認值
        {
            function log(x, y = 'World') {
              console.log(x, y);
            }

            log('Hello') // Hello World
            log('Hello', 'China') // Hello China
            log('Hello', '') // Hello
        }

        {
            function foo({x, y = 5}) {
              console.log(x, y);
            }

            foo({}) // undefined, 5
            foo({x: 1}) // 1, 5
            foo({x: 1, y: 2}) // 1, 2
            //foo() // TypeError: Cannot read property 'x' of undefined
        }

        //雙重默認值
        {
            function fetch(url, { method = 'GET' } = {}) {
              console.log(method);
            }

            fetch('http://example.com')
            // "GET"

            function m1({x = 0, y = 0} = {}) {
              return [x, y];
            }
            m1({x: 3}) // [3, 0]
        }
        // 作用域
        {
            let x = 1;

            function f(y = x) {
              let x = 2;
              console.log(y);
            }

            f() // 1

            var z = 1;

            function f(z, y = z) {
              console.log(y);
            }

            f(2) // 2
        }

        // 省略參數,拋出錯誤
        {
            function throwIfMissing() {
              throw new Error('Missing parameter');
            }

            function foo(mustBeProvided = throwIfMissing()) {
              return mustBeProvided;
            }

            //foo()
            // Error: Missing parameter
        }
        // ES6引入rest參數(形式爲“...變量名”),用於獲取函數的多餘參數,這樣就不需要使用arguments對象了
        {
            function add(...values) {
              let sum = 0;

              for (var val of values) {
                sum += val;
              }

              return sum;
            }

            add(2, 5, 3) // 10

            // arguments變量的寫法
            function sortNumbers() {
              return Array.prototype.slice.call(arguments).sort();
            }

            // rest參數的寫法
            const sortNumbers2 = (...numbers) => numbers.sort();
            console.log(sortNumbers([2,3,1]))
            console.log(sortNumbers2([2,3,1]))
        }
        // 擴展運算符(spread)是三個點(...)。它好比rest參數的逆運算,將一個數組轉爲用逗號分隔的參數序列。
        {
            console.log(...[1, 2, 3]);
            // 1 2 3

            console.log(1, ...[2, 3, 4], 5);
            // 1 2 3 4 5

            [...document.querySelectorAll('div')];
            // [<div>, <div>, <div>]

            function push(array, ...items) {
              array.push(...items);
            }

            function add(x, y) {
              return x + y;
            }

            var numbers = [4, 38];
            add(...numbers) // 42
        }
        // 由於擴展運算符可以展開數組,所以不再需要apply方法,將數組轉爲函數的參數了。
        {
            // ES5的寫法
            function f(x, y, z) {
              // ...
            }
            var args = [0, 1, 2];
            f.apply(null, args);

            // ES6的寫法
            function f(x, y, z) {
              // ...
            }
            var args = [0, 1, 2];
            f(...args);
        }
        // 簡化求出一個數組最大元素的寫法。
        {
            // ES5的寫法
            Math.max.apply(null, [14, 3, 77])

            // ES6的寫法
            Math.max(...[14, 3, 77])

            // 等同於
            Math.max(14, 3, 77);
        }

        {
            // ES5的寫法
            var arr1 = [0, 1, 2];
            var arr2 = [3, 4, 5];
            Array.prototype.push.apply(arr1, arr2);

            // ES6的寫法
            var arr1 = [0, 1, 2];
            var arr2 = [3, 4, 5];
            arr1.push(...arr2);
        }

        // 合併數組
        {
            let more = [5];
            // ES5
            [1, 2].concat(more);
            // ES6
            [1, 2, ...more];

            var arr1 = ['a', 'b'];
            var arr2 = ['c'];
            var arr3 = ['d', 'e'];

            // ES5的合併數組
            arr1.concat(arr2, arr3);
            // [ 'a', 'b', 'c', 'd', 'e' ]

            // ES6的合併數組
            [...arr1, ...arr2, ...arr3]
            // [ 'a', 'b', 'c', 'd', 'e' ]
        }

        {
            const [first, ...rest] = [1, 2, 3, 4, 5];
            first; // 1
            rest;  // [2, 3, 4, 5]

            const [first2, ...rest2] = [];
            first2; // undefined
            rest2;  // []:

            const [first3, ...rest3] = ["foo"];
            first3;  // "foo"
            rest3;   // []
        }
        // 如果將擴展運算符用於數組賦值,只能放在參數的最後一位,否則會報錯。
        {
            //const [...butLast, last] = [1, 2, 3, 4, 5];
            // 報錯

            //const [first, ...middle, last] = [1, 2, 3, 4, 5];
            // 報錯
        }
        {
            [...'hello']
            // [ "h", "e", "l", "l", "o" ]

            var nodeList = document.querySelectorAll('div');
            var array = [...nodeList];
        }

        //只要函數參數使用了默認值、解構賦值、或者擴展運算符,那麼函數內部就不能顯式設定爲嚴格模式,否則會報錯。
        {
            // 報錯
            /*function doSomething(a, b = a) {
              'use strict';
              // code
            }*/
        }
    </script>
</head>
<body>
    <span class="name">註釋的代碼表示會報錯,或者當前瀏覽器不支持</span>
</body>
</html>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章