ES6變數解構

打響武昌第二槍發表於2019-04-10

分享變數解構分3部分

  1. ES變數的宣告
  2. 變數的解構概念,用法,注意事項
  3. 可能在專案遇到的應用場景

第一部分變數的宣告

ES6之前

大家都瞭解JavaScript 中變數作用域的基本單元一直是 function,就是函式作用域, 如果建立塊級作用域的話就是要宣告立即呼叫函式

// 全域性作用域
var a = 2

// 塊級作用域,function (){

    var a = 3
    console.log(a)

 })()

 console.log(a)
複製程式碼
let 宣告

es新增2個宣告變數 let ,const方式, 只要在任意塊裡用這2個宣告方式宣告的都市塊級作用域變數, var,function宣告的還是函式作用域變數,塊的標誌是{...}這意味著我們只需要一對{ .. } 就可以建立一個作用域

var a = 2;

{

  let a = 3
  console.log( a );        // 3

}

console.log( a );          // 2
複製程式碼
const 宣告

用於建立常量。塊級變數宣告,這個變數的值在宣告時設定之後就不允許改變。 const 宣告必須要有顯式的初始化。如果需要一個值為 undefined 的常量,就要宣告 const a = undefined 。

{
   const a = 2;
   console.log( a );     // 2
   a = 3;                     // TypeError!
}
複製程式碼
塊作用域函式

從 ES6 開始,塊內宣告的函式,其作用域在這個塊內

{
   foo();         // 可以這麼做!
   function foo() {
    // ..
   }
}

foo();          // ReferenceError
複製程式碼
舉個列子

a = 1, 每隔1秒輸出a+1的值, 並賦值給a以此累加到值5為止

// 錯誤的
// 錯誤原因是 非同步執行時去找 i變數,此時i的值為 
for (var i = 1; i<=5;i++) {

    setTimeout(function(){
      console.log('i=>', i)
    }, i*1000)

}

// 利用之前的塊級作用域
for (var i = 1; i<=5;i++) {

      (function (i){
             //  原因相當於每次宣告一個i 來實現塊級
           setTimeout(function(){
               console.log('i=>', i)
           }, i*1000)

        })(i)

}

// 利用ES6的塊級申明
for (let i = 1;i<=5;i++) {
   // 相當於每次宣告 i 在塊內
   setTimeout(function(){
        console.log('i=>', i)
    }, i*1000)
}
複製程式碼
let,var,const注意事項

let,var 宣告且未賦值時預設值undefined,const必須顯示宣告 不會預設undefined

let  name = '張三',age 
var _name = '李四',_age
const __name = '王五', __age  // 報錯
複製程式碼

let ,const 不允許重複宣告

let a = 1
let a = 2  // 報錯
複製程式碼

let ,const 必須宣告後使用,如在宣告前呼叫會報錯,var宣告前使用值預設為undefined

console.log(a)       // undefined
console.log(b)      // 報錯
var a = 0
let  b = 1
複製程式碼
連續宣告賦值可採用陣列解構
  1. 物件
  2. 陣列
  3. 字串
  4. 數字
  5. 布林
  6. 類陣列 (arguments,Dom物件)
  7. set, map 其中字串,數字,布林都會有個轉成物件的過過程後面有例子

第二部分變數解構

把這個功能看作是一個結構化賦值(structured assignment)方法

  1. 什麼變數可解構?
  2. 何時賦值?
  3. 賦什麼位置的值?

什麼變數可使用賦值解構

可迭代的變數

物件解構

我們構造了一個手動賦值,把 foo() 返回物件中的值賦給獨立變數 x 、 y 和 z , 為了實現這一點,我們(不幸地)需要一個臨時變數 tmp,或者每次都呼叫一下函式 。 之前

function bar() {
  return {
          x: 4,
          y: 5,
          z: 6
         };
 }
var tmp = bar(),
x = tmp.x, y = tmp.y, z = tmp.z;
console.log( x, y, z );    // 4 5 6
tmp.x 屬性值賦給了變數 x ,同樣地, tmp.y 賦給了 y , tmp.z 賦給了 z 。
複製程式碼

之後

function bar() {
    return {
              x: 4,
              y: 5,
              z: 6
           };
 }
var { x, y, z } = bar();
console.log( x, y, z ); // 4 5 6

// 這裡可體現啦,物件賦什麼位置上的值
var {x: ban,  z: bap,  y: baz,} = bar()
console.log(ban,bap,baz)  // 4 6 5

// 先用x標識去右邊物件找到值  --> 然後把值付給ban變數, source = target 
// 剛好與什麼物件指定值相反 -->  target = source 

var testObj = {
     ban: x,
     bap:z,
     baz:y
   }
// 所以上面的實則是
var { x:x, y:y, z:z } = bar();
// 完全體現把物件賦給陣列
var o1 = { a: 1, b: 2, c: 3 },
a2 = [];
( { a: a2[0], b: a2[1], c: a2[2] } = o1 );
console.log( a2 ); // [1,2,3]
複製程式碼
物件巢狀解構
var o1 = { x: { y: { z: 6 } } };

var { x: { y: { z: w } } } = o1;

console.log( w ); // 6
複製程式碼
不只是宣告

在已經宣告的變數中應用解構賦值就是賦值操作,不只是宣告

var bar = {x: 4, y: 5,z: 6}
var x , y, z
( { x, y, z } = bar );
console.log( x, y, z );   // 4 5 6
複製程式碼

如果省略了 var/let/const 宣告符,就必須把 整個賦值表示式用 ( ) 括起來。因為如果不這樣做,語句左側的 {..} 作為語 句中的第一個元素就會被當作是一個塊語句而不是一個物件

賦值表示式 ( x 、 y ,z等 ) 並不必須是變數識別符號。任何合法的賦值表示式都可以。 舉個栗子

var o = {x:88,y:88,z:88};
( { x: o.x, y: o.y, z: o.z } = bar() );
console.log( o.x, o.y, o.z ); // 4 5 6
複製程式碼

可以在解構中使用計算出的屬性表示式 舉個例子( 應用場景 )

var which = "x",
o = {};
 ( { [which]: o[which] } = bar() );
console.log( o.x );
// 遍歷式動態匹配
var keyArr = ['name', 'age', 'score']
var obj = {
   name: 'a',
   age: 18,
   score: 99
 }
var copyObj = {}
keyArr.forEach((v)=>{
 ({[v]: copyObj[v]} = obj)
})
console.log(copyObj)
複製程式碼
注意事項

物件的解構的值包括繼承物件

function Parent(){
   this.child = 'child'
}
Parent.prototype = {
  parent: 'parent'
}

// 在Object.prototype上有hasOwnProperty
var obj = new Parent()
var {child,parent,hasOwnProperty} =  obj 
console.log(child, parent, hasOwnProperty)
// 再次用函式驗證
function abc () {}
var {hasOwnProperty:myHas} = abc
console.log(myHas === Object.prototype.hasOwnProperty) // true
複製程式碼

陣列的解構賦值

賦何值 --> 陣列中提取值,按照對應位置,對變數賦值

以前,為變數賦值,只能都是指定值

var a = 1;
var b = 2;
var c = 3;
複製程式碼

ES6 允許寫成下面這樣。

var [a, b, c] = [1, 2, 3];
複製程式碼

巢狀陣列進行解構

var [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo,bar,baz)  // 1,2,3
複製程式碼

預設賦值

預設引數值

多年以來我們實現這一點的方式是這樣的,

function foo(x,y) {
   x = x || 11;
   y = y || 31;
   console.log( x + y );
}
  foo();                // 42
  foo( 5, 6 );        // 11
  foo( 5 );            // 36
  foo( null, 6 );     // 17  null被強制轉換成0  11+6

  foo( 0, 42 );      // 53 <--哎呀,並非42
複製程式碼

es6 預設引數值

function foo(x = 11, y = 31) {
     console.log( x + y );
}
foo();                             // 42
foo( 5, 6 );                     // 11
foo( 5 );                         // 36
foo( 5, undefined );        // 36 <-- 丟了undefined
foo( 5, null );                 // 5 <-- null被強制轉換為0
foo( undefined, 6 );       // 17 <-- 丟了undefined
foo( null, 6 );                // 6 <-- null被強制轉換為0

foo( 0, 42 );                   // 42
複製程式碼

知識點: 在函式宣告中的 x = 11 更像是 x !== undefined ? x : 11 而不是常見技巧 x || 11 ,所以 在把前 ES6 程式碼轉換為 ES6 預設引數值語法的時候要格外小心。

再來看解構賦值的預設值

// 全為undefined時
var obj = []
var [a = 3, b = 6, c =7] =  obj
console.log(a,b,c)     // 3,6,7
// 驗證
var obj = [null, false,undefined,NaN,0]
var [a = 1,b = 1,c = 1,d = 1,e = 1] = obj
console.log(a,b,c,d,e)   // 只有c為 1
複製程式碼

字串解構

var str = '你好世界'
var[a,b,c,d,length] = str
console.log(a,b,c,d,length)  // 你 好 世 界 4

// 中間實際有一個轉換過程
var strObj = new String('你好世界')
var [aa,bb,cc,dd,length] = strObj
console.log(aa,bb,cc,dd,length)
複製程式碼

數值的解構

var num = 1234
var {toString: s}= num
console.log(s)

// 中間實際有一個轉換過程
var numObj = new Number(1234)
var {toString: s} = numObj
複製程式碼

布林的解構

var bool= false
var {toString: s}= bool
console.log(s)

// 中間實際有一個轉換過程
var boolObj = new Boolean(1234)
var {toString: s} = boolObj
console.log(s)
複製程式碼

第三部分專案中應用

  1. 交換變數的值 在專案中我們可能會要備份一份資料來,處理邏輯 之前
let a  =  '你好',b  = '世界'
console.log(a,b)
a = [a,b];
b = a[0];
a = a[1];
console.log(a,b)
複製程式碼

es6

let a  =  '你好',b  = '世界';
console.log(a,b);
[a,b] = [b,a];
console.log(a,b);
複製程式碼
  1. 需快取重置資料時 (應用場景resetCom.vue)
  2. 提取後臺介面引數 (應用場景apiCom.vue)
  3. 封裝函式需大量形參時(應用場景funcCom.vue)

程式碼地址及附件碼雲百度雲提取碼:0uqu

相關文章