一芭毙、聲明變量
es5之前筋蓖,聲明變量只有var聲明、隱式聲明和函數(shù)聲明退敦。而es6中則多了let和const粘咖。
(1)let和const的“塊級作用域”:
var a = 1;
function test(){
var a = 2;
}
test();
console.log(a);
最終結(jié)果是"1",這是因為在js中侈百,var有“函數(shù)作用域”瓮下,所以var a = 2的聲明只能在函數(shù)test區(qū)域里面有效,在外面則不會生效钝域,現(xiàn)在去掉函數(shù):
var a =1;
{
var a = 2;
}
console.log(a);
得到的結(jié)果則是“2”讽坏,這是因為var沒有“塊級作用域”。
像c网梢、java等其他語言中震缭,變量的聲明都有“塊級作用域”,所謂“塊”战虏,就是以花括號{}為邊界拣宰,而花括號里面的區(qū)域党涕,就是這個聲明可以被訪問的域區(qū),而花括號之外就不可以了巡社。在es6中膛堤,新添加的let的const同樣擁有“塊級作用域”,將上面代碼中的var改成let:
let a = 1;
{
let a = 2;
}
console.log(a);
最后輸出的結(jié)果依然是“1”晌该,改成const也是這個結(jié)果肥荔。
塊級作用域,最大的應(yīng)用朝群,就是每篇let和const教學(xué)文章都會提到的for循環(huán):
for( var i = 0; i < 3; i++){
setTimeout(function(){
console.log(i);
},100)
}
3次輸出的結(jié)果都是“2”燕耿;
而改用let:
for( let i = 0; i < 3; i++){
setTimeout(function(){
console.log(i);
},100)
}
則3次輸出的結(jié)果分別是“0、1姜胖、2”誉帅;
(2)var有提升變量的作用,而let和const則沒有右莱。
console.log(a);
var a = 1;
則輸出的結(jié)果是:
因為var有提升變量的功能蚜锨,但是不能提升賦值,所以輸出的結(jié)果就是undefined慢蜓,上面的代碼就相當(dāng)于:
var a;
console.log(a);
a = 1;
如果把var改成let或者const亚再,例如:
console.log(a);
let/const a = 1;
則得到的結(jié)果就是:
造成這樣的原因,是因為在let和const聲明某個變量之前晨抡,會形成一個“Temporal Dead Zone”(暫時性死區(qū)),在這個區(qū)域里是無法訪問這個變量氛悬。
(3)var可以重復(fù)聲明,而let和const在同一塊級作用域中不可以:
(1)var a = 1;
var a = 2;
(2)let a = 1;
let a = 2;
(3)const a = 1;
const a = 2;
(4)let a = 1;
const a = 2;
(5)let a = 1;
var a = 2;
(6)const a = 1;
var a = 2;
console.log(a);
后面5種情況都會報錯:
[注意凄诞,let和const在不同塊級作用域則可以同時存在圆雁,參見(1)“塊級作用域部分”];
(4)const是常量不可變帆谍,let可變:
const的全拼“constant”就是不可變的意思
let a = 1;
a = a+1;
console.log(a);
輸出的結(jié)果是“2”伪朽,如果改成const:
const a = 1;
a = a +1;
console.log(a);
則會報錯:
需要注意的是,const的不可變并不是完全不可變汛蝙,例如:
const a = [];
a.push(1);
console.log(a);
則輸出的結(jié)果是“[1]”烈涮,這是因為const更像是“constant reference”。
也就是說窖剑,地址不能改變坚洽,而地址指向的值可以改變。
二西土、解構(gòu)賦值(Destructuring):
es6之前讶舰,變量聲明的結(jié)構(gòu)是十分固定的,變量名放在等號的左邊,而數(shù)組[]跳昼、對象{}和字符串則是放在等號的右邊般甲。而在es6中,它們的位置可以互相調(diào)換了鹅颊。
let arr = [1,2,3];
let first = arr[0];
console.log(first);
則輸出的結(jié)果是‘1’敷存。
let arr = [1,2,3];
let [first] = arr;
console.log(first);
則輸出的結(jié)果還是‘1’。
而對象的解構(gòu)堪伍,屬性名與變量名需要保持一致锚烦,否則會輸出undefined
let {first}={'a':1};
console.log(first); //undefined;
左側(cè)的變量可以通過逗號的形式跳過右側(cè)對應(yīng)的值:
var [,b] = [1,2,3];
console.log(b); // 輸出結(jié)果為‘2’;
解構(gòu)賦值的優(yōu)勢帝雇,就是能省去不少額外的聲明涮俄,最典型的應(yīng)用,就是json尸闸,例如后臺通過ajax傳過來的數(shù)據(jù)都是json禽拔,那是用的時候就不需要一個屬性一個屬性的聲明了:
let json = {'username':xxx, 'option':'a', 'score':'100'}
let {username, option, score} = json;
console.log(username);
// 不用解構(gòu)的話,想獲取json中username的值室叉,就要寫成 json.username。
還有一個就是給函數(shù)的參數(shù)設(shè)定默認(rèn)值:
function test(a,b){
if(a == true){
var b = 1;
}else{
var b = 2;
}
console.log(b);
}
test(false);
而使用解構(gòu)賦值的話:
function test(a,{b = 2}){
if(a == true){
var b = 1;
}
console.log(b);
}
test(true,{});
另外要注意一點硫惕,解構(gòu)賦值只能獲取值茧痕,不能改變值:
let json = {num:1, num2:2};
let { num2 } = json;
console.log(num2 ); // 輸出的結(jié)果為2;
num2 = 3;
console.log( json) // 輸出的結(jié)果為{num:1, num2:2},而不是{num:1, num2:3}恼除;
通過解構(gòu)賦值踪旷,json里num2的值被賦給了num2。但是反過來豁辉,如果你想通過直接修改num2的值來修改json里num2的值令野,這樣是不行的。
所以有時你可能還要再包一層json:
let json = { nums : { num:1 ,num2:2} };
let {nums} = json;
nums.num2 = 3;
console.log(json) // 輸出結(jié)果為{nums : { num:1 ,num2:3} };
三徽级、模板字符串(template strings)----字符串拼接:
es5之前字符串的拼接是通過把字符串放在雙引號或單引號里气破,而變量則通過‘+’和字符串拼接起來,而在es6中則是把字符串放在反引號`` 里餐抢,變量則放在$符號和花括號里现使,例如:
const word = "world";
console.log(`hi! ${word}.`);
輸出的結(jié)果為:
而這個${}被稱為“模板替換”(template substitutions),在這里你可以放任意JavaScript表達(dá)式(運算表達(dá)式旷痕,函數(shù)的調(diào)用)或者是某個對象屬性碳锈、另一個模板字符串。
(1)換行
模板字符串添加了一個新的功能欺抗,支持換行售碳。把兩句話放在一個雙引號或者單引號里,在兩句話之間通按回車鍵進(jìn)行換行,即:
console.log('this is line1,
this is line2');
js會認(rèn)為這句話少了半邊引號贸人,導(dǎo)致報錯间景,要想實現(xiàn)換行,只能在兩句話之間加轉(zhuǎn)移字符‘\n’灸姊。
如果換用反引號拱燃,即:
這樣是不會報錯的,只是輸出的結(jié)果則為:
這是因為第二句話并不是在第二行最開始的地方書寫力惯,而是留有一定的空隙碗誉。由于模板字符串會保留反引號之內(nèi)每一行的所有空格,所以導(dǎo)致這些空隙也被保留了下了父晶。如果改成:
那么兩句話的開頭就是對齊的哮缺。
當(dāng)然,如果你想要實現(xiàn)在html里換行甲喝,模板字符串里直接回車也是不會生效的尝苇,只有加上換行標(biāo)簽</br>才行。
document.write(`this is line1,
</br>this is line2`)
(2)嵌套
提到模板字符串埠胖,大部分的文章都會提到類似“模板字符串之間還可以進(jìn)行嵌套”之類的話糠溜,而這個嵌套,也主要是指在${}里放入另一個模板字符串直撤。例如聲明一個變量:
let b = 'world';
console.log(``${a}``); // 報錯非竿,可見模板字符串不能直接嵌套在另一個反引號里。
console.log(`${ `hello $谋竖` }`); // 輸出‘hello world’
如果聲明多個變量:
let a = 'hello';
let b = 'world';
console.log(`${a `$红柱`}`); //報錯:a is not a function(…),可見${}里面如果存在變量時蓖乘,也不能放入另一個模板字符串锤悄。
(3)標(biāo)簽?zāi)0?tagged template)
定義一個test函數(shù):
function test(){
console.log('hello');
};
test ``;
最后結(jié)果輸出:
然而``調(diào)用函數(shù)和()調(diào)用函數(shù)還是有一定的區(qū)別,現(xiàn)在改成通過傳參的方式調(diào)用函數(shù):
function test(data){
console.log(data);
};
test `hello`;
結(jié)果輸出的卻是數(shù)組:
這就是模板字符串的‘標(biāo)記模板’屬性嘉抒,所謂“標(biāo)記模板”零聚,就是定義一個函數(shù),然后把該函數(shù)的函數(shù)名放在模板字符串的前面些侍,這樣就能將該函數(shù)和模板字符串聯(lián)系起來握牧,然后通過這個函數(shù)對模板字符串進(jìn)行處理。