TypeScript 解(jie)構
⒈解構數組
最(zui)簡單的(de)解構莫過于數組的(de)解構賦值了:
let input = [1, 2];
let [first, second] = input;
console.log(first); // outputs 1
console.log(second); // outputs 2
這創建了2個命名變量 first 和 second。 等價于(yu)下(xia)面(mian)使用了索(suo)引的代碼,但更為(wei)方便(bian):
first = input[0];
second = input[1];
解(jie)構作(zuo)用(yong)于已聲明的變量會更(geng)好(hao):
// swap variables
[first, second] = [second, first];
作用于(yu)函數參數:
function f([first, second]: [number, number]) {
console.log(first);
console.log(second);
}
f(input);
你可以在數組里使用...語法創建剩余變量:
let [first, ...rest] = [1, 2, 3, 4];
console.log(first); // outputs 1
console.log(rest); // outputs [ 2, 3, 4 ]
當然,由于是JavaScript, 你可以(yi)忽略你不關心的尾隨元素:
let [first] = [1, 2, 3, 4];
console.log(first); // outputs 1
或其它元素:
let [, second, , fourth] = [1, 2, 3, 4];
⒉對象解構
你也可以(yi)解構(gou)對象:
let o = {
a: "foo",
b: 12,
c: "bar"
};
let { a, b } = o;
這通過 o.a and o.b 創建了 a 和 b 。 注意,如果你不需要 c 你可以忽略它。
就像數組解構,你可以用沒有聲明的賦值:
({ a, b } = { a: "baz", b: 101 });
注意,我們需要用括號將它括起來,因為Javascript通常會將以 { 起始的語句解析為一個塊。
你可以在對象里使用...語法創建剩余變量:
let { a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;
⒊屬性重命名
你也可以給(gei)屬性以不同(tong)的名字:
let { a: newName1, b: newName2 } = o;
這里的語法開始變得混亂。 你可以將 a: newName1 讀做 "a 作為 newName1"。 方向是從左(zuo)到右,好像你寫成了(le)以下樣子:
let newName1 = o.a;
let newName2 = o.b;
令人困惑的是,這里的冒號不是指示類(lei)型的。 如果你想指定它的類(lei)型, 仍然需要(yao)在其后寫上完(wan)整的模式。
let {a, b}: {a: string, b: number} = o;
⒋默認值
默認(ren)值可以讓你(ni)在屬性為 undefined 時使用缺省值:
function keepWholeObject(wholeObject: { a: string, b?: number }) {
let { a, b = 1001 } = wholeObject;
}
現在,即使 b 為 undefined , keepWholeObject 函數的變量 wholeObject 的屬性 a 和 b 都會有(you)值。
⒌解構函數聲明
解(jie)構(gou)也能用于函數聲明。 看以下簡單的(de)情況:
type C = { a: string, b?: number }
function f({ a, b }: C): void {
// ...
}
但是,通常(chang)情(qing)況下更多的是指(zhi)定(ding)默(mo)認(ren)值,解(jie)構默(mo)認(ren)值有些棘手。 首先,你需要在默(mo)認(ren)值之前設置其(qi)格式(shi)。
其次,你需要知道在解構屬性上給予一個默認或可選的屬性用來替換主初始化列表。 要知道 C 的定義有一個 b 可選屬性(xing):
function f({ a, b = 0 } = { a: "" }): void {
// ...
}
f({ a: "yes" }); // ok, default b = 0
f(); // ok, default to {a: ""}, which then defaults b = 0
f({}); // error, 'a' is required if you supply an argument
要小(xiao)心使用(yong)解(jie)構(gou)。 從(cong)前面的(de)(de)(de)例子可以(yi)(yi)看出,就算是(shi)(shi)最簡單(dan)的(de)(de)(de)解(jie)構(gou)表(biao)達式也是(shi)(shi)難以(yi)(yi)理(li)解(jie)的(de)(de)(de)。 尤其當存在深層嵌套解(jie)構(gou)的(de)(de)(de)時候(hou),就算這時沒有堆疊在一起(qi)的(de)(de)(de)重命名,默認值和類(lei)型注解(jie),也是(shi)(shi)令人難以(yi)(yi)理(li)解(jie)的(de)(de)(de)。 解(jie)構(gou)表(biao)達式要盡量保持(chi)小(xiao)而(er)簡單(dan)。 你自己也可以(yi)(yi)直接使用(yong)解(jie)構(gou)將會生成的(de)(de)(de)賦值表(biao)達式。
⒍展開
展(zhan)開(kai)(kai)操作(zuo)符正與解構相反。 它(ta)允許你將(jiang)一(yi)(yi)個數組(zu)展(zhan)開(kai)(kai)為(wei)另(ling)一(yi)(yi)個數組(zu),或將(jiang)一(yi)(yi)個對(dui)象(xiang)展(zhan)開(kai)(kai)為(wei)另(ling)一(yi)(yi)個對(dui)象(xiang)。 例如(ru):
let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];
這會令bothPlus的值為[0, 1, 2, 3, 4, 5]。 展開操作創建了 first和second的一份淺(qian)拷貝。 它們不會被展開操作(zuo)所改變(bian)。
你還可以展開對象:
let defaults = { food: "spicy", price: "$$", ambiance: "noisy" };
let search = { ...defaults, food: "rich" };
search的值為{ food: "rich", price: "$$", ambiance: "noisy" }。 對(dui)象(xiang)的(de)(de)展(zhan)(zhan)開(kai)比數組的(de)(de)展(zhan)(zhan)開(kai)要(yao)復雜的(de)(de)多。 像數組展(zhan)(zhan)開(kai)一樣,它是從左至右進行處理(li),但結果仍(reng)為對(dui)象(xiang)。 這(zhe)就意(yi)味(wei)著出現在展(zhan)(zhan)開(kai)對(dui)象(xiang)后面(mian)的(de)(de)屬性會覆蓋(gai)前面(mian)的(de)(de)屬性。 因此(ci),如果我(wo)們修改上面(mian)的(de)(de)例子,在結尾(wei)處進行展(zhan)(zhan)開(kai)的(de)(de)話:
let defaults = { food: "spicy", price: "$$", ambiance: "noisy" };
let search = { food: "rich", ...defaults };
那么,defaults里的food屬性會重寫food: "rich",在這里這并不是我(wo)們(men)想要的結果。
對象(xiang)展開還有(you)其它一些意想不到的限制。 首先,它僅包含對象(xiang) 。 大(da)體上是說(shuo)當你(ni)展開一個對象(xiang)實(shi)例時,你(ni)會丟失(shi)其方法:
class C {
p = 12;
m() {
}
}
let c = new C();
let clone = { ...c };
clone.p; // ok
clone.m(); // error!
其次,TypeScript編譯器不允許展(zhan)開泛(fan)型(xing)函數上的類型(xing)參數。 這個特性會在TypeScript的未來版本中考慮實現。
