一. ECMAScript6簡介
-
ECMAScript和JavaScript的關(guān)系
1996年忿薇,JavaScript的創(chuàng)造者NetScape公司,將JavaScript提交給國際標(biāo)準(zhǔn)化組織ECMA,希望成為國際標(biāo)準(zhǔn)署浩,次年ECMA組織發(fā)布了ECAMScript標(biāo)準(zhǔn)筋栋,也就是ECMAScript 1.0版本
為什么不使用原來的名字呢
a. java是sun公司的商標(biāo)弊攘,
b. 想體現(xiàn)這門語言的制定者是ECMA襟交,不是NetScape渣磷,這樣有利于保證這門語言的開放性和中立性
-
ES6與ECMAScript2015的關(guān)系
2011年醋界,ECMAScript 5.1版發(fā)布后,此標(biāo)準(zhǔn)成為ISO國際標(biāo)準(zhǔn),
2015年6月形纺,ECMA 6發(fā)布正式版本
標(biāo)準(zhǔn)在每年的6月份正式發(fā)布一次,作為當(dāng)年的正式版本,這樣,就不需要以前的版本號了蜗字,只要用年份標(biāo)記就可以了挪捕,所以ECMA 6的正式名字是ECMAScript 2015
二. let和const命令
-
let命令
a用來聲明變量级零。它的用法類似于var滞乙,但是所聲明的變量,只在let命令所在的代碼塊內(nèi)有效
for循環(huán)的計(jì)數(shù)器醉锅,就很合適使用let命令
-
思考下面兩句代碼的輸出
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6]();
var命令會(huì)發(fā)生”聲明提前“現(xiàn)象硬耍,let命令改變了語法行為默垄,它所聲明的變量一定要在聲明后使用甚纲,否則報(bào)錯(cuò)
-
暫時(shí)性死區(qū)
a. 只要塊級作用域內(nèi)存在let命令介杆,它所聲明的變量就“綁定”(binding)這個(gè)區(qū)域春哨,形成了封閉作用域,不再受外部的影響赴背。
b. 在代碼塊內(nèi),使用let命令聲明變量之前燃观,該變量都是不可用的缆毁。這在語法上脊框,稱為“暫時(shí)性死區(qū)”
let不允許在相同作用域內(nèi)浇雹,重復(fù)聲明同一個(gè)變量昭灵。
-
塊級作用域
-
ES6的塊級作用域
任何一對花括號({和})中的語句集都屬于一個(gè)塊虎锚,在這之中定義的所有變量在代碼塊外都是不可見的窜护,我們稱之為塊級作用域柱徙。
ES5只有全局作用域和函數(shù)作用域(屬于塊級作用域)奇昙,沒有塊級作用域储耐,這帶來很多不合理的場景
a) 用來計(jì)數(shù)的循環(huán)變量泄漏為全局變量 var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5 b) 內(nèi)層變量可能會(huì)覆蓋外層變量 var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = "hello world"; } } f(); // undefined
-
-
const命令
聲明一個(gè)只讀的常量什湘,一旦聲明,常量的值就不能改變,所以const一旦聲明變量得哆,就必須立即初始化贩据,不能留到以后賦值
const的作用域與let命令相同饱亮,只在聲明所在的塊級作用域內(nèi)有效
const命令聲明的變量也是不提升近尚,同樣存暫時(shí)性死區(qū)戈锻,只能在聲明的位置后面使用
不可重復(fù)聲明
本質(zhì)
const實(shí)際上保證的格遭,并不是變量的值不得改動(dòng)拒迅,而是變量指向的那個(gè)內(nèi)存地址不得改動(dòng)璧微。對于簡單類型的數(shù)據(jù)(數(shù)值前硫、字符串屹电、布爾值)危号,值就保存在變量指向的那個(gè)內(nèi)存地址猪半,因此等同于常量苍狰。但對于復(fù)合類型的數(shù)據(jù)(主要是對象和數(shù)組)淋昭,變量指向的內(nèi)存地址翔忽,保存的只是一個(gè)指針歇式,const只能保證這個(gè)指針是固定的,至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的痕鳍,就完全不能控制了
部分修改常量是不允許的,全部修改常量是允許的 const foo = {}; // 為 foo 添加一個(gè)屬性诗赌,可以成功 foo.prop = 123; foo.prop // 123 // 將 foo 指向另一個(gè)對象铭若,就會(huì)報(bào)錯(cuò) foo = {};
-
頂層對象的屬性
- 頂層對象的屬性與全局變量掛鉤,被認(rèn)為是JavaScript語言最大的設(shè)計(jì)敗筆之一,
a. 特別容易創(chuàng)建全局變量瞳腌,
b. 對象的屬性是到處可以讀寫的纯趋,另外window指的是瀏覽器的窗口對象,這非常不利于模塊化編程- ES6為了保持兼容性西剥,規(guī)定var命令和function命令聲明的全局變量,依舊是頂層對象的屬性咆畏;同時(shí)規(guī)定旧找,let命令麦牺、const命令钮蛛、class命令聲明的全局變量,不屬于頂層對象的屬性剖膳。也就是說魏颓,從ES6開始,全局變量將逐步與頂層對象的屬性脫鉤
三. 數(shù)組的解構(gòu)賦值
-
ES6 允許按照一定模式吱晒,從數(shù)組和對象中提取值甸饱,對變量進(jìn)行賦值,這被稱為解構(gòu)(Destructuring)仑濒,比如
let [a, b, c] = [1, 2, 3];
-
本質(zhì)上叹话,這種寫法屬于“模式匹配”,只要等號兩邊的模式相同躏精,左邊的變量就會(huì)被賦予對應(yīng)的值辅柴。下面是一些使用嵌套數(shù)組進(jìn)行解構(gòu)的例子,如果結(jié)構(gòu)不成,變量的值就為undefined烹棉。
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3let [ , , third] = ["foo", "bar", "baz"];
third // "baz"let [x, , y] = [1, 2, 3];
x // 1
y // 3let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // [] -
不完全解構(gòu),即等號左邊的模式,只匹配一部分的等號右邊的數(shù)組。這種情況下,解構(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
-
結(jié)構(gòu)賦值允許指定默認(rèn)值
let [foo = true] = [];
foo // truelet [x, y = 'b'] = ['a']; // x='a', y='b' let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
-
默認(rèn)值是一個(gè)表達(dá)式,那么這個(gè)表達(dá)式是惰性求值的屁擅,即只有值為undefind時(shí)才會(huì)執(zhí)行表達(dá)式
function f() { console.log('aaa'); } let [x = f()] = [1];
四. 對象的解構(gòu)賦值
-
對象的解構(gòu)與數(shù)組有一個(gè)重要的不同。數(shù)組的元素是按次序排列的霎烙,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名昧捷,才能取到正確的值。
let { foo, bar } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb"
-
對象的解構(gòu)其實(shí)是下面形式的簡寫
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
毒返,采用這種寫法時(shí)贾富,變量的聲明和賦值是一體的畏纲。對于let和const來說读整,變量不能重新聲明屈糊,所以一旦賦值的變量以前聲明過晓淀,就會(huì)報(bào)錯(cuò)
let foo;
let {foo} = {foo: 1}; -
對象的解構(gòu)也可以指定默認(rèn)值,默認(rèn)值生效的條件是稚配,對象的屬性值嚴(yán)格等于undefined
var {x = 3} = {}; var {x, y = 5} = {x: 1};
五. 字符串的解構(gòu)賦值
-
本質(zhì)是字符串被轉(zhuǎn)換成了一個(gè)類似數(shù)組的對象
const [a, b, c, d, e] = 'hello'; a // "h" b // "e" c // "l" d // "l" e // "o"
-
似數(shù)組的對象都有一個(gè)length屬性苇经,因此還可以對這個(gè)屬性解構(gòu)賦值
let {length : len} = 'hello'; len // 5
六. 數(shù)值和布爾值的解構(gòu)賦值
-
解構(gòu)賦值時(shí)施流,如果等號右邊是數(shù)值和布爾值宾巍,則會(huì)先轉(zhuǎn)為對象玄叠。
let {toString: s} = 123; s === Number.prototype.toString // true let {toString: s} = true; s === Boolean.prototype.toString // true
-
解構(gòu)賦值的規(guī)則是狐粱,只要等號右邊的值不是對象或數(shù)組,就先將其轉(zhuǎn)為對象蒋搜。由于undefined和null無法轉(zhuǎn)為對象,所以對它們進(jìn)行解構(gòu)賦值憾筏,都會(huì)報(bào)錯(cuò)
let { prop: x } = undefined; // TypeError let { prop: y } = null; // TypeError
七. 函數(shù)參數(shù)的解構(gòu)賦值
-
函數(shù)的參數(shù)也可以使用解構(gòu)賦值
function add([x, y]){ return x + y; } add([1, 2]);
函數(shù)add的參數(shù)表面上是一個(gè)數(shù)組膏潮,但在傳入?yún)?shù)的那一刻,數(shù)組參數(shù)就被解構(gòu)成變量x和y掂僵。對于函數(shù)內(nèi)部的代碼來說航厚,它們能感受到的參數(shù)就是x和y
-
函數(shù)參數(shù)的解構(gòu)也可以使用默認(rèn)值
function move({x = 0, y = 0} = {}) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, 0] move({}); // [0, 0] move(); // [0, 0]
函數(shù)move的參數(shù)是一個(gè)對象,通過對這個(gè)對象進(jìn)行解構(gòu)锰蓬,得到變量x和y的值幔睬。如果解構(gòu)失敗,x和y等于默認(rèn)值芹扭。
八. 解構(gòu)賦值-用途
-
交換變量的值
let x = 1; let y = 2; [x, y] = [y, x];
面代碼交換變量x和y的值麻顶,這樣的寫法不僅簡潔,而且易讀舱卡,語義非常清晰
-
從函數(shù)返回多個(gè)值
function example() { return [1, 2, 3]; } let [a, b, c] = example();
// 返回一個(gè)對象
function example() { return { foo: 1, bar: 2 }; } let { foo, bar } = example();
函數(shù)只能返回一個(gè)值辅肾,如果要返回多個(gè)值,只能將它們放在數(shù)組或?qū)ο罄锓祷芈肿丁S辛私鈽?gòu)賦值宛瞄,取出這些值就非常方便。
-
提取JSON數(shù)據(jù)
解構(gòu)賦值對提取JSON對象中的數(shù)據(jù),尤其有用份汗。
let jsonData = { id: 42, status: "OK", data: [867, 5309] }; let { id, status, data: number } = jsonData; console.log(id, status, number);
-
函數(shù)參數(shù)的默認(rèn)值
jQuery.ajax = function (url, { async = true, beforeSend = function () {}, cache = true, complete = function () {}, crossDomain = false, global = true, // ... more config }) { // ... do stuff };
指定參數(shù)的默認(rèn)值盈电,就避免了在函數(shù)體內(nèi)部再寫var foo = config.foo || 'default foo';
-
遍歷Map結(jié)構(gòu)
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
如果只想獲取鍵名,或者只想獲取鍵值
// 獲取鍵名 for (let [key] of map) { // ... } // 獲取鍵值 for (let [,value] of map) { // ... }
-
輸入模塊的指定方法
加載模塊時(shí)杯活,往往需要指定輸入哪些方法匆帚。解構(gòu)賦值使得輸入語句非常清晰
const { SourceMapConsumer, SourceNode } = require("source-map");