(JS基礎)變量聲明、解構賦值和展開運算符

聲明變量

使用 var 、let 、const 均可以聲明變量,var 是咱們熟悉的就很少說,下面討論一下另外兩個。
javascript

let

在 ES6 以前的 JavaScript 是沒有塊級做用域。而 let 的誕生也帶來的塊級做用域。舉個例:java

function fn1() {
  for (let i of [1, 3, 2, 4, 5, 9]) { }
  console.log(i)
}
function fn2() {
  for (var i of [1, 3, 2, 4, 5, 9]) { }
  console.log(i)
}
fn1();    // 報錯,由於let聲明的變量有塊級做用域
fn2();    // 9
複製代碼

還有,let "修復"了 var 的變量提高(變量提高,意思是函數及變量的聲明都將被提高到函數的最頂部),即 let 聲明的變量不存在變量提高。看下例子:
node

console.log(b);    // undefined
var b = 10;
console.log(a);    // 報錯
let a = 10;複製代碼

除此,let 還會形成暫時性死區(即,只要塊級做用域內存在let命令,它所聲明的變量就"綁定"(binding)這個區域,再也不受外部的影響)。例子:json

var a = 1;
{
  // 報錯。由於變量"c"已經被綁定在此區域,且不能變量提高
  console.log(a);   
  let a = 2;
  // 暫時性死區內 重複聲明 會報錯
  var a = 3;
}複製代碼

const

const 其實與 let 基本一致,惟一不一樣的是,const 聲明時必須賦值。而 const 聲明的變量是不能被修改的。
數組

const a = 1;
a = 2;    // 報錯,常量不能被修改
複製代碼


解構賦值

按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構(Destructuring)。函數

基本語法

let { foo, baz } = { foo: 'a', bar: 'b' };  // foo='a' baz=undefined
let { foo: bar } = { foo: 'a', bar: 'b' };  // bar='a' 被從新命名
let [one, two] = [100, 200, 300];           // one=100 two=200複製代碼

對象的結構賦值中,等號左邊對象的"key"暫且稱爲"匹配器",等號左邊對象的"value"暫且稱爲"命名器",當二者相同時,可省略"命名鍵"。ui

執行解構賦值時,從等號右邊的對象的"key"尋找與"匹配器"匹配的屬性,找到則賦值,不然爲 undefined ,而"命名器"則做爲新變量的名字。如上例子中第二行,"foo"匹配對象的"foo"屬性,並複製到"bar"變量上,則有"bar='a'"。
spa

數組是特殊的對象,數組每項的"key"爲 0 開始遞增的整數,因此老是按順序匹配賦值。指針

下面針對 對象 的解構賦值詳細講解,數組則同理。
rest

嵌套賦值

let obj = { p: ['Hello', { y: 'World' }] };
let { p, p: [x, { y }] } = obj;
x  // "Hello"
y  // "World"
p  // ["Hello", {y: "World"}]

const node = { loc: { start: { line: 1, column: 5 } } };
let { loc, loc: { start }, loc: { start: { line } } } = node;
line    // 1
loc     // Object {start: Object}
start   // Object {line: 1, column: 5}

let arr = [], obj = {};
[arr[0], obj.prop] = [1, 2];
// arr = [1] obj = {prop: 2}複製代碼

解構默認值

var { x, y = 3 } = { x: 1 };         // x = 1 y = 3
var { x, y = 3 } = { x: 1, y=2 };    // x = 1 y = 2
// 使用"命名器"也能夠設定默認值
var { x, y:a = 3 } = { x: 1 };       // x = 1 a = 3複製代碼

函數參數解構

本質是[x,y,...] = arguments的解構賦值。上面的解構默認值和嵌套賦值同理可用。

// 本質是 {x,y}=arguments[0] 的解構賦值
function fn({x, y}) { }複製代碼

幾種經常使用的用途

  1. 函數的傳參(上面已講解)。
  2. 交換賦值
    • let x = 1, y = 2;
      [x, y] = [y, x];複製代碼
  3. 提取 JSON 對象中的數據
    • let jsonData = { id: 12, name: 'lisi', data: '...' }
      let { id, name, data: num } = jsonData;複製代碼
  4. 遍歷 map 對象
    • const map = new Map();
      map.set('first', 'hello');
      map.set('second', 'world');
      for (let [key, value] of map) {
        console.log(key + " is " + value);
      }複製代碼
  5. require 加載模塊時指定別名
    • const { SourceMapConsumer, SourceNode } = require("source-map");複製代碼


展開運算符(...)

展開運算符(spread)是三個點(...)。比如把對象的"{}"去掉,數組則是去掉"[]"。

基本語法

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };    // x=1 y=2 z={a:3,b:4}
let arr = [...[1, 2, 3], 4];                        // arr=[1,2,3,4]
let obj = { ...{ x: 1, y: 2 }, z: 3 }               // obj={x:1,y:2,z:3}
複製代碼

在數組中的應用

  1. 淺複製:(數組內含有數組,則只複製內數組的指針)
    • const arr = [1, 2, 3];
      const newArr = [...arr];    // newArr=[1,2,3]
      複製代碼
  2. 合併數組
    • const
        arr1 = ['a', 'b'],
        arr2 = ['c'],
        arr3 = ['d', 'e'];
      let arr = [...arr1, ...arr2, ...arr3];    // arr=['a','b','c','d','e']
      複製代碼
  3. 與解構賦值結合:(注意,使用展開運算符的對象必須在最後
    • const [first, ...rest] = [1, 2, 3, 4, 5];    // first=1 rest=[2,3,4,5]
      const [first, ...rest] = ["foo"];            // first=1 rest=[]
      const [...rest, first] = ["foo"];            // 報錯
      複製代碼
  4. 字符串
    • let strs = [...'hello'];    // strs=["h","e","l","l","o"]
      // 快速翻轉字符串
      let newStr = [...'hello'].reverse().join();    // "olleh"
      複製代碼
  5. 類數組轉換成數組
    • // 任何定義了遍歷器(Iterator)接口的對象,均可以用擴展運算符轉爲真正的數組。
      let nodeList = document.querySelectorAll('div');
      let array = [...nodeList];
      複製代碼

在對象中的應用

  1. 淺複製:(和數組同樣,對象內的對象只能複製指針)
    • let obj1 = { a: 3, b: 4 };
      let obj2 = { ...obj1 };    // obj2={a:3,b:4}複製代碼
  2. 字符串
    • let strs = {...'hello'}    // strs={0:"h",1:"e",2:"l",3:"l",4:"o"}複製代碼
  3. 用於數組
    • let foo = { ...['a', 'b', 'c'] };    // foo={0:"a",1:"b",2:"c"}複製代碼
  4. 對象合併:(只能合併對象內可枚舉的,非繼承的屬性。且後者會覆蓋前者同名屬性
    • let
        a = { x: 1, y: 2 },
        b = { y: 3, z: 4 };
      let ab = { ...a, ...b };            // ab={ x:1,y:3,z:4}
      // 等同於
      let ab1 = Object.assign({}, a, b);  // ab={ x:1,y:3,z:4}
      複製代碼
相關文章
相關標籤/搜索