阮一峰ES6教程讀書筆記(一)解構(gòu)賦值熄诡、let和const

About

讀完阮一峰大神ES5教程后自覺(jué)獲益匪淺,遂拜讀其ES6教程诗力。為記錄所感所得凰浮,打算寫《阮一峰ES6教程讀后感》系列文章,有興趣的朋友可以關(guān)注一下姜骡。

一导坟、詳解let和const命令

letconstES6新增的變量聲明命令,他們的用法與var類似圈澈,但是經(jīng)它們聲明的變量與var聲明的變量有很大的區(qū)別惫周。

(一)var和let的區(qū)別

  • var聲明的變量的作用域?yàn)槿肿饔糜蚧蛘吆瘮?shù)作用域,而let聲明的變量多一個(gè)塊級(jí)作用域
  • var聲明的變量可以進(jìn)行變量提升康栈,即在聲明變量之前使用變量递递,而let聲明的變量必須要在變量聲明語(yǔ)句之后使用,否則會(huì)報(bào)錯(cuò)
  • let聲明的變量存在“暫時(shí)性死區(qū)”啥么,即從區(qū)塊開(kāi)始至變量聲明語(yǔ)句之前是無(wú)法訪問(wèn)變量的
  • let聲明的變量不允許重復(fù)聲明

1. 塊級(jí)作用域

我們先看看這個(gè)例子:

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

其實(shí)我們預(yù)期的答案是6登舞,但是如果這樣寫代碼,我們無(wú)法的到預(yù)期的答案悬荣,因?yàn)?code>a[6]里面存儲(chǔ)的函數(shù)語(yǔ)句中的i指向的是一個(gè)全局變量菠秒,當(dāng)for循環(huán)完畢后,i的值為10氯迂,即函數(shù)語(yǔ)句中的每一個(gè)i都指向了同一個(gè)地址践叠,而這個(gè)地址中存儲(chǔ)的數(shù)字為10,所以我們無(wú)論通過(guò)數(shù)組a中哪一個(gè)元素中的函數(shù)去打印i得到的答案都是10

為了得到我們預(yù)期的答案嚼蚀,我們應(yīng)該將代碼進(jìn)行一定的改寫:

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

可以看到這里面的for循環(huán)的i是通過(guò)let聲明的禁灼,所以i僅在當(dāng)前循環(huán)中有效,在其他循環(huán)中無(wú)法訪問(wèn)到當(dāng)前循環(huán)的i轿曙,我們可以理解為每一個(gè)i是獨(dú)立的弄捕,所以數(shù)組a中每一個(gè)元素中存儲(chǔ)的函數(shù)語(yǔ)句中的i指向的是不同的地址僻孝,每個(gè)地址存儲(chǔ)的是當(dāng)前循環(huán)中的i

2. 不存在變量提升

正常的邏輯是我們必須先聲明一個(gè)變量,然后再去使用守谓,如果在沒(méi)有聲明就去使用而僅僅告訴我undefined穿铆,這顯然不能讓我們滿意。

// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;

// let 的情況
console.log(bar); // 報(bào)錯(cuò)ReferenceError
let bar = 2;

通過(guò)上面的代碼我們可以發(fā)現(xiàn)分飞,使用let聲明的變量終于糾正了這一點(diǎn)悴务,我們無(wú)法在聲明變量之前去使用它。

3. 暫時(shí)性死區(qū)(temporal dead zone譬猫,簡(jiǎn)稱 TDZ)

正因?yàn)槭褂?code>let聲明的變量不存在變量提升現(xiàn)象讯檐,所以會(huì)出現(xiàn)暫時(shí)性死區(qū)的現(xiàn)象

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
  tmp = '2333'
  console.log(tmp) // 2333
}

盡管我們知道在使用大括號(hào)括起來(lái)的代碼塊內(nèi)使用let聲明變量,該變量的作用域?yàn)閴K級(jí)作用域染服,但是該塊級(jí)作用域并非整個(gè)區(qū)塊别洪,從該區(qū)塊開(kāi)始到聲明變量之前的區(qū)域被稱之為“暫時(shí)性死區(qū)”,因?yàn)樵谶@一區(qū)域內(nèi)我們無(wú)法訪問(wèn)到后面聲明的變量柳刮。

4. 不允許重復(fù)聲明

在使用let聲明的變量的作用域內(nèi)挖垛,不允許重復(fù)聲明,無(wú)論你用let秉颗,var還是const痢毒。在函數(shù)內(nèi)也一樣:

function func(arg) {
  let arg;
}
func() // 報(bào)錯(cuò)

function func(arg) {
  {
    let arg;
  }
}
func() // 不報(bào)錯(cuò)

(二)塊級(jí)作用域與函數(shù)聲明

ES5 規(guī)定,函數(shù)只能在頂層作用域和函數(shù)作用域之中聲明蚕甥,不能在塊級(jí)作用域聲明哪替。但是,瀏覽器沒(méi)有遵守這個(gè)規(guī)定菇怀,為了兼容以前的舊代碼凭舶,還是支持在塊級(jí)作用域之中聲明函數(shù),因此上面兩種情況實(shí)際都能運(yùn)行爱沟,不會(huì)報(bào)錯(cuò)帅霜。比如:

// 在使用ES5標(biāo)準(zhǔn)的瀏覽器中
function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重復(fù)聲明一次函數(shù)f
    function f() { console.log('I am inside!'); }
  }

  f();
}()); // 'I am inside!'

因?yàn)?code>ES5中,函數(shù)也是“一等公民”具有變量提升的作用呼伸,但是函數(shù)的變量提升不僅僅是函數(shù)名的變量提升身冀,而是包括整個(gè)函數(shù)體的提升,所以上述代碼可翻譯為:

// 在使用ES5標(biāo)準(zhǔn)的瀏覽器中
function f() { console.log('I am outside!'); }

(function () {
  // 重復(fù)聲明一次函數(shù)f
  function f() { console.log('I am inside!'); }
  if (false) {
    }
  f();
}()); // 'I am inside!'

但是在使用ES6標(biāo)準(zhǔn)的瀏覽器中括享,上述代碼就會(huì)報(bào)錯(cuò)ES6 在附錄 B里面規(guī)定闽铐,瀏覽器的實(shí)現(xiàn)可以不遵守上面的規(guī)定,有自己的行為方式奶浦。

  • 允許在塊級(jí)作用域內(nèi)聲明函數(shù)。
  • 函數(shù)聲明類似于var踢星,即會(huì)提升到全局作用域或函數(shù)作用域的頭部澳叉。
  • 同時(shí),函數(shù)聲明還會(huì)提升到所在的塊級(jí)作用域的頭部。
    所以上述代碼可翻譯為:
// 在使用ES6標(biāo)準(zhǔn)的瀏覽器中
function f() { console.log('I am outside!'); }

(function () {
  var f  // 此時(shí)f為undefined
  if (false) {
  }

  f();
}()); // Uncaught TypeError: f is not a function

(三)const命令

letconst的用法差不多成洗,只不過(guò)是const一般被用來(lái)聲明常量五督,即聲明語(yǔ)句中必須賦值,并且聲明之后不能更改

1. const命令的本質(zhì)

const實(shí)際上保證的瓶殃,并不是變量的值不得改動(dòng)充包,而是變量指向的那個(gè)內(nèi)存地址所保存的數(shù)據(jù)不得改動(dòng)。對(duì)于簡(jiǎn)單類型的數(shù)據(jù)(數(shù)值遥椿、字符串基矮、布爾值),值就保存在變量指向的那個(gè)內(nèi)存地址冠场,因此等同于常量家浇。但對(duì)于復(fù)合類型的數(shù)據(jù)(主要是對(duì)象和數(shù)組),變量指向的內(nèi)存地址碴裙,保存的只是一個(gè)指向?qū)嶋H數(shù)據(jù)的指針钢悲,const只能保證這個(gè)指針是固定的(即總是指向另一個(gè)固定的地址),至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的舔株,就完全不能控制了莺琳。因此,將一個(gè)對(duì)象聲明為常量必須非常小心载慈。

const foo = {};

// 為 foo 添加一個(gè)屬性惭等,可以成功
foo.prop = 123;
foo.prop // 123

// 將 foo 指向另一個(gè)對(duì)象,就會(huì)報(bào)錯(cuò)
foo = {}; // TypeError: "foo" is read-only

(四)頂層對(duì)象的屬性

ES6以前的標(biāo)準(zhǔn)中娃肿,我們使用varfunction聲明的全局變量會(huì)變成頂層對(duì)象的屬性咕缎,ES6 為了改變這一點(diǎn),一方面規(guī)定料扰,為了保持兼容性凭豪,var命令和function命令聲明的全局變量,依舊是頂層對(duì)象的屬性晒杈;另一方面規(guī)定嫂伞,let命令、const命令拯钻、class命令聲明的全局變量帖努,不屬于頂層對(duì)象的屬性。也就是說(shuō)粪般,從 ES6 開(kāi)始拼余,全局變量將逐步與頂層對(duì)象的屬性脫鉤。

var a = 1;
// 如果在 Node 的 REPL 環(huán)境亩歹,可以寫成 global.a
// 或者采用通用方法匙监,寫成 this.a
window.a // 1

let b = 1;
window.b // undefined

二凡橱、變量的解構(gòu)賦值

ES6 允許按照一定模式,從數(shù)組和對(duì)象中提取值亭姥,對(duì)變量進(jìn)行賦值稼钩,這被稱為解構(gòu)(Destructuring)。

(一)基本用法

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

上面代碼表示达罗,可以從數(shù)組中提取值坝撑,按照對(duì)應(yīng)位置,對(duì)變量賦值粮揉。本質(zhì)上巡李,這種寫法屬于“模式匹配”,只要等號(hào)兩邊的模式相同滔蝉,左邊的變量就會(huì)被賦予對(duì)應(yīng)的值

1. 解構(gòu)成功

解構(gòu)成功的條件是=兩邊的模式完全相同

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 // []

2. 不完全解構(gòu)

因?yàn)槲覀兪褂媒鈽?gòu)的目的是為了給=左邊的變量賦值击儡,那么如果從左到右都能找到對(duì)應(yīng)元素,那么就能完成解構(gòu)蝠引,如果此時(shí)從右到左無(wú)法完成一一對(duì)應(yīng)阳谍,那么就稱之為不完全解構(gòu),例如:

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

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

3. 解構(gòu)失敗

如果等號(hào)的右邊不是數(shù)組(或者嚴(yán)格地說(shuō)螃概,不是可遍歷的結(jié)構(gòu))矫夯,那么將會(huì)報(bào)錯(cuò)。

// 報(bào)錯(cuò)
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

上面的語(yǔ)句都會(huì)報(bào)錯(cuò)吊洼,因?yàn)榈忍?hào)右邊的值训貌,要么轉(zhuǎn)為對(duì)象以后不具備 Iterator 接口(前五個(gè)表達(dá)式),要么本身就不具備 Iterator 接口(最后一個(gè)表達(dá)式)冒窍。

(二)解構(gòu)表達(dá)式默認(rèn)賦值

同聲明函數(shù)一樣递沪,我們可以在函數(shù)表達(dá)式中聲明實(shí)參時(shí)給實(shí)參賦默認(rèn)值,如果調(diào)用該函數(shù)時(shí)综液,形參為空款慨,那么實(shí)參就采用聲明函數(shù)時(shí)的默認(rèn)值。解構(gòu)賦值表達(dá)式同理

let [foo = true] = [];
foo // true

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

(三)對(duì)象的解構(gòu)賦值

與數(shù)組一樣谬莹,解構(gòu)也可以用于嵌套結(jié)構(gòu)的對(duì)象檩奠。

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"

此時(shí)的p僅僅是一個(gè)模式,如果要對(duì)p賦值附帽,必須這么寫:

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

(四)字符串解構(gòu)賦值和布爾值解構(gòu)賦值

1. 字符串解構(gòu)賦值

字符串也可以解構(gòu)賦值埠戳。這是因?yàn)榇藭r(shí),字符串被轉(zhuǎn)換成了一個(gè)類似數(shù)組的對(duì)象蕉扮。

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

類似數(shù)組的對(duì)象都有一個(gè)length屬性整胃,因此還可以對(duì)這個(gè)屬性解構(gòu)賦值。

let {length : len} = 'hello';
len // 5

2. 布爾值解構(gòu)賦值

解構(gòu)賦值時(shí)喳钟,如果等號(hào)右邊是數(shù)值和布爾值爪模,則會(huì)先轉(zhuǎn)為對(duì)象欠啤。

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

(五)解構(gòu)賦值的作用

1. 交換變量的值

以前,這個(gè)功能只在Python中使用過(guò)屋灌,如今可以在JavaScript中使用還是很開(kāi)心的

[x, y] = [y, x]

2. 從函數(shù)返回多個(gè)值

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

3. 函數(shù)參數(shù)的定義

解構(gòu)賦值可以方便地將一組參數(shù)與變量名對(duì)應(yīng)起來(lái)。

4. 提取JSON數(shù)據(jù)

這個(gè)太有用了应狱,因?yàn)槲覀儚慕涌谥蝎@得的數(shù)據(jù)一般都是JSON對(duì)象共郭,所以使用結(jié)構(gòu)賦值可以使我們的代碼更簡(jiǎn)潔

const {ret, data} = res.data

5. 遍歷Map結(jié)構(gòu)

任何部署了 Iterator 接口的對(duì)象,都可以用for...of循環(huán)遍歷疾呻。Map 結(jié)構(gòu)原生支持 Iterator 接口除嘹,配合變量的解構(gòu)賦值,獲取鍵名和鍵值就非常方便岸蜗。這個(gè)在Vue中也是經(jīng)常使用

const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}

6. 輸入模塊的指定方法

加載模塊時(shí)尉咕,往往需要指定輸入哪些方法。解構(gòu)賦值使得輸入語(yǔ)句非常清晰璃岳。

const { SourceMapConsumer, SourceNode } = require("source-map");

參考鏈接

作者:阮一峰
鏈接:http://es6.ruanyifeng.com/#docs/destructuring

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末年缎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子铃慷,更是在濱河造成了極大的恐慌单芜,老刑警劉巖坛吁,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谋作,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡教馆,警方通過(guò)查閱死者的電腦和手機(jī)馋缅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門扒腕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人萤悴,你說(shuō)我怎么就攤上這事瘾腰。” “怎么了稚疹?”我有些...
    開(kāi)封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵居灯,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我内狗,道長(zhǎng)怪嫌,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任柳沙,我火速辦了婚禮岩灭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赂鲤。我一直安慰自己噪径,他們只是感情好柱恤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著找爱,像睡著了一般梗顺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上车摄,一...
    開(kāi)封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天寺谤,我揣著相機(jī)與錄音,去河邊找鬼吮播。 笑死变屁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的意狠。 我是一名探鬼主播粟关,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼环戈!你這毒婦竟也來(lái)了闷板?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谷市,失蹤者是張志新(化名)和其女友劉穎蛔垢,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體迫悠,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹏漆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了创泄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艺玲。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鞠抑,靈堂內(nèi)的尸體忽然破棺而出饭聚,到底是詐尸還是另有隱情,我是刑警寧澤搁拙,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布秒梳,位于F島的核電站,受9級(jí)特大地震影響箕速,放射性物質(zhì)發(fā)生泄漏酪碘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一盐茎、第九天 我趴在偏房一處隱蔽的房頂上張望兴垦。 院中可真熱鬧,春花似錦、人聲如沸探越。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)钦幔。三九已至枕屉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鲤氢,已是汗流浹背搀庶。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铜异,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓秸架,卻偏偏與公主長(zhǎng)得像揍庄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子东抹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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