2.ES6-解構賦值及其原理-解構看完這篇足夠了

所謂的解構賦值其實就是分解出一個對象的解構,分成兩個步驟:
1. 變量的聲明
2. 變量的賦值


一、 數組的解構賦值

/*
	對於數組的解構賦值,其實就是獲得數組的元素,而我們一般情況下獲取數組元素的方法是通過下標獲取,例如:
		let arr = [1,2,3];
		let a = arr[0];
		let b = arr[1];
		let c = arr[2];
	而數組的解構賦值給我們提供了極其方便的獲取方式,如下:
*/

	let arr0 = [1,2,3];
	let [a,b,c] = arr0;
	console.log(a,b,c);//1,2,3
	
1.模式匹配解構賦值
let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo,bar,baz);//1,2,3
2. 省略解構賦值
let [,,a,,b] = [1,2,3,4,5];
console.log(a,b);//3,5
3.含剩餘參數的解構賦值
let [a,...reset] = [1,2,3,4,5];
console.log(a,reset);//1,[2,3,4,5]

其轉成ES5的原理如下:

var a = 1,
    reset = [2, 3, 4, 5];
console.log(a,reset);//1,[2,3,4,5]
注意:如果剩餘參數是對應的值爲undefined,則賦值爲[],因爲找不到對應值的時候,是通過slice截取的,如下:
let [a,...reset] = [1];
console.log(a,reset);//1,[]

其轉成ES5的原理如下:

var _ref = [1],
    a = _ref[0],
    reset = _ref.slice(1);
console.log(a,reset);//1,[]
  1. 非數組解構成數組(重點,難點)

一條原則:要解構成數組的前提:如果等號右邊,不是數組(嚴格地說,不是可遍歷的解構),則直接報錯,例如:

let [foo] = 1;//報錯
let [foo1] = false;//報錯
let [foo2] = NaN;//報錯
let [foo3] = undefined;//報錯
let [foo4] = null;//報錯
let [foo5] = {};//報錯

爲什麼?轉成ES5看下原理就一清二楚了:

var _ = 1,
	foo = _[0];//報錯
var _false = false,
	foo1 = _false[0];//報錯
var _NaN = NaN,
	foo2 = _NaN[0];//報錯
var _undefined = undefined,
	foo3 = _undefined[0];//報錯
var _ref= null;
	foo4 = _ref[0];//報錯
var _ref2 = {},
	foo5 = _ref2[0];//報錯
5. Set的解構賦值

先執行new Set()去重,然後對得到的結果進行解構

let [a,b,c] = new Set([1,2,2,3]);
console.log(a,b,c);//1,2,3
6. 迭代器解構
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
《來自阮一峯教程》

總結1:只要某種數據結構具有 Iterator 接口,都可以採用數組形式的解構賦值。

7.解構賦值的默認值

當變量嚴格等於undefined的時候,會讀取默認值,所謂的嚴格等於,就是“===”



----------


let [a,b = 'default'] = [1];
console.log(a,b);//1,'default'


----------


let [c = 'default'] = [undefined];
console.log(c);//'default'


----------


function f() {
  console.log('aaa');
}

let [x = f()] = [1];
console.log(x);//1


----------
function f() {
  console.log('aaa');//'aaa'
}

let [a,x = f()] = [1];
console.log(a,x);//1,undefined

總結2:如果不使用默認值,則不會執行默認值的函數


二、對象的解構賦值

1. 解構賦值的舉例:
	let p1 = {
		"name":"zhuangzhuang",
		"age":25
	}
	let {name,age} = p1;//注意變量必須爲屬性名
	console.log(name,age);//"zhuangzhuang",25

其轉成es5的原理則爲:

	var _p1 = p1,
	name = _p1.name,
	age = _p1.age;
	console.log(name,age);//"zhuangzhuang",25
2. 解構賦值的別名

如果使用別名,則不允許再使用原有的解構出來的屬性名,看以下舉例則會明白:

	let p1 = {
		"name":"zhuangzhuang",
		"age":25
	}
	let {name:aliasName,age:aliasAge} = p1;//注意變量必須爲屬性名
	console.log(aliasName,aliasAge);//"zhuangzhuang",25
	console.log(name,age);//Uncaught ReferenceError: age is not defined

爲何打印原有的屬性名則會報錯?讓我們看看轉成es5後的原理是如何實現的:

	var _p1 = p1,
		aliasName = _p1.name,
		aliasAge = _p1.age;
	console.log(aliasName,aliasAge);//"zhuangzhuang",25
	console.log(name,age);//所以打印name和age會報錯——“Uncaught ReferenceError: age is not defined”,但是爲何只報錯age,不報錯name呢?

只報錯age,不報錯name,這說明其實name是存在的,那麼根據js的解析順序,當在當前作用域name無法找到時,會向上找,直到找到window下的name,而我們打印window可以發現,其下面確實有一個name,值爲“”,而其下面並沒有屬性叫做age,所以在這裏name不報錯,只報age的錯。類似name的屬性還有很多,比如length等。

3.解構賦值的默認值

有些情況下,我們解構出來的值並不存在,所以需要設定一個默認值,例如:

	let obj = {
		name:"zhuangzhuang"
	};
	let {name,age} = obj;
	console.log(name,age);//"zhuangzhuang",undefined

我們可以看到當age這個屬性並不存在於obj的時候,解構出來的值爲undefined,那麼爲了避免這種尷尬的情況,我們常常會設置該屬性的默認值,如下:

	let obj = {
		name:"zhuangzhuang"
	};
	let {name,age = 18} = obj;
	console.log(name,age);//"zhuangzhuang",18

當我們取出來的值不存在,即爲undefined的時候,則會取默認值(假設存在默認值),ES6的默認值是使用**“變量=默認值”**的方式。
注意:只有當爲undefined的時候纔會取默認值,null等均不會取默認值

	let obj = {
		name:"zhuangzhuang",
		age:27,
		gender:null,//假設未知使用null
		isFat:false
	}
	let {name,age = 18,gender = 'man',isFat = true,hobbies = 'study'} = obj;
	console.log(name,age,gender,isFat,hobbies);//"zhuangzhuang",27,null,false,"study"
4. 解構賦值的省略賦值

當我們並不是需要取出所有的值的時候,其實可以省略一些變量,這就是省略賦值,如下

	let arr = [1,2,3];
	let [,,c] = arr;
	console.log(c);//3

注意:省略賦值並不存在與對象解構,因爲對象解構,明確了需要的屬性

	let obj = {
		name:"zhuangzhuang",
		age:27,
		gender:"man"
	}
	let {age} = obj;
	console.log(age);//27
5. 解構賦值的嵌套賦值(易錯點,重點,難點)
	let obj = {},
		arr = [];

	({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
	console.log(obj,arr);//{prop:123},[true]

注意當解構出來是undefined的時候,如果再給子對象的屬性,則會報錯,如下

let {foo: {bar}} = {baz: 'baz'};
//報錯,原因很簡單,看下原理即可,如下:
------
//原理:
let obj = {baz:"baz"};
let foo = obj.foo;//foo爲undefined
let bar = foo.bar;//undefined的bar,可定報錯
6. {}是塊還是對象?

當我們寫解構賦值的時候,很容易犯一個錯誤——{}的作用是塊還是對象混淆,舉例如下:

//舉例一:
let {a} = {a:"a"};
console.loh(a);//'a',這個很簡單
//很多人覺得,以下這種寫法也是可以的:
let a;
{a} = {a:"a"};//直接報錯,因爲此時a已經聲明過了,在語法解析的時候,會將這一行的{}看做塊結構,而“塊=對象”,顯然是語法錯誤,所以正確的做法是不將大括號寫在開頭,如下:
let a;
({a} = {a:"a"})
7. 空解構

按照之前寫的,解構賦值,左邊則爲解構出來的屬性名,當然,在這裏,我們也可以不寫任何屬性名稱,也不會又任何的語法錯誤,即便這樣沒有任何意義,如下:

({} = [true, false]);
({} = 'abc');
({} = []);
8.解構成對象的原則

如果解構成對象,右側不是null或者undefined即可!

之前說過,要解構成數組,右側必須是可迭代對象,但是如果解構成對象,右側不是null活着undefined即可!

此條如果不對,請聯繫我微信:809742006

三、字符串的解構賦值

字符串也是可以解構賦值的

	const [a, b, c, d, e] = 'hello';
	console.log(a,b,c,d,e);//'h','e','l','l','o'

轉成es5的原理如下:

	var _hello = 'hello',
    a = _hello[0],
    b = _hello[1],
    c = _hello[2];

	console.log(a, b, c);
注意:字符串有一個屬性length,也可以被解構出來,但是要注意,解構屬性一定是對象解構
	let {length} = 'hello';
	console.log(length);//5

4. 布爾值和數值的解構

布爾值和數值的解構,其實就是對其包裝對象的解構,取的是包裝對象的屬性

{toString:s} = 123;
console.log(s);//s === Number.prototype.toString

{toString:s} = true;
console.log(s);//s === Boolean.prototype.toString


總結:解構賦值的規則是:

>1. 解構成對象,只要等號右邊的值不是對象或數組,就先將其轉爲對象。由於undefined和null無法轉爲對象,所以對它們進行解構賦值,都會報錯。   
>2. 解構成數組,等號右邊必須爲可迭代對象
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章