ES6+ 特性整理

ES6新特性

let關(guān)鍵字

控制作用域在塊級(jí)作用域下的定義關(guān)鍵字伍绳,并且不允許重復(fù)聲明搭伤,舉例:

for(var i = 0; i < 10; i++) {}
console.log(i);
// 輸出10
for(let j = 0; j < 10; j++) {}
console.log(j);
// j未定義只怎,報(bào)錯(cuò)(let定義的變量出了其所在代碼塊就銷(xiāo)毀)

注:
在沒(méi)有let關(guān)鍵字之前,只用用var定義變量怜俐,但由于其作用域在函數(shù)級(jí)別身堡,因此存在很多問(wèn)題,例如下面希望實(shí)現(xiàn)多個(gè)按鈕拍鲤,點(diǎn)擊輸出對(duì)應(yīng)的索引:

<body>
    <button>a</button>
    <button>b</button>
    <button>c</button>
</body>
<script>
btns = document.getElementsByTagName('button');
for (var i = 0; i < btns.length; i++) {
    // 使用var定義
    btns[i].onclick = function() {
        console.log(i);
    }
}
</script>

結(jié)果發(fā)現(xiàn)不管點(diǎn)擊哪個(gè)按鈕贴谎,輸出的都是3,原因就是var定義的變量i作用域在函數(shù)擅这,因此這里的i對(duì)于3個(gè)按鈕來(lái)說(shuō)是共用的,而這個(gè)i經(jīng)過(guò)循環(huán)變成了3鲫构,所以無(wú)論哪個(gè)按鈕湿镀,獲得到的i都是3算途。為了解決上述問(wèn)題,在ES6前提出了閉包的解決方案:

<body>
    <button>a</button>
    <button>b</button>
    <button>c</button>
</body>
<script>
    btns = document.getElementsByTagName('button');
    for (var i = 0; i < btns.length; i++) {
        // 通過(guò)閉包廓脆,即把i傳入到一個(gè)函數(shù)內(nèi)部停忿,避免變量被覆蓋
        (function(i) {
            btns[i].onclick = function() {
                console.log(i);
            }
        })(i);
    }
</script>

但是這樣需要多定義一個(gè)函數(shù),代碼上也顯得冗余颅停,因此ES6以后塊級(jí)作用域的let關(guān)鍵字完美的解決了這個(gè)問(wèn)題:

<body>
    <button>a</button>
    <button>b</button>
    <button>c</button>
</body>
<script>
btns = document.getElementsByTagName('button');
for (let i = 0; i < btns.length; i++) {
    // 使用let定義塊級(jí)作用域變量溺欧,此時(shí)相當(dāng)于在3個(gè)代碼塊里分別let i = 0/1/2芥牌,三個(gè)i都在自己的作用域下,互相不會(huì)沖突
    btns[i].onclick = function() {
        console.log(i);
    }
}
</script>

注2:
關(guān)于let是否存在變量提升問(wèn)題可以參考(事實(shí)上是存在的):https://blog.csdn.net/weixin_40169665/article/details/83819825

const關(guān)鍵字

定義常量宿礁,被定義的常量無(wú)法被更改梆靖,但是要注意定義常量的時(shí)候必須為其初始化,以及其作用域和let一樣只在自己的代碼塊內(nèi)起作用返吻,并且也不可重復(fù)聲明。實(shí)際上const相當(dāng)于一個(gè)不能被更改指向的指針街佑,但是如果指向的是對(duì)象這樣的數(shù)據(jù),那么對(duì)象的內(nèi)容是允許更改的捍靠,比如下面的操作是允許的:

const a = {name:1}
// 常量a指向一個(gè)對(duì)象
a["name"] = 2
// 修改對(duì)象的值允許
// const a = {name:1}
// 常量重新指向一個(gè)對(duì)象榨婆,此時(shí)不允許
數(shù)組解構(gòu)賦值

允許將數(shù)組的值分別賦值給多個(gè)變量烟央,舉例:

[x, y] = [1, 2]
// 此時(shí)x=1,y=2
[x, y] = [1, 2, 3, 4]
// 此時(shí)只有1和2被賦值給x和y,和上面的等價(jià)
[x, y, z] = [1, 2]
// z沒(méi)有被賦值怠硼,為undefined

對(duì)于數(shù)組當(dāng)中不希望賦值的數(shù)據(jù)鬼贱,可以用逗號(hào)間空開(kāi),舉例:

[a, , c] = [1, 2, 3]
// 此時(shí)a=1香璃,c=3这难,而2沒(méi)有賦值給任何一個(gè)數(shù)

如果希望把數(shù)組剩余的部分都賦值給某個(gè)變量,可以用...變量名實(shí)現(xiàn)葡秒,舉例:

[a, ...c] = [1, 2, 3]
// 此時(shí)a=1姻乓,c=[2, 3]嵌溢,要注意...開(kāi)頭的變量必須放在最后

如果擔(dān)心數(shù)組的內(nèi)容不夠賦值給變量,還可以給變量設(shè)置默認(rèn)值蹋岩,舉例:

[a, b, c, d] = [1, 2, 3]
// 此時(shí)d沒(méi)有被賦值赖草,結(jié)果為undefined
[a, b, c, d=4] = [1, 2, 3]
// d設(shè)置了默認(rèn)值為4

對(duì)于字符串也可以當(dāng)做數(shù)組來(lái)解構(gòu),舉例:

[a, b, c] = 'xyz'
// a='x'剪个,...

這種解構(gòu)在函數(shù)傳參時(shí)也很實(shí)用秧骑,舉例:

function test([a, b, ...c]){
    console.log(a + b, c);
}
test([1,2,3,4,5])
// 3, [3, 4, 5]
對(duì)象解構(gòu)賦值

對(duì)象的解構(gòu)賦值基于屬性名,舉例:

{a, b, c} = {a:1, b:2}
// a為1扣囊,b為2乎折,c沒(méi)有被賦值,為undefined

如果希望屬性賦值給變量名不同的變量侵歇,則看下面示例:

{a:A, b} = {a:1, b:2}
// 此時(shí)a的屬性賦值給變量A骂澄,所以變量a為未定義,A為1惕虑,b為2

由于對(duì)象解構(gòu)時(shí)是使用{}包起來(lái)的坟冲,因此會(huì)被解析成代碼塊,此時(shí)就可能出現(xiàn)作用域沖突問(wèn)題枷遂,可以在外面包一層括號(hào)解決樱衷,舉例:

let x = 0;
({x} = {x:1})

對(duì)于多級(jí)對(duì)象的解構(gòu)示例如下:

{people: [{name}, age]} = {people:[{name:"aaa"}, 18]}
// 此時(shí)name為aaa,age為18

對(duì)象解構(gòu)的默認(rèn)值設(shè)置和數(shù)組的同理酒唉,舉例:

{x=0,y=0} = {x:1}
// 此時(shí)x為1矩桂,y為0

還有些用法如提取對(duì)象中的方法成變量調(diào)用,舉例:

let {floor} = Math;
// 將Math下的floor方法提取成變量
floor(1.5)
// 調(diào)用floor方法
let {length:s_length} = 'hello';
// 將字符串長(zhǎng)度屬性提取出來(lái)
s_length
// 輸出字符串長(zhǎng)度

對(duì)象解構(gòu)同樣可以用于函數(shù)傳參痪伦,且更方便侄榴,避免了傳遞順序等問(wèn)題,舉例:

function test({a, b}){
    console.log(a + b);
}
test({a:1, b:2})

注:
這里順便介紹一些對(duì)象的基本用法网沾,比如直接定義函數(shù)癞蚕,舉例:

x = {a:1, b(){return 2;}, c(){console.log(3);}}
// {a: 1, b: ?, c: ?}
x.b()
// 2
x.c()
// 3

直接傳入已賦值的變量或常量,舉例:

let x = 1
const y = 2
z = {x, y}
// 將變量或常量傳入對(duì)象辉哥,此時(shí)z為:{x: 1, y: 2}
z.y = 3
// 但傳入以后都會(huì)變成變量桦山,所以z里的y可以修改
z
// {x: 2, y: 3}

設(shè)置默認(rèn)值,舉例:

function test({
    x = 100,
    y = 200
}) {
    console.log(x, y);
}

test({x: 500, y: 200});
// 500 200
數(shù)組展開(kāi)

通過(guò)...可以將數(shù)組展開(kāi)傳入醋旦,舉例:

function test(a, b, c) {
    console.log(a + b + c);
}
test(...[1, 2, 3])
// 將數(shù)組展開(kāi)成1, 2, 3賦值給a, b, c

數(shù)組展開(kāi)還可以用于數(shù)組拼接恒水,舉例:

a = [1,2,3]
b = [4,5,6]
[...a, ...b]
// [1, 2, 3, 4, 5, 6]

實(shí)際上數(shù)組展開(kāi)就是把數(shù)組當(dāng)中的一個(gè)個(gè)數(shù)據(jù)通過(guò)類(lèi)似迭代器那樣給分離出來(lái),因此需要給一個(gè)數(shù)據(jù)類(lèi)型來(lái)存放所有分離出來(lái)的數(shù)據(jù)饲齐,舉例:

a = [1,2,3]
...a
// 報(bào)錯(cuò):VM323:1 Uncaught SyntaxError: Unexpected token ...钉凌,因?yàn)榉蛛x出來(lái)的數(shù)據(jù)沒(méi)有東西存放
[...a]
// 通過(guò)數(shù)組存放a中分離出來(lái)的數(shù)據(jù),結(jié)果為[1, 2, 3]
對(duì)象展開(kāi)

和數(shù)組類(lèi)似捂人,對(duì)象也能夠通過(guò)...展開(kāi)御雕,同時(shí)也需要數(shù)據(jù)類(lèi)型來(lái)存放這個(gè)展開(kāi)后的所有數(shù)據(jù)矢沿,舉例:

a = {name: 111, pwd: 222}
{...a, b:1}
// 通過(guò)對(duì)象{b: 1}存放...a,結(jié)果為:{name: 111, pwd: 222, b: 1}
字符串新增方法
includes方法

判斷字符串是否存在于其中酸纲,舉例:

"abc".includes('a')
// true
"abc".includes('d')
// false

注:
該方法對(duì)數(shù)組同樣適用捣鲸,舉例:

[1,2,3].includes(1)
// true
startsWith方法

判斷字符串是否以其開(kāi)頭,舉例:

"abc".startsWith('a')
// true
"abc".startsWith('b')
// false
endsWith方法

判斷字符串是否以其結(jié)尾

repeat方法

將字符串復(fù)制成原來(lái)的幾倍闽坡,舉例:

"abc".repeat(3)
// "abcabcabc"
數(shù)組新增方法
map方法

對(duì)數(shù)組數(shù)據(jù)進(jìn)行統(tǒng)一操作摄狱,舉例:

a = [1,2,3,4,5]
a.map(function(item){return item>=3})
// 統(tǒng)一操作判斷每個(gè)數(shù)據(jù)是否大于等于3,[false, false, true, true, true]
// 由于上面的函數(shù)符合一個(gè)參數(shù)无午,且只有一條return語(yǔ)句,因此可以簡(jiǎn)寫(xiě)如下:
// 簡(jiǎn)寫(xiě)后:a.map(item=>item>=3)
// 這里容易看混掉的是第一個(gè)=>是代表箭頭函數(shù)祝谚,第二個(gè)=>代表大于等于運(yùn)算符

注:
map方法里其實(shí)還有第二個(gè)參數(shù)宪迟,為數(shù)據(jù)索引,舉例:

a = [1,2,3,4,5]
a.map(function(item, index){return [item, index]})
// [[1,0],[2,1],[3,2],[4,3],[5,4]]
reduce方法

對(duì)整個(gè)數(shù)組進(jìn)行循環(huán)某運(yùn)算交惯,其下有三個(gè)參數(shù)為:tmp/item/index次泽,分別代表上一次操作返回的結(jié)果(第一次默認(rèn)為數(shù)組的第一個(gè)數(shù))、下一個(gè)傳入的值(即數(shù)據(jù)的下一個(gè)數(shù))席爽、循環(huán)的索引意荤,舉例:

a = [1,2,3,4,5]
a.reduce(function(tmp, item, index) {
    console.log(tmp, item);
    return tmp + item;
    // 返回結(jié)果為當(dāng)前數(shù)和下一個(gè)數(shù)的求和
})
// 最后的結(jié)果為15
filter方法

根據(jù)條件過(guò)濾數(shù)據(jù),舉例:

a = [1,2,3,4,5]
a.filter(item => item%2==0)
// 返回所有偶數(shù)只锻,結(jié)果為[2, 4]
forEach方法

遍歷數(shù)組玖像,舉例:

a = [1,2,3,4,5]
a.forEach((item, index) => {console.log(item, index)})
// 循環(huán)輸出:1 0、2 1齐饮、...
some方法

循環(huán)判斷數(shù)組中是否存在滿(mǎn)足條件的數(shù)據(jù)捐寥,只要有一個(gè)滿(mǎn)足就返回true,舉例:

a = [1,2,3,4,5]
a.some(item=>item>=3)
// 有大于等于3的數(shù)祖驱,返回true
every方法

some方法類(lèi)似握恳,循環(huán)判斷數(shù)組中是否全部滿(mǎn)足條件,是則返回true捺僻,舉例:

a = [1,2,3,4,5]
a.every(item=>item>=3)
// 有不大于等于3的數(shù)乡洼,返回false
對(duì)象新增方法
Object.keys()

會(huì)將對(duì)象的所有鍵以數(shù)組形式輸出,舉例:

o = {a:1, b:2, c:3}
Object.keys(o)
// ["a", "b", "c"]
Object.values()

會(huì)將對(duì)象的所有值以數(shù)組形式輸出

Object.entries()

會(huì)將對(duì)象的所有鍵和值以數(shù)組形式輸出匕坯,數(shù)組中的子元素是長(zhǎng)為2的數(shù)字束昵,分別為鍵和值,舉例:

o = {a:1, b:2, c:3}
Object.entries(o)
// [Array(2), Array(2), Array(2)]
Object.entries(o)[0]
// ["a", 1]
模板字符串

原來(lái)的字符串要拼接值都是通過(guò)多個(gè)+號(hào)實(shí)現(xiàn)醒颖,而通過(guò)反引號(hào)包起來(lái)的模板字符串則可以通過(guò)${value}傳值妻怎,舉例:

x = 2
`1${x}3`
// 123

模板字符串還可以嵌套,舉例:

`1${x+`${y}`}3`
// 1203
標(biāo)簽?zāi)0?/h5>

在定義模板字符串時(shí)泞歉,可以使用標(biāo)簽?zāi)0鍖?duì)其進(jìn)行一些操作逼侦,舉例:

function toLower(strings, ...params) {
    // 傳入第一個(gè)參數(shù)為模板字符串中的靜態(tài)字符匿辩,params接收多個(gè)傳入的變量
    console.log(strings, params);
    let s = "";
    strings.forEach((item, index) => {
        if (index >= params.length) return;
        s += item + params[index].toLowerCase();
    })
    s += strings.slice(-1);
    return s;
}

let name = "Aaa";
let result = toLower`My name is ${name}.`;
console.log(result);
// [ 'My name is ', '.' ] [ 'Aaa' ]
// My name is aaa.

參考:http://www.reibang.com/p/c65b9930dd11

Symbol數(shù)據(jù)類(lèi)型

生成一個(gè)每次都不同的隨機(jī)變量,一般用于防止對(duì)象屬性被修改榛丢,舉例:

a = Symbol()
b = Symbol()
a == b
// false
c = {}
c[a] = 1
c[b] = 2
c
// {Symbol(): 1, Symbol(): 2}铲球,可以看出a的值沒(méi)有被b給覆蓋
Set類(lèi)型

集合,舉例:

s = new Set([1,2,3,3])
// Set(3) {1, 2, 3}晰赞,可以看出結(jié)果為3個(gè)
s.size
// 3稼病,相當(dāng)于length
s.add(4)
// Set(4) {1, 2, 3, 4},添加了4進(jìn)去
s.delete(5)
// false掖鱼,沒(méi)有5然走,刪除失敗
s.delete(3)
// true,刪除成功
s.has(2)
// true戏挡,存在2
s.clear()
// 清空集合
迭代器

可以惰性加載數(shù)據(jù)芍瑞,并且每個(gè)數(shù)據(jù)只能加載一次,不能回退

自定義迭代器實(shí)現(xiàn)
function createIterator(arr) {
  let i = 0;
  let done = false;
  return {
    next() {
      if (i === arr.length) done = true;
      return {value: arr[i++], done};
    }
  }
}

let iterator = createIterator([1,2,3]);
while ((item = iterator.next()) && (!item.done)) {
  console.log(item);
}

// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
通過(guò)Symbol實(shí)現(xiàn)迭代器
let arr = [1, 2, 3];
let createIterator = arr[Symbol.iterator];
// 創(chuàng)建迭代器函數(shù)
let iterator = createIterator.call(arr);
// 綁定迭代器數(shù)據(jù)
while ((item = iterator.next()) && !item.done) {
  console.log(item);
}

// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
生成器

在函數(shù)名前加符號(hào)*褐墅,并且通過(guò)yield關(guān)鍵字返回值拆檬,通過(guò)next方法獲取下一個(gè)的值,舉例:

function *gen() {
  yield 1
  yield 2
  yield 3
  return 100
}

let g = gen();
console.log(g.next());
console.log(g.next());
console.log(g.next());
console.log(g.next());
console.log(g.next());

// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: 100, done: true }
// { value: undefined, done: true }
生成器特性

生成器相當(dāng)于可以暫停的函數(shù)妥凳,因此我們可以在函數(shù)上一次返回的地方繼續(xù)執(zhí)行竟贯,舉例:

// 無(wú)限生成的遞增數(shù)字
function *gen() {
  let i = 0;
  while (true) {
    yield i++;
  }
}

let g = gen();
console.log(g.next());
console.log(g.next());
console.log(g.next());
console.log(g.next());
console.log(g.next());

// { value: 0, done: false }
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: 4, done: false }
函數(shù)參數(shù)默認(rèn)值

函數(shù)支持給參數(shù)設(shè)置默認(rèn)值,舉例:

function test(x, y=1){
  return x + y;
}
test(1);
// 2
test(1, 2);
// 3
常量函數(shù)命名

可以通過(guò)定義一個(gè)常量而不用function關(guān)鍵字來(lái)命令一個(gè)函數(shù)逝钥,舉例:

const FUN = "test";
// 定義一個(gè)常量FUN屑那,值為test
funs = {
    [FUN] (x, y) {
        return x + y; 
    } 
}
// 定義以后,可以發(fā)現(xiàn)funs為:{test: ?}艘款,即定義了一個(gè)名為test的函數(shù)
funs.test(1, 2)
// 3

不過(guò)本人嘗試以后發(fā)現(xiàn)貌似不用常量齐莲,用字符串也可以這樣定義(常量傳進(jìn)對(duì)象本身也都不是常量了)

箭頭函數(shù)

能夠?qū)崿F(xiàn)對(duì)函數(shù)的簡(jiǎn)寫(xiě),舉例:

function(x, y) {
    ...
}
// 上面的原來(lái)函數(shù)的寫(xiě)法
(x, y) => { ... }
// 通過(guò)箭頭函數(shù)可以簡(jiǎn)寫(xiě)并替代上面的寫(xiě)法

其中使用箭頭函數(shù)有以下注意事項(xiàng):

  • 當(dāng)參數(shù)只有一個(gè)時(shí)磷箕,可以省略()选酗,舉例:
function(data) {
    console.log(data);
}
// 只有一個(gè)參數(shù)
data => {console.log(data);}
// 省略了括號(hào)
  • 如果函數(shù)里只有一個(gè)return語(yǔ)句,那么可以不用加{}岳枷,并且可以省略return關(guān)鍵字芒填,舉例:
function(x, y) {
    return x + y;
}
// 只有一個(gè)return語(yǔ)句
(x, y) => x + y;
// 省略了花括號(hào)和return關(guān)鍵字

注:
通過(guò)箭頭函數(shù)還能夠綁定this,使得this一直為當(dāng)前的環(huán)境而不會(huì)被變更空繁,舉例:

a = {
    name: "aaa",
    fn: function() {
        console.log(this, this.name + "bbb")
        // 使用function定義的this會(huì)綁定到當(dāng)前對(duì)象殿衰,因此輸出為當(dāng)前對(duì)象a和"aaabbb"
    },
    fn1: () => {
        console.log(this, this.name + "bbb")
        // 箭頭函數(shù)使得this綁定在window對(duì)象,因此輸出為window對(duì)象和"bbb"
    }
}
a.fn()
a.fn1()
JSON操作
對(duì)象轉(zhuǎn)json

通過(guò)JSON對(duì)象的stringify方法實(shí)現(xiàn)盛泡,舉例:

JSON.stringify({a:1, b:2})
// "{"a":1,"b":2}"
json轉(zhuǎn)對(duì)象

通過(guò)JSON對(duì)象的parse方法實(shí)現(xiàn)闷祥,舉例:

JSON.parse('{"a":1,"b":2}')
// {a: 1, b: 2}
面向?qū)ο?/h5>

ES6之前JS的面向?qū)ο笫且粋€(gè)偽面向?qū)ο螅嬖谥S多問(wèn)題傲诵,比如用function關(guān)鍵字定義類(lèi)凯砍,以至于不知道是函數(shù)還是類(lèi)箱硕、添加方法方式限制不嚴(yán),導(dǎo)致代碼編寫(xiě)可能不統(tǒng)一等等一系列問(wèn)題悟衩。因此在ES6中提供了幾個(gè)面向?qū)ο蟮年P(guān)鍵字統(tǒng)一了JS的面向?qū)ο缶幊叹缯郑ǎ?code>class(定義類(lèi))、constructor(構(gòu)造器)座泳、extends(繼承)惠昔、super(父類(lèi)),static(定義靜態(tài)屬性/方法)舉例:

class User {
    constructor(name, pwd) {
        // 構(gòu)造方法
        this.name = name;
        this.pwd = pwd;
    }
    showName() {
        // 直接輸入方法名定義方法
        console.log(this.name);
    }
    static showRule() {
        // 定義靜態(tài)方法挑势,可以從類(lèi)直接調(diào)用而無(wú)需實(shí)例化
        console.log("this is User rule");
    }
    static rule = "this is rule";
    // 定義靜態(tài)屬性镇防,如果報(bào)錯(cuò)可能是瀏覽器版本不支持,建議換成最新chrome嘗試
}
class Vip extends User {
    // 繼承父類(lèi)
    constructor(name, pwd, level) {
        super(name, pwd);
        // 調(diào)用父類(lèi)構(gòu)造方法
        this.level = level;
    }
    showPwd() {
        console.log(this.pwd);
    }
    showLevel() {
        console.log(this.level);
    }
}
console.log(User.rule);
User.showRule();
// 直接從類(lèi)調(diào)用靜態(tài)方法
let user = new Vip("aaa", "111", "1");
user.showName();
user.showPwd();
user.showLevel();
類(lèi)表達(dá)式
  • 我們可以通過(guò)類(lèi)表達(dá)式來(lái)定義匿名類(lèi)潮饱,舉例:
const test = class Test {
    constructor() {
        console.log("init test");
    }
}

new test();
  • 類(lèi)表達(dá)式可以省略類(lèi)名:
const test = class {
    constructor() {
        console.log("init test");
    }
}

new test();
  • 可以通過(guò)該方式創(chuàng)建內(nèi)部類(lèi):
class Base {}

function Factory(cls) {
    return class extends Base {
        test() {
            console.log(cls);
        }
    }
}

const cls = Factory("test")
const instance = new cls();
instance.test();
fetch

fetch是一個(gè)新提供的網(wǎng)絡(luò)請(qǐng)求api营罢,在fetch出來(lái)之前,異步請(qǐng)求主要還是用ajaxaxiosaxios相當(dāng)于結(jié)合ajaxpromise后再封裝了一層)饼齿。fetch也是基于promise管理(因此可以像promise對(duì)象那樣處理),并且是JS原生的內(nèi)置類(lèi)蝙搔,所以可以直接使用缕溉,而無(wú)需像ajaxaxios那樣還需要先導(dǎo)入一個(gè)庫(kù)。并且fetch底層不是基于XMLHttpRequest實(shí)現(xiàn)的吃型,官方的意思是用了一種更好的方案實(shí)現(xiàn)证鸥,不過(guò)fetch不支持老版本IE,并且fetch和原來(lái)的ajax勤晚、axios不一樣枉层,他只要有服務(wù)端返回就算訪問(wèn)成功(別的會(huì)根據(jù)狀態(tài)碼等來(lái)判斷),因此只有網(wǎng)絡(luò)連接失敗時(shí)才算是訪問(wèn)失敗赐写。

使用

fetch的使用十分簡(jiǎn)單鸟蜡,只需要配置第一個(gè)參數(shù)url,以及第二個(gè)可選參數(shù)(請(qǐng)求的配置和傳輸?shù)臄?shù)據(jù)對(duì)象等)挺邀,使用舉例:

fetch("http://jsonplaceholder.typicode.com/users").then(res => res.json()).then(json => {console.log(json)})
// 向該網(wǎng)址發(fā)送請(qǐng)求,并且第二個(gè)參數(shù)不傳默認(rèn)為get請(qǐng)求端铛。
fetch("http://xxx", {
  method: "post",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({'name': 'aaa'})
})
  .then(res => res.json())
  .then(json => {
    console.log(json);
  });
// 指定發(fā)送的數(shù)據(jù)格式和內(nèi)容等

更多參考:
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
https://blog.csdn.net/qq_36754767/article/details/89645041

模塊化
使用步驟

1.通過(guò)export導(dǎo)出成員
2.在另一個(gè)文件當(dāng)中通過(guò)import接收成員
3.引用通過(guò)webpack編譯后生成的bundle.js文件
舉例:

  • a.js
export let a = { name: "aaa" };
export const b = 111;
// 導(dǎo)出成員a和b
  • b.js
import * as a from './a'
// 導(dǎo)入a.js里的所有成員泣矛,注意相對(duì)路徑需要加`./`這樣的定位符
console.log(a.a, a.b);
// 輸出導(dǎo)入的成員
  • webpack.config.js
module.exports = {
    mode: 'development',
    entry: './b.js',
    output: {
        filename: 'bundle.js',
        path: __dirname + '/build'
    }
}

導(dǎo)入webpack生成的文件后可以發(fā)現(xiàn)輸出了ab的值。
注:
注意相對(duì)路徑需要加./這樣的定位符禾蚕,因?yàn)槟K化需要在node環(huán)境下使用您朽,如果不加定位符,則默認(rèn)去依賴(lài)模塊當(dāng)中尋找换淆,而不會(huì)去相對(duì)路徑下找

默認(rèn)成員default

在模塊化當(dāng)中還可以導(dǎo)出默認(rèn)成員default哗总,則通過(guò)導(dǎo)入模塊成功語(yǔ)法時(shí)几颜,只導(dǎo)入默認(rèn)成員default的值,舉例:

  • a.js
export default "aaa";
// 導(dǎo)出默認(rèn)成員"aaa"
  • b.js
import a from './a'
// 導(dǎo)入默認(rèn)成員default魂奥,并命名為a菠剩,相當(dāng)于下面這個(gè)意思
// import default as a from './a'

console.log(a);

這種語(yǔ)法在vue的組件化工程當(dāng)中很常見(jiàn)

導(dǎo)入成員語(yǔ)法

前面介紹了兩種語(yǔ)法,一種是導(dǎo)入全部:

import * as xxx from './xxx'

還有導(dǎo)入默認(rèn)默認(rèn)成員語(yǔ)法:

import xxx from './xxx'

如果希望導(dǎo)入指定的成員也可以:

import {xxx, yyy as zzz} from './xxx'
// 導(dǎo)入./xxx文件里的xxx和yyy成員耻煤,并將yyy改名為zzz

還有導(dǎo)入如CSS文件具壮、圖片文件等模塊時(shí)(在模塊化開(kāi)發(fā)下一些靜態(tài)文件都稱(chēng)為模塊),因?yàn)檫@些文件里可能不存在成員啥的哈蝇,所以可以只導(dǎo)入棺妓,舉例:

import './xxx'

還有異步引入,使用import方法炮赦,舉例:

let x = import('./xxx')
// 當(dāng)需要用到的時(shí)候引入怜跑,簡(jiǎn)化代碼體積
// 傳回來(lái)的是個(gè)Promise對(duì)象,需要使用await關(guān)鍵字等待
模塊化導(dǎo)入路徑問(wèn)題
  • 'xxx':直接從npm依賴(lài)?yán)飳ふ蚁嚓P(guān)模塊
  • './xxx'/../xxx:從相對(duì)路徑當(dāng)中尋找相關(guān)模塊
  • @/xxx:從src目錄下尋找相關(guān)模塊
瀏覽器兼容

對(duì)于ES6以上的寫(xiě)法吠勘,在一個(gè)古老的瀏覽器上是不兼容的性芬,因此需要對(duì)這些內(nèi)容進(jìn)行編譯

babel.js編譯

需要安裝node環(huán)境

安裝
npm install @babel/core @babel/cli @babel/preset-env -D
使用步驟

1.初始化項(xiàng)目環(huán)境:npm init -y
2.在安裝好babel后,在項(xiàng)目下添加一個(gè)文件.babelrc剧防,添加內(nèi)容如下:

{
    presets: ["@babel/preset-env"]
}

3.在src目錄下編寫(xiě)js文件
4.輸入命令:babel src -d dest植锉,即可在dest目錄發(fā)現(xiàn)文件被編譯成兼容低版本瀏覽器的js文件了
注:
如果嫌命令麻煩,也可以打開(kāi)package.json文件峭拘,在script屬性下配置自定義命令:"自定義命令": "babel src -d dest"俊庇,此時(shí)只需要輸入命令:npm run 自定義命令即可

ES7新特性

冪操作

通過(guò)**可以實(shí)現(xiàn)冪運(yùn)算,舉例:

2**3
// 8

感覺(jué)這越發(fā)展越來(lái)越像java和python的結(jié)合體了

ES8新特性

異步操作控制

對(duì)于異步操作(如ajax)本身帶來(lái)了很大的便利鸡挠,但是由于其異步的關(guān)系辉饱,有些依賴(lài)性的異步代碼則很可能陷入一種回調(diào)地獄,比如下面的代碼:

$.ajax({
    url: "https://xxx",
    success(data) {
        // 當(dāng)訪問(wèn)xxx成功時(shí)訪問(wèn)yyy
        $.ajax({
            url: "https://yyy",
            success(data) {
                // 當(dāng)訪問(wèn)yyy成功時(shí)訪問(wèn)zzz
                $.ajax({
                    url: "https://zzz",
                    success(data) {
                        // 一直回調(diào)下去...
                    },
                    error() {}
                })
            },
            error() {}
        })
    },
    error() {}
})

上面的代碼里對(duì)于yyy的訪問(wèn)是基于xxx訪問(wèn)成功的前提下拣展,而zzz的訪問(wèn)是基于yyy訪問(wèn)成功的前提下彭沼,一直這樣下去,代碼會(huì)十分混亂备埃,所以為了美化這種代碼溜腐,提出了兩種解決方案:

  • Promise對(duì)象(其實(shí)是ES5.5的內(nèi)容)
  • async/await關(guān)鍵字
Promise對(duì)象

用于封裝異步操作,使用步驟如下:
1.實(shí)例化一個(gè)Promise()對(duì)象
2.將所有異步操作封裝到Promise()對(duì)象內(nèi)部瓜喇,里面?zhèn)魅雰蓚€(gè)參數(shù)挺益,分別是執(zhí)行成功和失敗的回調(diào)函數(shù)
3.通過(guò)Promise()對(duì)象的then()方法調(diào)用異步操作時(shí)執(zhí)行的成功和失敗的回調(diào)函數(shù)
舉例:

let p = new Promise(function(resolve, reject) {
  // 封裝異步操作,傳入成功時(shí)執(zhí)行的resolve函數(shù)和失敗執(zhí)行的reject函數(shù)
  $.ajax({
    url: "https://xxx",
    success(data) {
      resolve("success", data);
      // 成功的話執(zhí)行resolve函數(shù)乘寒,并傳入一個(gè)狀態(tài)和對(duì)應(yīng)的數(shù)據(jù)望众,在后面then的時(shí)候調(diào)用
    },
    error(data) {
      reject("error", data);
      // 失敗執(zhí)行reject函數(shù),在后面catch的時(shí)候調(diào)用
    }
  });
});

// 在這里進(jìn)行異步操作的回調(diào)處理
p.then(function(status, data) {
  // 成功時(shí)的回調(diào)函數(shù),相當(dāng)于此時(shí)執(zhí)行resolve方法
  console.log(status, ":", data);
}).catch(function(status, data) {
  // 失敗時(shí)的回調(diào)函數(shù)烂翰,相當(dāng)于此時(shí)執(zhí)行reject方法
  console.log(status, ":", data);
});

從上面代碼可以看出夯缺,此時(shí)整個(gè)異步操作被放在了一個(gè)對(duì)象p里,然后后續(xù)只需要調(diào)用p.then().catch()來(lái)進(jìn)行異步操作的回調(diào)即可甘耿,相比之前的來(lái)說(shuō)踊兜,這個(gè)顯然看起來(lái)更加直觀

Promise統(tǒng)一封裝

Promise對(duì)象下有一個(gè)all方法,可以將所有的異步操作通過(guò)數(shù)組方式傳入佳恬,然后當(dāng)所有異步操作都執(zhí)行成功或存在失敗操作時(shí)通過(guò)then方法調(diào)用后續(xù)操作捏境,舉例:

new Promise.all([
    // 傳入一個(gè)包含多個(gè)異步操作的數(shù)組
    $.ajax({ url: "https://xxx", dataType: "json"}),
    $.ajax({ url: "https://yyy", dataType: "json"}),
    $.ajax({ url: "https://zzz", dataType: "json"}),
]).then(
    // 通過(guò)then方法調(diào)用后續(xù)操作,分別傳入一個(gè)成功和失敗的處理方法
    ([data1, data2, data3]) => {
        // 返回的數(shù)組分別是data1,data2,data3毁葱,通過(guò)結(jié)構(gòu)方式接受
        console.log(data1, data2, data3);
    }, res => {
        console.log("失敗");
    })
Promise異步擇優(yōu)

Promise下有race方法和all方法操作類(lèi)似垫言,也是傳入一個(gè)異步操作數(shù)組,然后當(dāng)最快的一個(gè)異步操作完成時(shí)則調(diào)用then方法進(jìn)行后續(xù)操作倾剿,并忽視其他的異步操作聋袋,若所有操作都失敗才會(huì)執(zhí)行錯(cuò)誤方法凝垛,常用于類(lèi)似CDN加速時(shí)選擇最快的鏈接場(chǎng)景截珍,舉例:

Promise.race([
    $.ajax({ url: "https://xxx", dataType: "json"}),
    $.ajax({ url: "https://yyy", dataType: "json"}),
    $.ajax({ url: "https://zzz", dataType: "json"}),
]).then(
    (data) => {
        // 只對(duì)第一個(gè)完成的操作進(jìn)行回調(diào)
        console.log(data);
    }, res => {
        console.log("失敗");
    })
async/await關(guān)鍵字

前面的Promise對(duì)象雖然讓回調(diào)代碼更加直觀坎拐,但在封裝時(shí)感覺(jué)還是挺不簡(jiǎn)潔的,而asyncawait可以讓異步的代碼更加直觀芹缔,能使我們編寫(xiě)異步代碼時(shí)更加貼近于同步代碼的寫(xiě)法坯癣。使用這兩個(gè)關(guān)鍵字可以控制異步操作是否暫停,async關(guān)鍵字用來(lái)聲明操作中存在異步乖菱,只需在操作前聲明這個(gè)關(guān)鍵字即可(注意聲明了async的函數(shù)的返回值將會(huì)自動(dòng)轉(zhuǎn)為promise對(duì)象),而在async關(guān)鍵字下的異步操作如果存在需要等待的操作蓬网,可以使用await關(guān)鍵字聲明窒所,舉例:

async function aaa() {
    console.log(0);
    let x = await $.ajax({ url: "https://xxx", dataType: "json" }, function(data) { console.log(data); })
    // x接收異步操作返回的數(shù)據(jù)
    // 由于這里使用了await等待,所以在該步會(huì)等待異步操作執(zhí)行
    // 如果異步操作失敗成功則執(zhí)行后續(xù)步驟帆锋,否則不會(huì)進(jìn)行后面的操作
    console.log(1);
    let y = await $.ajax({ url: "https://yyy", dataType: "json" }, function(data) { console.log(data); })
    console.log(2);
    let z = await $.ajax({ url: "https://zzz", dataType: "json" }, function(data) { console.log(data); })
    console.log(3);
}

上面是添加了asyncawait關(guān)鍵字以后的代碼吵取,其和沒(méi)添加的代碼結(jié)果有什么區(qū)別呢?如果是沒(méi)添加這兩個(gè)關(guān)鍵字的的情況锯厢,那么結(jié)果異步操作不管是否執(zhí)行成功皮官,一般都是先依次輸出0/1/2,然后再輸出三個(gè)異步請(qǐng)求的回調(diào)方法(成功或者失斒导)捺氢;而添加了關(guān)鍵字以后,就會(huì)先去等待第一個(gè)await的地方的執(zhí)行剪撬,并且判斷執(zhí)行是否成功摄乒,如果成功則繼續(xù)往后執(zhí)行,否則就報(bào)錯(cuò)不繼續(xù)執(zhí)行,所以就會(huì)先輸出0馍佑,然后等待一段時(shí)間斋否,當(dāng)?shù)谝粋€(gè)await地方執(zhí)行成功則繼續(xù)往后輸出1,否則報(bào)錯(cuò)后停止拭荤,以此類(lèi)推...
注:
從上面可以看出代碼相比使用Promise對(duì)象要更加的簡(jiǎn)潔茵臭,而其返回的對(duì)象(上面變量x、y舅世、z)接收的內(nèi)容旦委,實(shí)際上還是Promise對(duì)象,所以可以理解成這兩個(gè)關(guān)鍵字就是對(duì)Promise對(duì)象的進(jìn)一步封裝歇终。
注2:
asyncawait關(guān)鍵字組合操作的原理就是將函數(shù)拆分成一個(gè)個(gè)小的存在依賴(lài)關(guān)系的函數(shù)執(zhí)行社证,比如上面的實(shí)際上就可以看成如下代碼:

function aaa() {
    console.log(0);
    let x = $.ajax({
        url: "https://xxx",
        dataType: "json"
    }, function(data) {
        console.log(data);
        // 第一個(gè)await執(zhí)行成功則執(zhí)行后續(xù)內(nèi)容
        console.log(1);
        let y = $.ajax({
            url: "https://yyy",
            dataType: "json"
        }, function(data) {
            console.log(data);
            // 第二個(gè)await執(zhí)行成功則執(zhí)行后續(xù)內(nèi)容
            console.log(2);
            let z = $.ajax({
                url: "https://zzz",
                dataType: "json"
            }, function(data) {
                console.log(data);
                // 第三個(gè)await執(zhí)行成功則執(zhí)行后續(xù)內(nèi)容
                console.log(3);
            })
        })
    })
}

可以看出這個(gè)和最開(kāi)始回調(diào)地獄的代碼一樣,但是通過(guò)兩個(gè)關(guān)鍵字修飾了以后评凝,達(dá)到了簡(jiǎn)化代碼的目的
注3:
對(duì)于異步失敗的操作處理追葡,如ajax,此時(shí)如果請(qǐng)求失敗是不會(huì)有返回的奕短,比如下面代碼:

async function aaa() {
  console.log(0);
  let x = await $.ajax({ url: "https://xxx", dataType: "json" }, function(data) { console.log(data); })
  // 這里如果請(qǐng)求失敗將會(huì)沒(méi)有返回值宜肉,此時(shí)x就會(huì)變成undefined,導(dǎo)致下面那句報(bào)錯(cuò)
  console.log(x);
}

所以為了能夠?qū)κ〉恼?qǐng)求進(jìn)行處理翎碑,我們可以使用try{}catch(e){}來(lái)捕捉處理谬返,舉例:

async function aaa() {
  console.log(0);
  try{
    let x = await $.ajax({ url: "https://xxx", dataType: "json" }, function(data) { console.log(data); })
    console.log(x);
  } catch(e) {
    // 捕捉失敗的請(qǐng)求
    console.log(e);
  }
}

或者封裝到Promise對(duì)象里操作也可以,舉例:

function ajax() {
  // 封裝成Promise對(duì)象
  return new Promise((resolve, reject) =>
    $.ajax({
      url: "https://xxx",
      dataType: "json",
      success(data) {
        // then里調(diào)用
        resolve(data);
      },
      error(e) {
        // 失敗時(shí)catch捕捉
        reject(e);
      }
    })
  );
}

async function aaa() {
  console.log(0);
  let x = await ajax().then(data => data).catch(e => false);
  // 異步成功則只執(zhí)行then日杈,返回data遣铝,失敗則捕捉并返回false
  console.log(x);
}
更多參考

http://es6.ruanyifeng.com/#docs/module

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市莉擒,隨后出現(xiàn)的幾起案子酿炸,更是在濱河造成了極大的恐慌,老刑警劉巖涨冀,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件填硕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鹿鳖,警方通過(guò)查閱死者的電腦和手機(jī)扁眯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)翅帜,“玉大人姻檀,你說(shuō)我怎么就攤上這事±缘危” “怎么了施敢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵周荐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我僵娃,道長(zhǎng)概作,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任默怨,我火速辦了婚禮讯榕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匙睹。我一直安慰自己愚屁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布痕檬。 她就那樣靜靜地躺著霎槐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梦谜。 梳的紋絲不亂的頭發(fā)上丘跌,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音唁桩,去河邊找鬼闭树。 笑死,一個(gè)胖子當(dāng)著我的面吹牛荒澡,可吹牛的內(nèi)容都是我干的报辱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼单山,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼碍现!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起米奸,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昼接,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后躏升,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辩棒,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狼忱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年膨疏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钻弄。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佃却,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窘俺,到底是詐尸還是另有隱情饲帅,我是刑警寧澤复凳,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站灶泵,受9級(jí)特大地震影響育八,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赦邻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一髓棋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惶洲,春花似錦按声、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至铐料,卻和暖如春渐裂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背余赢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工芯义, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人妻柒。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓扛拨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親举塔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绑警,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • es6相較之前es5,增加了許多新的特性央渣,提高了javascript體驗(yàn)计盒,我在es6學(xué)習(xí)和使用的過(guò)程中進(jìn)行了紀(jì)錄。...
    YomonAh閱讀 229評(píng)論 0 2
  • 本文為阮一峰大神的《ECMAScript 6 入門(mén)》的個(gè)人版提純芽丹! babel babel負(fù)責(zé)將JS高級(jí)語(yǔ)法轉(zhuǎn)義北启,...
    Devildi已被占用閱讀 1,983評(píng)論 0 4
  • 第一章:塊級(jí)作用域綁定 塊級(jí)聲明 1.var聲明及變量提升機(jī)制:在函數(shù)作用域或者全局作用域中通過(guò)關(guān)鍵字var聲明的...
    BeADre_wang閱讀 837評(píng)論 0 0
  • [TOC] 參考阮一峰的ECMAScript 6 入門(mén)參考深入淺出ES6 let和const let和const都...
    郭子web閱讀 1,781評(píng)論 0 1
  • 你不知道JS:異步 第三章:Promises 接上篇3-1 錯(cuò)誤處理(Error Handling) 在異步編程中...
    purple_force閱讀 1,398評(píng)論 0 2