年都過去半個月了,我終於又從新開始更新了。雖然只是第二篇,可是我會繼續加油努力,必定不會放棄更新的。在文章中如有什麼不妥或者您有更多建議的話,歡迎和期待您給我留言,您的每個留言均可能成爲我進步的助力,十分感謝。那就廢話很少說直接開始吧。es6
解構賦值,顧名思義,就是解開一個結構,而後從裏面拿出值用來給變量賦值賦值。因此解構賦值主要是以數據類型來劃分的。ajax
var [a,b,c] = [1,2,3];
複製代碼
上述代碼算是最簡單的數組解構賦值,其實也能夠看作是數據的另外一種展現。好比上述代碼與下面的代碼實際上是同樣的。json
var a=1,b=2,c=3;
複製代碼
因此解構賦值最主要的做用,是可讓咱們簡化提取值的過程。數組
本質上,這種寫法屬於「模式匹配」,同模式下,左邊的變量就會被賦予對應位置的右邊的值。例如:bash
let [a,[[b],c]] = [1,[[2],3]];
a //1
b //2
c //3
複製代碼
而且只要模式相同,即使部分位置的變量或者值爲空,依舊能夠進行匹配。數據結構
let [a, , b] = [1,2,3];
a //1
b //3
let [a,b,c] = [1,2];
a//1
b//2
c//undefind
複製代碼
當解構不成功,即變量沒有獲得賦值,或者直接賦值undefind
時,變量的值就會等於undefind
。async
當匹配兩邊的模式相同,且長度不一樣時,此時的解構賦值被稱爲不徹底解構。雖然叫不徹底解構,可是依舊算解構成功的。函數
let [a,b] = [1,2,3];
a //1
b //2
複製代碼
上面一直提到一個前提狀況,那就是模式相同,沒錯,這是比較須要注意的一點。當兩邊模式不一樣時,解構賦值是會報錯的。ui
let [a] = 1;
let [b] = false;
let [c] = {};
複製代碼
在不嚴謹的狀況下,咱們能夠說,當兩邊的數據類型不一樣時,解構賦值會出現報錯。url
只要某種數據結構具備Iterator接口,均可以採用數組形式的解構賦值。Iterator接口最主要的功能是能夠提供遍歷命令for...of
使用,不難猜想,其實數組解構賦值是一個將變量遍歷循環,而後一一進行賦值的操做。
function* fibs() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
複製代碼
以上是阮一峯大神ES6入門裏面的實例,因爲我的目前還不清楚具體哪些數據結構具備Iterator
接口,因此這裏直接搬運一下。
let [a=1] = [];
a//1
複製代碼
解構賦值操做時,能夠設置一個默認值,若解構賦值操做室,對應位置上的值爲undefind
時,將會給變量賦值默認值。
須要注意的是,ES6內部使用嚴格相等運算符(===)來判斷一個位置是否有值,我通常習慣稱它爲全等符號。因此,與通常的判斷不一樣,這裏只有用於賦值的數組成員的值爲
undefined
(嚴格等於undefined
)時,默認值纔會生效。
let [a=1] = [undefined];
a//1
let [b=1] = [null];
b//null
let [c=1] = [NaN];
c//NaN
複製代碼
使用默認值時,還能夠引用解構賦值的其餘變量,但前提是該變量已聲明。
let [a=1,b=a] = [];
a//1
b//1
let [a=b,b=1] = [];
//ReferenceError: b is not defined
var [a=b,b=1] = [];
a//undefined
b//1
複製代碼
let { a,b } = { a:'1',b:'2'};
a //'1'
b //'2'
複製代碼
對象的解構賦值與數組的解構賦值最大的不一樣之處,在於數組的解構賦值,變量的取值是由位置決定的;而對象的解構賦值,變量的取值是由屬性名來決定的,只有變量與屬性名相同,才能夠取到值。
let { a , b } = { b : '2' , a : '1' };
a //1
b //2
let { a } = { b: '1' , c: '2' };
a//undefined
複製代碼
當變量名與屬性名不一致,卻又須要進行解構賦值時,可使用變量再進行一次解構賦值。
let obj = { a : '1' , b : '2' };
let { a : c , b : d } = obj;
c //'1'
d //'2'
複製代碼
而且,在這過程當中,實際被賦值的,實際上是c
和d
。而a
和b
是模式,起到相似於一箇中介做用,不會被實際賦值。
let { a : b } = { a : '1'};
a //ReferenceError: a is not defined
b //'1'
複製代碼
對象的解構賦值,與數組的解構賦值同樣,也能夠用於嵌套結構的對象。
let a = {
b : [
'1',
{ c : '2' }
]
};
let {
b : [
x ,
{ c }
]
} = a;
x // '1'
c // '2'
b // ReferenceError: b is not defined
複製代碼
此時b
只是模式,因此沒法被賦值。
對象的解構賦值也有默認值,默認值的設置方式與數組相同,而不是依舊使用對象的內部寫法。
let { a = 1} = {};
a // 1
let { b : 1 } = {};
//SyntaxError: Invalid destructuring assignment target
複製代碼
默認值生效的條件與數組的解構賦值相同,屬性值必須嚴格等於undefined
纔會生效。
let { a = 1 } = { a : undefined };
a //1
let { b = 1 } = { b : null };
b // null
let { c = 1 } = { c : NaN };
c // NaN
複製代碼
在對嵌套的對象使用解構賦值時,須要注意,若子對象所在的父屬性不存在時,會報錯。這也是我在工做中,發現比較常見的一種報錯,仍是須要多多注意的。特別是在使用多層結構的時候,例如res.data.id
。
let { a: {b} } = { c : '1' };
TypeError: Cannot destructure property `b` of 'undefined' or 'null'
複製代碼
在使用對象解構賦值的時候,若是要對已經聲明的變量進行解構賦值,須要當心。
let a;
{a} = {a:1};
//SyntaxError: Unexpected token =
複製代碼
這裏是由於JavaScript引擎會將{a}
當作一個代碼塊,從而引起語法錯誤。因此須要避免將大括號寫在行首。
let a;
({a} = {a:1});
a // 1
複製代碼
因爲數組的本質是特殊的對象,所以能夠對數組進行對象屬性的解構賦值。
let a = [1, 2, 3];
let {0 : b, 2: c} = a;
b // 1
c // 3
複製代碼
第二行代碼的0和2表明的是數組的位置,能夠簡單理解爲如下代碼:
let a = [1,2,3];
let b = a[0];
let c = a[2];
複製代碼
字符串也能夠進行解構賦值,由於此時字符串被轉換成了一個相似數組的對象。
let [a, b, c, d, e] = 'hello';
a // 'h'
b // 'e'
c // 'l'
d // 'l'
e // 'o'
複製代碼
看到這裏是否是感受這個過程有點眼熟,其實這個過程能夠理解爲如下代碼:
let x = 'hello';
a = x[0];
b = x[1];
c = x[2];
...
複製代碼
解構賦值時,若是等號右邊是數值或者布爾值,則會先轉化成對象。
let {toString:a} = 123;
a === Number.prototype.toString // true
let {toString:a} = 123;
a === Boolean.prototype.toString // true
複製代碼
解構賦值的規則是,若等號右邊的值不是對象或者數組,就會先將其轉化成對象。因爲
undefined
和null
沒法轉化成對象,因此對其進行解構賦值時會報錯。
let { a:b } = undefined;
//TypeError: Cannot destructure property `a` of 'undefined' or 'null'
let { a:b } = null;
//TypeError: Cannot destructure property `a` of 'undefined' or 'null'
複製代碼
function add({x,y]){
return x+y;
}
add({1,2}); //3
複製代碼
函數add
的參數表面上爲一個數組,可是在傳入參數的那一刻,數組參數就被解構成了2個變量,x
和y
。
函數參數的解構也能夠用默認值。
function move({x=0,y=0} = {} ) {
return [x,y];
}
move({x:1}); // [1,0];
move({}); // [0,0];
複製代碼
函數參數的解構有另外一種寫法,會得出另外一種結果。
function move({x,y} = {x:0,y:0} ) {
return [x,y];
}
move({x:1}); // [1,undefined];
move({}); // [undefined,undefined];
move(); // [0,0]
複製代碼
上述的代碼時爲move
函數參數設置默認值,而不是爲解構後的x
和y
設置默認值,因此會得出不同的結果。
在使用解構賦值的時候,圓括號是否使用,是一個問題。
ES6的規則中說明,只要有可能致使解構歧義的,就不能使用圓括號。
但因爲該規則的標準不容易衡量和辨別,因此通常是儘可能不使用圓括號。
變量聲明語句
let [(a)] = [1];
let {x: (c)} = {};
//上述兩句代碼顯示爲undefined
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
//上述四句代碼會報錯。
複製代碼
上述代碼發生這種狀況,主要是由於它們都是變量聲明語句,模式不能使用圓括號。
函數參數 函數參數也屬於變量聲明,所以不能帶圓括號。
function a( [ ( b ) ] ) { return c; }
複製代碼
賦值語句的模式
( { a:b } ) = { a:1 };
[ ({a:b}) , { c:d } ] = [{},{}];
複製代碼
不管是將整個模式放入圓括號中,仍是將部分模式放入圓括號中,都會致使報錯。
交換變量的值
let a = 1;
let b = 2;
[a,b] = [b,a]
複製代碼
從函數返回多個值
經過解構賦值,能夠很方便的從數組或者對象裏獲取多個返回值。
function arr(){
return [1,2,3];
}
let [a,b,c] = arr();
//返回一個數組
function arr() {
return {
a:1,
b:2
};
}
let { a,b } = arr();
複製代碼
函數參數的定義 解構賦值能夠方便地將一組參數與變量名對應起來。
// 參數是一組有次序的值
function f([a, b, c]) { ... }f([1, 2, 3]);
// 參數是一組無次序的值
function f({a, b, c}) { ... }f({z: 3, y: 2, x: 1});
複製代碼
提取JSON數據 在提取JSON對象中的數據時,解構賦值能起到很是簡便和快速的做用,使得代碼更加簡潔。
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
複製代碼
函數參數的默認值 經過使用解構賦值,在給函數參數賦予默認值時,整個代碼會顯得更加簡潔。
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// 在這裏設置默認值
} = {}) {
// 這裏則是賦值的內容,若爲undefined,則使用默認值
};
複製代碼
遍歷Map結構 上文說過,面對擁有Iterator
接口的對象時,可使用解構賦值。在這裏,咱們能夠經過解構賦值快速的獲取鍵名和鍵值。
const 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
複製代碼
輸入模塊的指定方法 加載模塊時,須要指定輸入哪些方法。解構賦值使得輸入語句很是清晰。
const { SourceMapConsumer, SourceNode } = require("source-map");
複製代碼
在使用解構賦值的時候,總體感受上其實就是一個遍歷過程的簡化。我的感受最大的做用是能夠將相似邏輯的代碼進行過程簡化,從而給代碼瘦身。
同時在其中也發現了原文章中的部分細節錯誤。例如不能使用圓括號的狀況中的第一點,示例代碼中的前兩行代碼並無報錯,而是顯示undefined
。
而後這裏給本身留一個小做業,是在和朋友聊上述細節錯誤時發現的一個問題:爲何let [(a)] = [1];
顯示undefined
,而用[(a)] = [1]
則會顯示[1]
?