上接 ES6 - 基礎學習(3): 變數的解構賦值 函數參數的解構賦值 1、基本用法 function add([x, y]) { return x + y; } console.log(add([1, 2])); // 3 // 如上面代碼所示,函數add的形參錶面是一個數組,但在實參參數傳入時, ...
函數參數的解構賦值
1、基本用法
function add([x, y]) { return x + y; } console.log(add([1, 2])); // 3 // 如上面代碼所示,函數add的形參錶面是一個數組,但在實參參數傳入時,實參數組就被解構並賦值給變數x、y了。當然這些對於函數內部的代碼來說,跟參數一個個傳入是一樣的,反正都只認參數x、y [[1, 2], [3, 4]].map(([a, b]) => a + b); console.log([[1, 2], [3, 4]].map(([a, b]) => a + b)); // [3, 7] 1+2=3,3+4=7 map函數以二維數組內每個成員數組作為參數,進行參數解構,然後計算每個成員數組內參數值之和
2、函數參數的解構也可以使用預設值
// 下麵代碼中,函數defaultParameter的形參是一個對象(空對象)。通過對這個對象進行解構,得到變數x、y的值,如果解構失敗,x、y就等於預設值。 function defaultParameter({x = 0, y = 0} = {}) { console.log([x, y]); return [x, y]; }
defaultParameter({x: 1, y: 2}); // [1, 2] defaultParameter({x: 3}); // [3, 0] defaultParameter({}); // [0, 0] defaultParameter(); // [0, 0] // 註意,下麵這種寫法會得到不一樣的結果。區別在於此處是給參數指定預設值,而不是給變數x、y指定預設值。 // 這兩種寫法的執行區別是:上一種寫法 實參傳入函數後,實參對象內沒有對應屬性的值,則函數參數採用變數已有的預設值進行相關處理,代碼依然能正常執行,不會報錯。 // 而下一種寫法 實參傳入函數後,實參對象內沒有對應屬性的值,則就真沒有了,函數參數因為解構賦值操作,無對應屬性值的變數就只能等於undefined。這時如果再執行代碼,尤其是計算類相關操作,執行就會報錯,代碼就會中斷執行。 function defaultParameter({x, y} = {x: 0, y: 0}) { console.log([x, y]); return [x, y]; }
defaultParameter({x: 1, y: 2}); // [1, 2] defaultParameter({x: 3}); // [3, undefined] defaultParameter({}); // [undefined, undefined] defaultParameter(); // [0, 0] 沒有傳入參數,函數以預設對象進行解構賦值
// undefined會觸發函數參數的預設值。 [1, undefined, 3].map((x = 'yes') => x); console.log([1, undefined, 3].map((x = 'yes') => x)); // [1, "yes", 3]
圓括弧問題
解構賦值雖然使用很方便,但是解析起來卻不容易。對於編譯器來講,一個式子到底是模式,還是表達式,一開始並不知道,只有等到解析到(或解析不到)等號時才能知道。而由此帶來的問題,如果模式中出現圓括弧怎麼處理。
ES6的規則是,只要一個式子中有可能出現解構操作 或 可能讓解構操作產生歧義的,就不得使用圓括弧。
但是,這條規則實際操作起來卻不那麼容易辨別,處理起來也相當麻煩。因此,建議在實際開發中,除非很有必要,否則就不要在模式中放置圓括弧。
// 以下三種解構賦值不得使用圓括弧。 // 變數聲明語句,模式不能使用圓括弧 let [(a)] = [1]; let {x: (c)} = {}; let ({x: c}) = {}; let {(x: c)} = {}; let {(x): c} = {}; let { o: ({ p: p }) } = { o: { p: 2 } }; // 函數參數也屬於變數聲明,因此不能帶有圓括弧 function f([(z)]) { return z; } function f([z,(x)]) { return x; } // 賦值語句的模式 ({ p: a }) = { p: 42 }; // 將整個模式放在圓括弧之中,導致報錯 ([a]) = [5]; [({ p: a }), { x: c }] = [{}, {}]; // 將一部分模式放在圓括弧之中,導致報錯
// 可以使用圓括弧的情況只有一種:賦值語句的非模式部分,可以使用圓括弧。 // 下麵三行語句圓括弧使用正常,代碼執行也正確。因為它們都是賦值語句,而不是聲明語句;其次它們的圓括弧都不屬於模式的一部分。 // 第一行語句中,模式是取數組的第一個成員,跟圓括弧無關;第二行語句中,模式是p,而不是d;第三行語句與第一行語句的性質相同。 [(b)] = [3]; ({p: (d)} = {}); [(parseInt.prop)] = [3];
解構賦值的用途
變數的解構賦值用途很多
1、變數值交換
let x = 1, y = 2; [x, y] = [y, x]; console.log(x); // 2 console.log(y); // 1
2、函數返回多個值
// JS中,一個函數一次只能返回一個值,如果想要返回多個值,則只能將 需要返回的值封裝在數組或對象里一起返回,而且返回後取值還是一個麻煩問題。但有瞭解構賦值,取出這些值就方便很多了。 function returnsArray() { return [1, 2, 3]; // 返回一個數組 } let [a, b, c] = returnsArray(); console.log(a); // 1 console.log(c); // 3 function returnsObject() { return { // 返回一個對象 name: 'ES6', description: 'ES6解構賦值 補充' }; } let {name, description} = returnsObject(); console.log(name); // ES6 console.log(description); // ES6解構賦值 補充
3、函數參數的定義
// 解構賦值可以很方便地將一組參數與變數名對應起來。 // 參數是一組有次序的值:數組 function testFunc([x, y, z]) { console.log(x, y, z); // 1 2 3 } testFunc([1, 2, 3]); // 參數是一組無次序的值:對象 function test_func({x, y, z}) { console.log(x, y, z); // 1 2 3 } test_func({z: 3, x: 1, y: 2,});
4、函數參數的預設值
// 參數是一組有次序的值:數組 function testFunc([x = 0, y = 0, z = 0]) { console.log(x + y + z); } testFunc([1, 2]); // 3 實參 少於 形參個數,形參取預設值 testFunc([123, 234, 345]); // 702 實參 等於 形參個數,形參按位置對應取值 testFunc([12, 23, 34, 45]); // 69 實參 多餘 形參個數,形參按位置對應取值,多餘剩下的不管。 // 參數是一組無次序的值:對象 function test_func({x = 0, y = 0, z = 0}) { console.log(x + y + z); } test_func({x: 1, y: 2}); // 3 實參對象內屬性名 與 形參變數名不能一一對應(屬性名個數和變數個數不等),未能正確匹配的形參變數 取預設值 test_func({x: 1, y: 2, z: 3}); // 6 實參對象內屬性名 與 形參變數名一一對應,形參變數 按名一一對應 取值 test_func({x: 1, y: 2, aa: 4}); // 3 實參對象內屬性名 與 形參變數名不能一一對應(屬性名個數和變數個數相等),未能正確匹配的形參變數 取預設值
5、提取 JSON 數據
// 解構賦值對快速提取 JSON 對象中的數據,尤其有用。 let jsonData = { name: 'ES6', description: 'ES6解構賦值 補充', time: [2015, 6] }; let {name, description, time: number} = jsonData, [year, month] = number; console.log(name); // ES6 console.log(description); // ES6解構賦值 補充 console.log(year); // 2015 console.log(month); // 6
6、獲取 Set 數據結構內數據、 遍歷 Map 數據結構
// Set數據結構是ES6新增的一種數據結構,是一種類數組 數據結構,只是Set結構實例內各個成員是唯一的,不允許重覆。 // Map則是ES6新增的另一種數據結構,是一種類對象 數據結構,同樣Map實例內的屬性也不允許重覆,而且Map結構內 屬性欄位不限數據類型。 // 任何部署了 Iterator介面的對象,都可以用 for...of 迴圈遍歷。Map結構原生支持 Iterator介面,配合變數的解構賦值,可以更方便的獲取鍵名和鍵值。 let tempSet = new Set([1, 2, 'name', 'description']); console.log(tempSet); // Set(4) {1, 2, "name", "description"} let [a, b, c, e] = tempSet; console.log(a); // 1 console.log(b); // 2 console.log(c); // name console.log(e); // description let tempMap = new Map(); tempMap.set('name', 'ES6').set('description', 'ES6解構賦值 補充'); for (let [key, value] of tempMap) { console.log(key + " is " + value); } // 若只想獲取鍵名,或只想獲取鍵值,都可以。 for (let [key] of tempMap) { console.log(`鍵名: ${key}`); // 遍歷鍵名 } for (let [, value] of tempMap) { console.log(`鍵值: ${value}`); // 遍歷鍵值 }
7、輸入模塊的指定方法
載入其他模塊時,如果不想載入整個模塊,則可以通過解構賦值的方式指定輸入要載入的方法,從而既可以減少依賴載入,又可以使得輸入語句清晰明瞭。
const {SourceMapConsumer, SourceNode} = require("source-map");