【學習筆記】ES6標準入門

這裏簡要記錄一下對本身感觸比較深的幾個知識點,將核心的應用投放於實際的項目之中,提供代碼的可維護性。node

 

1、let和constreact

{
    // let聲明的變量只在let命令所在的代碼塊內有效
    let a = 1;
    var b = 2;
}

console.log(a);     // 報錯: ReferenceError: a is not defined
console.log(b);
// for循環的技術器就很適合let命令
for (let i = 0; i < 3; i++) {
    console.log(i);
}

console.log(i); // ReferenceError: i is not defined
// 這裏的i是var聲明的,在全局範圍內有效,素偶一每一次循環,新的i值都會覆蓋舊值,致使最後輸出的是最後一輪的i值
for (var i = 0; i < 10; i++) {
    a[i] = function() {
        console.log(i);
    }
}

a[6](); // 10

var b = [];

// 使用let聲明的變量盡在塊級做用域內有效,因此每一次循環的j其實都是一個新的變量,因而最後輸出6
for (let j = 0; j < 10; j++) {
    a[j] = function() {
        console.log(j);
    }
}

b[6]();
// let不像var那樣會發生"變量"提高的現象
// 可是通過babel轉換器轉換以後,仍是存在變量提高的現象
// ES6明確規定,若是區塊中存在let和const命令,則這個區塊中對這些命令聲明的變量從一開始就造成封閉做用域.只要在聲明這些變量以前就使用這些變量,就會報錯
{
    console.log(foo);   // ReferenceError
    let foo = 2;
}

// 塊級做用域
{
    // 塊級做用域的出現使得得到普遍應用的當即執行匿名函數(IIFE)再也不必要了
    // IIFE寫法
    (function() {
        var tmp = 'a';
        // ...
    })();

    // 塊級做用域寫法
    {
        let tmp = 'a';
        // ...
    }

    // 所以,咱們可使用塊級做用域來劃分業務模塊,以及避免全局變量

}

{
    let a = 'secret';

    function f() {
        return a;
    }
}

f();    // 報錯
// const聲明的常量不得改變值
// const一旦聲明常量,就必須當即初始化,不能留到之後賦值
// const的做用域與let命令相同:只在聲明所在的塊級做用域內有效
// const命令聲明的變量也不提高,只能聲明後使用
const foo = 'AAA';
foo = 'BBB';    // 編譯不經過
{
    // 跨模塊常量
    // constants.js
    //export const A = 1;
    //export const B = 2;
    //export const C = 3;

    // test1.js模塊
    //import * as constants from 'constants';
    
}
// 全局對象的屬性
var a = 1;
console.log(window.a);  // 1

let b = 2;
console.log(window.b);  // undefined

 

2、字符串es6

{
    // 使用for of循環字符串
    for (let c of 'foo') {
        console.log(c);
    }

    let s = 'Hello world!';
    
    // 使用字符串的startsWidth/endsWidth/includes方法
    console.log(s.startsWith('Hello')); // true
    console.log(s.endsWith('!'));   // true
    console.log(s.includes('e'));   // true

    // 這三個方法都支持第二個參數,表示開始搜索的位置
    s.startsWith('world', 6);   // true

    let person = {
        name: 'king',
        age: 20
    };
    
    // 模板字符串
    // 全部的空格和縮進都會被保留在輸出中
    let str = (`
        The name is ${person.name}.
        The age is ${person.age}.
    `);

    console.log(str);

}

 

3、函數ajax

// 函數參數的默認值
function log(x, y = 'world') {
    console.log(x, y);
}

log('hello');   // 能夠省略尾部參數的默認值

function f(x = 1, y) {
    return [x, y];
}

f();    // [1, undefined]
f(2);   // [2, undefined]
f(, 1); // 報錯, 編譯沒法經過


// rest參數
function add(...values) {
    let sum = 0;

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

    return sum;
}

console.log(add(2, 5, 3));   // 10


const sortNumbers = function() {
    let arr = Array.prototype.slice.call(arguments);
    return arr.sort();
};

const sortNumbers = function (...numbers) {
    return numbers.sort();
};

sortNumbers(3, 1, 2);

// rest參數必須是參數列表中的最後一個
const push = function(array, ...items) {
    items.forEach(function(item) {
        array.push(item);
    });
};

let a = [];

console.log(push(a, 3, 1, 2));

 

4、對象編程

// Object.assign方法用來將源對象的全部可枚舉屬性複製到目標對象
let target = {
    a: 1
};

// 後邊的屬性值,覆蓋前面的屬性值
Object.assign(target, {
    b: 2,
    c: 3
}, {
    a: 4
});

console.log(target);

// 用處1 - 爲對象添加屬性
class Point {
    constructor(x, y) {
        Object.assign(this, {x, y});
    }
}

//let p = new Point(1, 2);
//
//console.log(p); // Point {x: 1, y: 2}

// 用處2 - 爲對象添加方法
Object.assign(Point.prototype, {
    getX() {
        return this.x;
    },
    setX(x) {
        this.x = x;
    }
});

let p = new Point(1, 2);

console.log(p.getX());  // 1

// 用處3 - 克隆對象
function clone(origin) {
    return Object.assign({}, origin);
}

 

5、Set和Mapjson

  // Set裏面的成員的值都是惟一的,沒有重複的值,Set加入值時不會發生類型轉換,因此5和"5"是兩個不一樣的值.
    let s = new Set();

    [2, 3, 5, 4, 5, 2, 2].map(function(x) {
        s.add(x);
    });

    //for (let i of s) {
    //    console.log(i);
    //}

    console.log([...s]);

    console.log(s.size);


    // 數組去重
    function dedupe(array) {
        return Array.from(new Set(array));
    }

    console.log(dedupe([1, 2, 2, 3]));  // 1, 2, 3
{

    // Map相似於對象,也是鍵值對的集合,可是"鍵"的範圍不限於字符串,各類類型的值(包括對象)均可以當作鍵.
    // 也就是說,Object結構提供了"字符串--值"的對應,Map的結構提供了"值——值"的對象,是一種更完善的Hash結構實現.

    var m = new Map();

    var o = {
        p: 'Hello World'
    };

    m.set(o, 'content');
    m.get(o);   // content

    m.has(o);    // true
    m.delete(o);    // true
    m.has(o);   // false

    m.set(o, 'my content').set(true, 7).set('foo', 8);

    console.log(m);

    // Map/數組/對象 三者之間的相互轉換
    console.log([...m]);

}

 

6、Iterator和Generator數組

{
    // 是一種接口,爲各類不一樣的數據結構提供統一的訪問機制.任何數據結構,只要不輸Iterator接口,就能夠完成遍歷操做.
    // 可供for...of循環消費

    const arr = ['red', 'green', 'blue'];

    let iterator = arr[Symbol.iterator]();

    for (let v of arr) {
        console.log(v); // red green blue
    }

    for (let i of iterator) {
        console.log(i);
    }

    // for of 循環能夠代替數組對象的forEach方法, 一樣能夠替代對象的for in循環

}
{
    function * foo() {
        yield 1;
        yield 2;
        yield 3;
        yield 4;
        yield 5;
        return 6;
    }

    for (let v of foo()) {
        console.log(v);
    }

}

 

7、Promise和asyncpromise

{
    let getJSON = function (path, param) {

        return new Promise(function(resolve, reject) {
            let async = typeof param.async == 'undefined' ? true : param.async;
            //let deferred = $.Deferred();

            param = param || {};
            param.data.auth_token = lib.getToken();

            window.loading();

            $.ajax({
                url: path,
                data: param.data,
                type: 'POST',
                dataType: 'json',
                async: async,
                timeout: 15000,
                success: function (data) {
                    window.unloading();
                    if (data.code == 0) {
                        resolve.apply(this, [data]);
                    } else {
                        reject.apply(this, [data]);
                        lib.alert(data.msg, '我知道了');
                    }
                },
                error: function (xhr, type) {
                    window.unloading();
                    reject.apply(this, ['網絡異常, 請稍候再試']);
                    lib.alert('網絡異常, 請稍候再試');
                }
            });
        });

    };

    getJSON('/xxx.json').then(function(rep) {

    }).catch(function(rep) {

    });

}
{

    function timeout(ms) {
        return new Promise(function(resolve) {
            setTimeout(resolve, ms);
        });
    }

    async function asyncPrint(value, ms) {
        let promise = await timeout(ms);
        console.log(value);
    }

    asyncPrint('Hello world !', 1000);

}

 

8、class瀏覽器

{
    class Point {

        static classMethod() {
            return 'classMethod...';
        }

        // constructor方法是類的默認方法,經過new命令生成對象實例時自動調用該方法.
        // 一個類必須有constructor方法,若是沒有顯示定義,一個空的constructor方法會被默認添加
        constructor(x, y) {
            this.x = x;
            this.y = y;
        }

        toString() {
            return '(' + this.x + ', ' + this.y + ')';
        }

        get prop() {
            return 'getter';
        }

        set prop(value) {
            console.log('setter:' + value);
        }

    }

    // 靜態屬性的處理,只能用下面這種方式
    Point.foo = 1;
    console.log(Point.foo); // 1

    // 繼承
    class ColorPoint extends Point {

        constructor(x, y, color) {
            // super方法必須被調用, 不然編譯不經過
            // 若是super在賦值屬性this.xx = xx,後邊調用,會報錯'this' is not allowed before super()
            super(x, y);
            this.color = color;
        }

        toString() {
            return 'The color is ' + this.color + ' and the point is ' + super.toString();
        }

    }

    var p = new ColorPoint(1, 2, 'red');
    console.log(p.toString());
    p.prop = 1;
    p.prop;

    console.log(Point.classMethod());

    // 父類的靜態方法能夠被子類繼承
    console.log('ColorPoint.classMethod(): ' + ColorPoint.classMethod());


}

 

 9、Module服務器

{
    // module
    /**
     * 優點:
     *  1. ES6能夠在編譯時就完成模塊編譯,效率要比commonJs模塊的加載方式高
     *  2. 再也不須要UMD模塊格式,未來服務器端和瀏覽器都會支持ES6模塊格式.目前,經過各類工具庫其實已經作到了這一點
     *  3. 未來瀏覽器的新API能夠用模塊格式提供,再也不須要作成全局變量或者navigator對象的屬性
     *  4. 再也不須要對象做爲命名空間(好比Math對象),將來這些功能能夠經過模塊提供
     */

}
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};


// export命令除了輸出變量,還能夠輸出函數或類(class)。
export function multiply (x, y) {
    return x * y;
};

// export輸出的變量就是原本的名字,可是可使用as關鍵字重命名。

function v1() {
    //...
}
function v2() {
    //...
}

export {
    v1 as streamV1,
    v2 as streamV2,
    v2 as streamLatestVersion
};



// import
// main.js

import {firstName, lastName, year} from './profile';

// 重命名
import { lastName as surname } from './profile';

// import命令具備提高效果,會提高到整個模塊的頭部,首先執行。
foo();
import { foo } from 'my_module';


// 僅僅執行lodash模塊,可是不輸入任何值。
import 'lodash';




// export default
// 爲了給用戶提供方便,讓他們不用閱讀文檔就能加載模塊,就要用到export default命令,爲模塊指定默認輸出。

// export-default.js
export default function () {
    console.log('foo');
}

// import-default.js
// 須要注意,這時import命令後面,不使用大括號。
import customName from './export-default';
customName(); // 'foo'


// export default命令用在非匿名函數前,也是能夠的。
// export-default.js
export default function foo() {
    console.log('foo');
}

// 或者寫成

function foo() {
    console.log('foo');
}

export default foo;

 

10、編程風格
// 1. let取代var



// 2. 全局常量 // 在let和const之間,建議優先使用const,尤爲是在全局環境,不該該設置變量,只應設置常量。 // const聲明常量還有兩個好處,一是閱讀代碼的人馬上會意識到不該該修改這個值,二是防止了無心間修改變量值所致使的錯誤。 // 全部的函數都應該設置爲常量。 // bad var a = 1, b = 2, c = 3; // good const a = 1; const b = 2; const c = 3; // best const [a, b, c] = [1, 2, 3];


// 3. 字符串 // 靜態字符串一概使用單引號或反引號,不使用雙引號。動態字符串使用反引號。


// 4. 對象 //對象儘可能靜態化,一旦定義,就不得隨意添加新的屬性。若是添加屬性不可避免,要使用Object.assign方法。 // bad const a = {}; a.x = 3; // if reshape unavoidable const a = {}; Object.assign(a, { x: 3 }); // good const a = { x: null }; a.x = 3; // 對象的屬性和方法,儘可能採用簡潔表達法,這樣易於描述和書寫。 var ref = 'some value'; // bad const atom = { ref: ref, value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { ref, value: 1, addValue(value) { return atom.value + value; }, };


// 5. 數組 //使用擴展運算符(...)拷貝數組。 // bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items]; //使用Array.from方法,將相似數組的對象轉爲數組。 const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);



// 6. 函數 //不要在函數體內使用arguments變量,使用rest運算符(...)代替。由於rest運算符顯式代表你想要獲取參數,並且arguments是一個相似數組的對象,而rest運算符能夠提供一個真正的數組。 // bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); } //使用默認值語法設置函數參數的默認值。 // bad function handleThings(opts) { opts = opts || {}; } // good function handleThings(opts = {}) { // ... }



// 7. 模塊 //首先,Module語法是JavaScript模塊的標準寫法,堅持使用這種寫法。使用import取代require。 // bad const moduleA = require('moduleA'); const func1 = moduleA.func1; const func2 = moduleA.func2; // good import { func1, func2 } from 'moduleA'; //使用export取代module.exports。 // commonJS的寫法 var React = require('react'); var Breadcrumbs = React.createClass({ render() { return <nav />; } }); module.exports = Breadcrumbs; // ES6的寫法 import React from 'react'; const Breadcrumbs = React.createClass({ render() { return <nav />; } }); export default Breadcrumbs //若是模塊只有一個輸出值,就使用export default,若是模塊有多個輸出值,就不使用export default,不要export default與普通的export同時使用。 //不要在模塊輸入中使用通配符。由於這樣能夠確保你的模塊之中,有一個默認輸出(export default)。 // bad import * as myObject './importModule'; // good import myObject from './importModule'; //若是模塊默認輸出一個函數,函數名的首字母應該小寫。 function makeStyleGuide() { } export default makeStyleGuide; //若是模塊默認輸出一個對象,對象名的首字母應該大寫。 const StyleGuide = { es6: { } }; export default StyleGuide;

 

但願我所記錄的,正是你所想要的。 

最後,將這本書的封面放在這裏——

相關文章
相關標籤/搜索