1. 程式人生 > >es6 學習心得

es6 學習心得

inner sta reference 區別 aaa 子類 timeout extend pos

1、let/ const聲明變量(項目中常用)

之前使用var關鍵字聲明變量,無論聲明在何處,都會被視為聲明在它的作用域的最頂部(不在大括號內{}即在全局作用域的最頂部),而在es6之前JavaScript只有函數作用域和全局作用域。這就是變量提升。

console.log(a);  //輸出undefined

if (true) {

    var a = 1;

}

上面的代碼實際上是:

var a;

console.log(a); //輸出undefined

if (true) {

    a = 1;

}

(1)let聲明變量

let實際上為JavaScript新增了塊級作用域。let聲明的變量只在它所在的代碼塊內有效。

將上面變量提升的例子稍微變化一下:可以看出let聲明的a只在代碼塊內有效。

if(true) {

    var a = 1;

}

console.log(a)  //輸出1
if(true) {

    let a = 1;

}

console.log(a) //報錯ReferenceError: a is not defined

再看一個常見的例子:

var a = [];

for (var i = 0; i < 10; i++) {

    a[i] = function () {

        console.log(i);

    };

}

a[6](); //
10

每次循環的i指向的其實都是同一個i,很顯然最後的結果是10。那麽如何達到想要的效果?

·閉包(ES5)

var a = [];

for (var i = 0; i < 10; i++) {

    a[i] = (function (num) {

        return function () {

            console.log(num);

        };

    })(i)

}

a[6](); // 6

·let聲明變量(ES6)

var a = [];

for (let i = 0; i < 10; i++) {

    a[i] 
= function () { console.log(i); }; } a[6](); // 6

變量ilet聲明的,當前的i只在本輪循環有效,所以每一次循環的i其實都是一個新的變量。

使用let聲明變量的話,不存在變量提升的情況,必須在聲明以後才使用,否則會報錯,這在語法上稱為“暫時性死區”。並且let不允許在相同作用域內重復聲明變量。

(2)const聲明變量

const聲明的變量是一個只讀變量,一旦聲明就必須馬上初始化並且不能改變值,因此如果用const只聲明而不賦值也會報錯。

const的作用域與let相同,只在當前的塊級作用域內有效。同樣的,也不能變量提升,存在暫時性死區,不能重復聲明。

本質:

const實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同於常量。但對於復合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指針,const只能保證這個指針是固定的,至於它指向的數據結構是不是可變的,就完全不能控制了。因此,將一個對象聲明為常量必須非常小心。

const foo = {};

 

// 為 foo 添加一個屬性,可以成功

foo.prop = 123;

foo.prop // 123

 

// 將 foo 指向另一個對象,就會報錯

foo = {}; // TypeError: "foo" is read-only

總結:因此,可以知道什麽時候用let什麽時候用const:值會改變的變量用let聲明,值是一個不會改變的常量就用const聲明。

2、箭頭函數(項目中常用)

Es6使用“箭頭”(=>)定義函數。箭頭函數使得表達更簡潔。

箭頭函數的寫法:

const fn = (a, b) => a + b;

就相當於ES5標準下的:

var fn = function (a, b) {

    return a + b;

}

箭頭函數還可以與變量解構結合使用。

const full = ({ first, last }) => first + ‘ ‘ + last;

// 等同於

function full(person) {

    return person.first + ‘ ‘ + person.last;

}

使用箭頭函數有幾點需要註意。

(1) 函數體內的this對象,是定義時所在的對象,而不是使用時所在的對象。如果在箭頭函數內使用this,那麽該this是外層的this,換句話說,就是箭頭函數裏根本沒有自己的this,而是引用外層的this。

(2) 不可以當做構造函數,也就是說,不可以使用new命令,否則拋出錯誤。

(3) 不可以使用arguments對象,該對象在函數體內不存在。如果一定要用,可以使用rest參數代替。

上面的第一點尤其要註意,this對象的指向是可變的,但在箭頭函數中,它是固定的。

function foo() {

    setTimeout(() => {

        console.log(‘id:‘, this.id);

    }, 100);

}

var id = 21;

foo.call({ id: 42 });  // id: 42

上面代碼中,setTimeout的參數是一個箭頭函數,該箭頭函數生效是在foo函數生成時,而它真正執行則是在100毫秒後。如果是普通函數,執行時的this執行全局對象window,輸出21。而箭頭函數的this總是綁定在定義生效時所在的作用域,因此輸出42。

3、模板字符串

模板字符串解決了使用+號拼接字符串造成的不便利。模板字符串用(`)反引號標識,可以作普通字符串,也可以定義多行字符串,或者在字符串在嵌入變量。

// 普通字符串

`In JavaScript ‘\n‘ is a line-feed.`

// 多行字符串

`In JavaScript this is

 not legal.`

// 字符串中嵌入變量

let name = "Bob",

    time = "today";

`Hello ${name}, how are you ${time}?`

使用模板字符串表示多行字符串,所以的空格和縮進都會被保留在輸出中。

使用${}包裹一個變量或表達式。

4、變量的解構賦值

(1)數組的解構賦值

[基本用法]

let [a, b, c] = [1, 2, 3];

上面代碼表示。可以從數組中提取值,按照對應位置,給變量賦值。

本質上,這種寫法屬於“模式匹配”,只要等號兩邊模式相同,左邊的變量就會被賦予對應的值。

如果解構不成功,變量的值就等於undefined。

let [foo] = [];

foo //undefined

let [bar, foo] = [1];

foo //undefined

另一種情況是不完全解構,即等號左邊的模式只匹配一部分等號右邊的數組,這種情況下,解構依然成功

let [x, y] = [1, 2, 3];

x // 1

y // 2

[默認值]

解構賦值允許制定默認值。

let [foo = true] = [];

foo // true

es6內部使用嚴格相等運算符(===),判斷一個位置是否有值。只有數組成員嚴格等於undefined,默認值才會生效。

let [x, y = ‘b‘] = [‘a‘]; // x=‘a‘, y=‘b‘

let [x, y = ‘b‘] = [‘a‘, undefined]; // x=‘a‘, y=‘b‘

let [x = ‘a‘] = [null];

x // null

null不嚴格等於undefined,因此默認值不生效

(2)對象的解構賦值

解構不僅可以用於數組,還可以應用於對象。

let { bar, foo } = { foo: "aaa", bar: "bbb" };

foo // "aaa"

bar // "bbb"

等號左邊的兩個變量的次序,與等號右邊兩個同名屬性的次序不一致,但是對取值完全沒有影響。

let { baz } = { foo: "aaa", bar: "bbb" };

baz // undefined

變量沒有對應的同名屬性,導致取不到值,最後等於undefined

對象的解構賦值的內部機制,是先找到同名屬性,然後再賦給對應的變量。真正被賦值的是後者,而不是前者。

let { foo: baz } = { foo: "aaa", bar: "bbb" };

baz // "aaa"

foo // error: foo is not defined

foo是匹配的模式,baz才是變量。真正被賦值的是變量baz,而不是模式foo

(3)字符串的解構賦值

const [a, b, c, d, e] = ‘hello‘;

a // "h"

b // "e"

c // "l"

d // "l"

e // "o"

還可以對字符串的length屬性解構賦值

let { length: len } = ‘hello‘;

len // 5

(4)數值和布爾值的解構賦值

解構賦值是,登等號右邊是數值或布爾值,則會先轉為對象。

 let { toString: s } = 123;

s === Number.prototype.toString // true

 

let { toString: s } = true;

s === Boolean.prototype.toString // true

(5)函數參數的解構賦值

函數的參數也可使用解構賦值。

function add([x, y]) {

    return x + y;

}

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

(6)用途

變量的解構賦值的用途:

·交換變量的值

let x = 1;

let y = 2;

[x, y] = [y, x];

·從函數返回多個值

函數只能返回一個值,如果要返回多個值,只能把他們放在數組或對象裏返回。有了解構賦值,取出這些值非常方便。

// 返回一個數組

function example() {

    return [1, 2, 3];

}

let [a, b, c] = example();

// 返回一個對象

function example() {

    return {

        foo: 1,

        bar: 2

    };

}

let { foo, bar } = example();

·函數參數的定義

解構賦值可以方便地將一組參數與變量名對應。

// 參數是一組有次序的值

function f([x, y, z]) { ... }

f([1, 2, 3]);

// 參數是一組無次序的值

function f({ x, y, z }) { ... }

f({ z: 3, y: 2, x: 1 });

·提取數據

解構賦值對提取JSON對象中的數據尤其有用。

let jsonData = {

    id: 42,

    status: "OK",

    data: [867, 5309]

};

 

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

console.log(id, status, number);

// 42, "OK", [867, 5309]

·函數參數的默認值

指定參數的默認值,就避免了在函數內部再寫var foo = config.foo || ‘default foo’。

jQuery.ajax = function (url, {

    async = true,

    beforeSend = function () {},

    cache = true,

    complete = function () {},

    crossDomain = false,

    global = true,

    // ... more config

}) {

    // ... do stuff

};

5、函數參數的默認值

(1)默認用法

ES6之前不能給函數參數指定默認值,只能采用變通的方法。

function log(x, y) {

    y = y || ‘World‘;  

    console.log(x, y);

}

 

log(‘Hello‘) // Hello World

log(‘Hello‘, ‘China‘) // Hello China

log(‘Hello‘, ‘‘) // Hello World

上面的代碼檢查函數的參數y有沒有賦值,如果沒有,則指定默認值為World。但這樣的缺點在於,如果參數y賦值了,但對應的布爾值為false,則該賦值不起作用。如上面代碼最後一行,y等於空字符,結果還是被改為默認值。

為避免這個問題,通常需先判斷參數y是否被復制,如果沒有,再等於默認值。

if (typeof y === ‘undefined‘) {

    y = ‘World‘;

}

Es6允許函數的參數設置默認值,直接寫在參數定義的後面。

function log(x, y = ‘World‘) {

    console.log(x, y);

}

 

log(‘Hello‘) // Hello World

log(‘Hello‘, ‘China‘) // Hello China

log(‘Hello‘, ‘‘) // Hello

(2)與解構賦值默認值結合使用

函數參數默認值可以與解構賦值的默認值,結合起來使用。

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

上面的代碼只使用了對象的解構賦值默認值,沒有使用函數參數的默認值。只當函數foo的參數是一個對象時,變量x和y才會通過解構賦值生成。如果函數調用時沒提供參數,變量x和變量y就不會生成,因此報錯。提供函數的默認值就可以避免這種情況。

function foo({ x, y = 5 } = {}) {

    console.log(x, y);

}

 

foo() // undefined 5

上面的代碼指定,沒有提供參數,函數的參數默認為一個空對象。

// 寫法一

function m1({ x = 0, y = 0 } = {}) {

    return [x, y];

}

 

// 寫法二

function m2({ x, y } = { x: 0, y: 0 }) {

    return [x, y];

}

上面兩張寫法都對函數的參數設定了默認值,區別是寫法一函數參數的默認值是空對象,但設置了對象解構賦值的默認值;寫法二函數參數的默認值是一個有具體屬性的對象,但是沒有設置對象解構賦值的默認值。

// 函數沒有參數的情況

m1() // [0, 0]

m2() // [0, 0]

 

// x 有值,y 無值的情況

m1({ x: 3 }) // [3, 0]

m2({ x: 3 }) // [3, undefined]

 

// x 和 y 都無值的情況

m1({}) // [0, 0];

m2({}) // [undefined, undefined]

(3)作用域

設置了參數的默認值,函數進行聲明初始化時,參數會形成單獨的作用域,初始化結束,則該作用域消失。

var x = 1;

function f(x, y = x) {

    console.log(y);

}

f(2) // 2

上面代碼,y的默認值等於變量x。調用函數f時,參數形成一個單獨的作用域。在這個作用域裏,默認值變量x指向第一個參數x,而不是全局變量x,因此輸出的是2。

let x = 1;

function f(y = x) {

    let x = 2;

    console.log(y);

}

f() // 1

上面代碼,函數f調用時,參數y=x形成一個單獨作用域,在這個作用域裏,變量x本身無定義,所以指向外層的全局變量x。函數調用時,函數體內部的局部變量x不影響默認值變量x。

var x = 1;

function foo(x = x) {

    // ...

}

foo() // ReferenceError: x is not defined

上面代碼,參數x=x形成單獨作用域,實際執行的是let x = x,由暫時性死區的原因,這行代碼會報錯“x未定義”。

如過參數的默認值是一個函數,該函數的作用域也遵守這個規則。

let foo = ‘outer‘;

function bar(func = () => foo) {

    let foo = ‘inner‘;

    console.log(func());

}

bar(); // outer

上面代碼,函數bar的參數func的默認值是一個匿名函數,返回值為變量foo。函數參數形成的單獨作用域裏,沒有定義變量foo,因此foo指向外層的全局變量foo,因此輸出outer。

var x = 1;

function foo(x, y = function () { x = 2; }) {

    var x = 3;

    y();

    console.log(x);

}

foo() // 3

x // 1

上面代碼,函數foo的參數形成一個單獨作用域。改作用域裏,首先聲明變量x,然後聲明變量y,y的默認值是一個匿名函數。這個匿名函數內部的變量x,指向同一個作用域的第一個參數x。函數foo內部又聲明了一個內部變量x,該變量與第一個參數x由於不是同一個作用域,所以不是同一個變量,因此執行y後,內部變量x和外部全局變量x的值都沒變。

var x = 1;

function foo(x, y = function () { x = 2; }) {

    x = 3;

    y();

    console.log(x);

}

foo() // 2

x // 1

如果將var x = 3的var去除,函數foo的內部變量x就指向第一個參數x,與匿名函數內部的x是一致的,最後輸出2,而外層的全局變量x不受影響。

6、rest參數

引入rest參數(…變量名),用於獲取函數的多余參數,這樣就不需要使用arguments對象。Rest參數搭配的變量是一個數組,將多余的參數放入數組中。

function add(...values) {

    let sum = 0;

    for (var val of values) {

        sum += val;

    }

    return sum;

}

add(2, 5, 3) // 10

add函數是一個求和函數,利用rest參數,可以向該函數傳入任意數目的參數。

// arguments變量的寫法

function sortNumbers() {

    return Array.prototype.slice.call(arguments).sort();

}

// rest參數的寫法

const sortNumbers = (...numbers) => numbers.sort();

上面是rest參數代替arguments變量的例子。比較後可發現,rest參數的寫法更自然更簡潔。

arguments對象不是數組,是類似數組的對象,為使用數組方法,需先將其轉為數組。Rest參數就不存在這個問題,它自身就是數組。

// arguments變量的寫法

function sortNumbers() {

    return Array.prototype.slice.call(arguments).sort();

}

// rest參數的寫法

const sortNumbers = (...numbers) => numbers.sort();

上面是利用rest參數改寫數組push方法的例子。

需註意。Rest參數之後不能再有其他參數,即只能是最後一個參數,否則報錯。

函數的length屬性返回沒有默認值的參數的個數,其中不包括rest參數。

(function (a) { }).length  // 1

(function (...a) { }).length  // 0

(function (a, ...b) { }).length  // 1

7、對象的擴展

(1)Es6中可以直接寫入變量和函數,作為對象的屬性和方法,使書寫更簡潔。

const foo = ‘bar‘;

const baz = { foo };

baz // {foo: "bar"}

// 等同於

const baz = { foo: foo };

此時,屬性名為變量名,屬性的值為變量的值。

function f(x, y) {

    return { x, y };

}

// 等同於

function f(x, y) {

    return { x: x, y: y

    };

}

 

f(1, 2) // Object {x: 1, y: 2}

方法也可以簡寫。

在一個模塊對外提供接口時非常適合使用簡潔寫法。

const getName = () => person.name;

const getAge = () => person.age;

commons的寫法:

module.exports = {

    getName: getName,

    getAge: getAge,

};

Es6 modules的寫法:

export default {

    getName,

    getAge

};

(2)若自適應字面量方法定義對象(使用大括號),es5中只能像下面這樣定義屬性:

var obj = {

    foo: true,

    abc: 123

};

在es6中,就可以把表達式放在方括號內定義對象:

let propKey = ‘foo‘;

let obj = {

    [propKey]: true,

    [‘a‘ + ‘bc‘]: 123

};

8、class

生成實例對象的傳統方法使通過構造函數,與傳統的面向對象語言差異很大,es6引入class類這個概念,通過class關鍵字可以定義類。Es6的class可以看作是一個語法糖,它的絕大部分功能,es5都可以做到,class寫法只是讓對象的寫法更清晰。

es5生成實例對象:

function Person(name, age) {

    this.name = name;

    this.age = age;

}

Person.prototype.getName = function () {

    return this.name;

}

var person = new Person(‘abc‘, 21);

es6用class改寫

class Person {

    constructor(name, age) {

        this.name = name;

        this.age = age;

    }

 

    getName() {

        return this.name

    }

}

var person = new Person(‘abc‘, 21);

constructor是構造方法,this代表實例對象,es5的構造函數Person,對應的就是Person類的構造方法,定義類方法使不需要function關鍵字,直接把函數定義放進去,另外方法之間也不需要逗號分隔。

typeof Person // "function"

Person === Person.prototype.constructor // true

上面表明,類的數據類型就是函數,類本身事項構造函數。

class Person {

    constructor() {

        // ...

    }

    getName() {

        // ...

    }

 

}

// 等同於

Person.prototype = {

    constructor() {},

    getName() {}

};

類的所有方法都定義在類的prototype屬性上。因此,類的新方法可以添加在prototype對象上。而Object.assign方法可以仿版地一次想類添加多個方法。

Object.assign(Person.prototype, {

    getNmae() {},

    getAge() {}

});

9、class的繼承

1)Es6中,class可以通過extends關鍵字實現繼承,比起es5的通過修改原型鏈實現繼承方便的多。

class Person {

    constructor(name, age) {

        this.name = name;

        this.age = age;

    }

 

    getName() {

        return this.name

    }

}

// Student類繼承Person類

class Student extends Person {

    constructor(name, age, gender, classes) {

        super(name, age);

        this.gender = gender;

        this.classes = classes;

    }

 

    getGender() {

        return this.gender;

    }

}

不用像es5那樣需要考慮構造函數繼承哈斯原型繼承,只需要使用extends關鍵字並關註一個叫super的方法。

如果不使用super方法,在新建實例時就會報錯。

Es5的繼承,實質是縣創造子類實例對象的this,在將父類的方法添加到this(Parent.apply(this))。 而es6的繼承機制完全不同,實質是先創造父類的實例對象this(所以必須先調用super方法),然後再用子類構造函數修改this。

如果子類沒有定義constructor(),也會被默認添加。即任何一個子類都有constructor方法。

class Student extends Person {}

 

// 等同於

class Student extends Person {

    constructor(...args) {

        super(...args);

    }

}

需要註意,只有調用super以後才能使用this,否則報錯。因為上面說過,子類實例的構建,是基於父類實例加工,super方法返回父類實例。

1) super關鍵字既可以當作函數使用也可以當作對象使用。

·Super作為函數調用時,代表父類的構造函數,子類的構造數必須執行一次super函數。

class A {}

 

class B extends A {

    constructor() {

        super();

    }

}

Super雖然代表了父類A的工業早函數,但返回的是子類B的實例,即super內部的this指的是B,因此super在這裏相當於A.prototype.constructor.call(this)。

class A {

    constructor() {

        console.log(new.target.name);

    }

}

class B extends A {

    constructor() {

        super();

    }

}

new A() // A

new B() // B

new.target指向當前正在執行的函數。從上面的代碼可以看出:在super執行時,它指向的是子類B的構造函數,即super內部的this指向B

並且,作為函數是,super只能用在子類的構造函數之中,否則報錯。

·第二種情況,super作為對象。在普通方法中,指向父類的原型對象;在靜態方法中,指向父類。

class A {

    p() {

        return 2;

    }

}

 

class B extends A {

    constructor() {

        super();

        console.log(super.p()); // 2

    }

}

 

let b = new B();

上面代碼中,子類B的super.p就是把super當做對象使用,此時super在普通方法中,指向A.prototype,因此super.p()就相當於A.prototype.p()。

註意:定義在父類實例上的方法、屬性無法通過super調用。

class A {

    constructor() {

        this.x = 1;

    }

    print() {

        console.log(this.x);

    }

}

 

class B extends A {

    constructor() {

        super();

        this.x = 2;

    }

    m() {

        super.print();

    }

}

 

let b = new B();

b.m() // 2

super.print()雖然調用的是A.prototype.print(),但A.prototype.print()內部的this指向子類B,因此輸出2,而不是1。實際上執行的是super.print.call(this)。

如果super作為對象,用在靜態方法中,super就指向父類,而不是父類的原型對象。

class Parent {

    static myMethod(msg) {

        console.log(‘static‘, msg);

    }

 

    myMethod(msg) {

        console.log(‘instance‘, msg);

    }

}

 

class Child extends Parent {

    static myMethod(msg) {

        super.myMethod(msg);

    }

 

    myMethod(msg) {

        super.myMethod(msg);

    }

}

 

Child.myMethod(1); // static 1

 

var child = new Child();

child.myMethod(2); // instance 2

上面的代碼,super在靜態方法中指向父類,在普通方法中指向父類的原型對象。

10、promise(項目中ajax.js中使用)

promise的作用與回調方法(callback)一樣,都是在某種情況下執行設定好的方法。但promise的多重鏈式調用能使代碼更整潔,避免出現“回調地獄”(回調嵌套太多層)。在es6中,promise成為了原生對象可以直接使用。

Ajax請求的傳統寫法:

技術分享圖片

改為promise寫法:

技術分享圖片

很顯然,promise的寫法把異步調用中使用回調函數的場景改為了.then()、.catch()等函數鏈式調用的方式,基於promise可以把復雜的異步調用方式進行模塊化。

Promise的原理分析:

Promise對象共有三個狀態,分別是:

·pending(進行中)

·resolved(已完成,又稱為fullfilled)

·rejected(已失敗)

由異步操作的結果決定當前是什麽狀態。狀態的改變只有兩種可能:

·從pending變為fullfilled

·從pending變為rejected

只要這兩種情況發生,狀態就不會再改變了,因此狀態是不能逆向改變的。

構建promise:

技術分享圖片

Promise的構造函數接受一個函數作為參數,該函數的兩個參數分別為resolve和reject兩個函數。

·Resolve函數將promise對象的狀態由pending變為resolved,異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去。

·reject函數將狀態由pending變為rejected,異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去。

Promise的實例方法:

Promise對象擁有兩個實例方法then()和catch()。

·then()方法接受兩個函數作為參數,第一個是狀態變為resolved時調用,第二個則是狀態變為rejected是調用,第二個函數是可選的。

Promise實例生成以後,可以用then方法指定resolved狀態和rejected狀態的回調函數,即成功和失敗的回調函數。

promise構造函數中通常都是異步的,所以then方法往往都先於resolvereject方法執行。這兩個函數作為成功和失敗的回調函數,都接受promise對象傳出的值作為參數。

技術分享圖片

技術分享圖片

then()方法將返回一個新的promise。

因此then可以鏈式調用,在新的對象上添加失敗或成功的回調。

·catch()方法的作用是捕獲promise的錯誤。

與then()方法的rejected回調作業幾乎一致。

我們知道,如果 Promise 狀態已經變成resolved,再拋出錯誤是無效的。

技術分享圖片

上面代碼中,Promise 在resolve語句後面,再拋出錯誤,不會被捕獲,等於沒有拋出。因為 Promise 的狀態一旦改變,就永久保持該狀態,不會再變了。

技術分享圖片

promise對象的錯誤會一直向後傳遞,直到被捕獲,即錯誤總會被下一個catch所捕獲。then方法指定的回調函數,若拋出錯誤,也會被下一個catch捕獲。catch中也能拋錯,則需要後面的catch來捕獲。

因此一般來說,不要在then方法裏面定義 Reject 狀態的回調函數(即then的第二個參數),總是使用catch方法。

這樣就能夠在下一個catch()中統一處理這些錯誤。同時catch()也能夠捕獲then()中拋出的錯誤,所以建議不使用then()的rejected回調,而是統一使用catch()來處理錯誤。

跟傳統的try/catch代碼塊不同的是,如果沒有使用catch方法指定錯誤處理的回調函數,Promise 對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應。Promise 內部的錯誤不會影響到 Promise 外部的代碼。

11、Module(項目中常用)

ES6實現了模塊功能,可以取代CommonJS和AMD規範,稱為瀏覽器和服務器通用的模塊解決方案。

模塊功能主要由兩個命令構成:export和import。

Export用於規定模塊的對外接口,import用於輸入其他模塊提供的功能。

一個模塊即一個獨立文件。該文件內部的所有變量,在外部是無法獲取的。如果需要讀取模塊內的某個變量,就必須使用export輸出該變量。

(1)export

export可以輸出變量:

// 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 };

除了輸出變量,還可以輸出函數或class類

export function multiply(x, y) {

    return x * y;

};

(2)import

使用export定義了,模塊對外的幾口以後,其他js文件就可以通過import加載這個模塊。

// main.js

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

 

function setName(element) {

    element.textContent = firstName + ‘ ‘ + lastName;

}

Import接收一堆大括號,裏面指定要從其他模塊導入的變量名,變量名必須與被導入模塊(profile.js)對外接口的名稱相同。

Import輸入的變量都是只讀的,不允許在加載模塊的腳本裏改寫接口。

From指定模塊文件的位置,.js後綴可以省略。

Import具有提升效果,會提升到整個模塊的頭部首先執行。

(3)export default

使用export default為模塊指定默認輸出。

// export-default.js

export default function () {

    console.log(‘foo‘);

}

默認輸出一個匿名函數

// import-default.js

import customName from ‘./export-default‘;

customName(); // ‘foo‘

加載該模塊時,import為函數指定名字。

需要註意的是export default對應的import不需要使用大括號{}。而export對應的import需要使用大括號。

es6 學習心得