1. let關(guān)鍵字
let的用途:
在之前寫js時(shí)候,用var來聲明一個(gè)變量,es6里面除了var還有其他的聲明變量的關(guān)鍵字,let就是其中之一,那么let的用途就是用來聲明變量的。
let與var
既然都是聲明變量的關(guān)鍵字,那肯定就有區(qū)別,要不就不會有第二個(gè)了,看看有什么區(qū)別。
使用 var 的不足之處:
1.var聲明的變量作用于函數(shù)內(nèi),let聲明的變量作用與塊級作用域。
任何一對“大括號{ }”中的語句都屬于一個(gè)塊,在大括號里面用let定義的所有變量在大括號外是不可見的,我們稱之為塊級作用域。
2.用var聲明變量的時(shí)候會導(dǎo)致“變量提升”。
JavaScript的函數(shù)定義有個(gè)特點(diǎn),它會先掃描整個(gè)函數(shù)體的語句,把所有申明的變量“提升”到函數(shù)頂部:
'use strict';
function foo() {
var x = 'Hello, ' + y;
alert(x);
var y = 'Bob';
}
foo();
雖然是strict模式,但語句var x = 'Hello, ' + y;并不報(bào)錯(cuò),原因是變量y在稍后申明了。但是alert顯示Hello, undefined,說明變量y的值為undefined。這正是因?yàn)镴avaScript引擎自動提升了變量y的聲明,但不會提升變量y的賦值。
對于上述foo()函數(shù),JavaScript引擎看到的代碼相當(dāng)于:
function foo() {
var y; // 提升變量y的申明
var x = 'Hello, ' + y;
alert(x);
y = 'Bob';
}
如果用let重寫foo():
'use strict';
function foo() {
var x = 'Hello, ' + y;
alert(x);
let y = 'Bob';
}
foo(); //結(jié)果:報(bào)錯(cuò) y is not defined
用let關(guān)鍵字來定義y;這樣y在代碼塊內(nèi)就不會提升了。報(bào)錯(cuò)是因?yàn)橛胠et聲明的變量要先聲明再使用,上面代碼里未聲明定義就使用,就只有報(bào)錯(cuò)了。
使用let的注意點(diǎn):
注意1:同一個(gè)塊級作用域內(nèi),不允許重復(fù)聲明同一個(gè)變量。
// 錯(cuò)誤示范一:
{
var a =1;
let a =2; //報(bào)錯(cuò),因?yàn)閍已經(jīng)用var聲明過
}
// 錯(cuò)誤示范二:
{
let a =1;
let a= 2; //還是報(bào)錯(cuò),a已經(jīng)用let聲明過。
}
注意2:函數(shù)內(nèi)不能用let重新聲明函數(shù)的參數(shù)
// 錯(cuò)誤示范:
function say(word){
let word = 'hello Jack'; //報(bào)錯(cuò):用let重新聲明word參數(shù)
alert(word)
}
say('hello Lili');
// 函數(shù)內(nèi)用let重新聲明word這個(gè)參數(shù),會報(bào)錯(cuò)的,千萬別這么干。
2. const關(guān)鍵字
const 的作用
const是constant(常量)的縮寫,const和let一樣,也是用來聲明變量的,但是const是專門用于聲明一個(gè)常量的,顧名思義,常量的值是不可改變的。
常量的特點(diǎn):
1、不可修改
const Name = '張三';
Name = '李四'; // 錯(cuò)誤,企圖修改常量Name
2、只在塊級作用域起作用,這點(diǎn)與let關(guān)鍵字一樣。
if(1){
const Name = '張三';
}
alert(Name); //錯(cuò)誤,在代碼塊{ }外,Name失效
3、不存在變量提升,必須先聲明后使用,這點(diǎn)也跟let關(guān)鍵字一樣。
if(1){
alert(Name);//錯(cuò)誤,使用前未聲明
const Name = '張三';
}
4、不可重復(fù)聲明同一個(gè)變量,這點(diǎn)跟let也一樣。
var Name = '張三';
const Name = '李四';//錯(cuò)誤,聲明一個(gè)已經(jīng)存在的變量Name
5、聲明后必須要賦值
const NAME; //錯(cuò)誤,只聲明不賦值
使用const的注意點(diǎn):
const Person = {"name":"張三"};
Person.name = "李四";
Person.age = 20;
console.log(Person);
//結(jié)果:正常輸出{name: "李四", age: 20}
如上常量是一個(gè)對象,常量是可以修改的,為什么呢?
這里用到了傳址賦值,什么叫傳址賦值?
傳址:在賦值過程中,變量實(shí)際上存儲的是數(shù)據(jù)的地址(對數(shù)據(jù)的引用),而不是原始數(shù)據(jù)或者數(shù)據(jù)的拷貝。
用const來聲明一個(gè)對象類型的常量,就是傳址賦值。而不可修改的是對象在內(nèi)存中的地址,而不是對象本身。
所以,這就很好的解釋剛剛的這段代碼為什么不會報(bào)錯(cuò),而是正常輸出了。
上面代碼中修改的只是Person本身,修改的是name屬性和增加一個(gè)屬性age,而地址沒變,也不可變,所以并沒有違背常量不可修改的約定。
但是,如果這樣寫呢,就會報(bào)錯(cuò):
const Person = {"name":"張三"};
Person.age = 20;
Person = {};
//錯(cuò)誤,企圖給常量Person賦新值(新地址)

3. 解構(gòu)賦值
官方的解釋:
ES6允許按照一定模式,從數(shù)組和對象中提取值,對變量進(jìn)行賦值,這被稱為解構(gòu)(Destructuring)。
上一段代碼進(jìn)一步解釋一下什么叫解構(gòu)賦值:
var arr = [1,2,3]; // 把數(shù)組的值分別賦給下面的變量;
var a = arr[0];
var b = arr[1];
var c = arr[2];
console.log(a); // a的值為1
console.log(b); // b的值為2
console.log(c); // c的值為3
以上是傳統(tǒng)的變量賦值,將數(shù)組的元素值1,2,3分別賦值給變量a,b,c,結(jié)果也是如我們所愿,賦值成功。
var [a,b,c] = [1,2,3]; //把數(shù)組的值分別賦給下面的變量;
console.log(a); // a的值為1
console.log(b); // b的值為2
console.log(c); // c的值為3
以上是變量的解構(gòu)賦值,賦值的代碼減少了,只需要將變量a,b,c作為一個(gè)數(shù)組的元素,然后將數(shù)組[1,2,3]賦值給數(shù)組[a,b,c]即可,變量a,b,c即可分別得到對應(yīng)的值,這種叫做數(shù)組的解構(gòu)賦值。
數(shù)組的解構(gòu)賦值注意點(diǎn):
1、結(jié)構(gòu)賦值可以嵌套的
var [ a,b,[ c1,c2 ] ] = [ 1,2,[ 3.1,3.2 ] ];
console.log(c1); // 結(jié)果:c1的值為3.1
console.log(c2); // 結(jié)果:c2的值為3.2
2、不完全解構(gòu)
var [a,b,c] = [1,2];
console.log(a); // 結(jié)果:a的值為1
console.log(b); // 結(jié)果:b的值為2
- 賦值不成功,變量的值為undefined
var [a,b,c] = [1,2];
console.log(a); // 結(jié)果:a的值為1
console.log(b); // 結(jié)果:b的值為2
console.log(c); // 結(jié)果:c的值為undefined
- 允許設(shè)定默認(rèn)值
var [a,b,c=3] = [1,2];
console.log(a); // 結(jié)果:a的值為1
console.log(b); // 結(jié)果:b的值為2
console.log(c); // 結(jié)果:c的值為3
- 重新賦值會覆蓋默認(rèn)值
var [a,b,c=3] =[1,2,4];
console.log(a); // 結(jié)果:a的值為1
console.log(b); // 結(jié)果:b的值為2
console.log(c); // 結(jié)果:c的值為4
?? 注意:當(dāng)新的值為undefined的時(shí)候,是不會覆蓋默認(rèn)值的。
對象的解構(gòu)賦值
對象的解構(gòu)賦值跟數(shù)組的解構(gòu)賦值很類似,上代碼:
var {a, b, c} = {a: 1, b: 2, c: 3};
console.log(a); // 結(jié)果:a的值為1
console.log(b); // 結(jié)果:b的值為2
console.log(c); // 結(jié)果:c的值為3
對象的解構(gòu)賦值不會受到屬性的排列次序影響(數(shù)組則會受影響),它是跟屬性名關(guān)聯(lián)起來的,變量名要和屬性名一致,才會成功賦值。
var { a, b, c } = {a: 1, c: 3, b: 2};
console.log(a); // 結(jié)果:a的值為1
console.log(b); // 結(jié)果:b的值為2
console.log(c); // 結(jié)果:c的值為3
如果變量找不到與其名字相同的屬性,就會賦值不成功:
var { a } = {"b":2};
console.log(a); // 結(jié)果:a的值為undefined
?? 變量名與屬性名不一樣的變量解構(gòu)賦值:
var { b: a} = {b: 2};
console.log(a); // 結(jié)果:a的值為2
對象的結(jié)構(gòu)賦值注意點(diǎn):
1、對象解構(gòu)賦值可以嵌套
var {a: } = {a: {b: 1}};
console.log(b); // 結(jié)果:b的值為1
2、可以指定默認(rèn)值
var {a, b=2} = {a: 1};
console.log(b); // 結(jié)果:b的值為默認(rèn)值2
字符串的解構(gòu)賦值
除了對象和數(shù)組可以解構(gòu)賦值外,字符串也可以結(jié)構(gòu)賦值,上代碼:
var [a, b, c, d, e, f] = "熱忱一直在!";
console.log(a); // 熱
console.log(b); // 忱
console.log(c); // 一
console.log(d); // 直
console.log(e); // 在
console.log(f); // !
解構(gòu)賦值的用途
一、交換變量的值
var x = 1;
var y = 2;
[x, y] = [y, x];
簡單的一行代碼即可成功交換x,y的值。
二、提取函數(shù)返回的多個(gè)值
函數(shù)只能返回一個(gè)值,我們可以將多個(gè)值裝在一個(gè)數(shù)組或者對象中,再用解構(gòu)賦值獲取其中的值。
function foo(){
return {name: "neo", age: 31}
}
var {name, age} = foo();
console.log(name); // 結(jié)果:neo
console.log(age); // 結(jié)果:31
將foo()的返回值直接通過結(jié)構(gòu)賦值賦給變量name和age,實(shí)現(xiàn)快速的提取對應(yīng)的值。
三、定義函數(shù)參數(shù)
function foo({name, age}){
console.log(`姓名:${name}`);
console.log(`年齡:${age}`);
}
foo({name: "neo", age: "31", sex: "male"});
通過這種寫法, 很方便就能獲取JSON對象中想要的參數(shù),例如案例中,只需要獲取實(shí)參中的:name,age而不需要管其他的參數(shù)。