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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章