1. 程式人生 > >ES6語法(2)—— 物件解構賦值、箭頭函式使用和思考

ES6語法(2)—— 物件解構賦值、箭頭函式使用和思考

    ES6的內容太過豐富,在學習的過程中,我選擇取其精華,跳過非精華,個人覺得變數的解構賦值和箭頭函式都是非常有實際使用價值的內容,就單獨拿出來放一個章節分析和介紹。

    關於變數的解構賦值,其實有很多種解構方式,包括陣列,物件,字串等都可以進行解構賦值,但個人認為物件的結構賦值是最常用,也是最有用的。

    下面來看一個應用場景:現在有一個person物件,然後你通過引用(import/require)等方式得到了這個物件,現在你需要獲取這個人的名字和性別,這個時候你只需要這樣寫即可。

//...引入person物件 person={name:'小明',sex:'男','age':17,'':'',...................}
let {name,sex} = person
name // 小明
sex // 男

    至於person物件裡還包含什麼屬性,那與你無關,你儘管取得你所需要的資料即可。當然在解構的時候,你需要寫對鍵名,你需要知道你所需要的資料,在未知物件中的鍵名是什麼,比如你想取‘性別’,你通過 let {性別} =  person,那性別這個變數賦值為undefined。因為只有'sex',沒有‘性別’。

    來看一下物件解構賦值裡常見的誤區。

let {a:c,b:d} = {a:'aaa',b:'bbb'}
//最終'aaa'賦值給變數c,模式a並未定義
console.log(a,b,c,d) // aaa bbb a,b均為undefined

    上述程式碼a,b均為undefined報錯,c,d有賦值,所以物件的解構賦值的內部機制,是先找到同名屬性,然後再賦給對應的變數。真正被賦值的是後者,而不是前者。

    關於變數解構賦值的巢狀這裡不過多說明,有興趣可以去看阮大神的原著,總結起來有點故意刁難自己的意思。

    來看一個實際應用吧,比如Math物件中的一些方法,你可以通過物件解構將他拎出來單獨使用。

let {sin,cos,log} = Math
console.log(sin(3.14/2),cos,log)

    關於箭頭函式的使用方式,最明顯的就是用=>符號定義函式,請不要手賤在=和>中間打個空格。如:

let add = (a)=>a*a
//等價於
let add = function(a){
  return a*a
}

    這種方式大大簡化了函式的寫法,增強了程式碼的可讀性(說實話,沒覺得可讀性提高多少)

    注意:箭頭函式用雙大括號{}劃分作用域,因此你在return一個物件的時候,千萬記得加(),不然他就會解析物件的雙括號為作用域的雙括號,然後再解析裡面的內容。

let name = ()=>({name:'dkr'})

    關於箭頭函式的好處,最重要的就是ES6中箭頭函式內部的this指標指向就是定義時所在的物件,而不是使用時所在的物件。看下面這個例子,s1和s2會輸出什麼?

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭頭函式
  setInterval(() => this.s1++, 1000);
  // 普通函式
  setInterval(function () {
    this.s2++;
  }, 1000);
}
let timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3000);
setTimeout(() => console.log('s2: ', timer.s2), 3000);

    這裡我故意修改了官網的例子,最終的結果列印,s1為3,s2為0。官網上給出的setTimeout的延遲為3100,個人認為阮大神可能考慮了setInterval執行計算需要時間,為了保證結果正確特意做的修改,關於這個到底是3000,還是3000多放到最後說明。

    首先,this.s1++使用了箭頭函式,此時的this指向生成箭頭函式的環境,this.s1 = 0,並可以累加。

    而普通函式的this,由於setInterval是window物件下面的方法,因此普通函式的this改成了window,因此對timer例項的s2並沒有影響。

    ok,講完了ES6語法問題,下面來探究下我真正感興趣的東西,javaScript的執行機制

    將,上述程式碼進行分析,逐行解析。

    第一步:javaScript中建立了一個Timer函式,他被扔在了一邊,還未執行函式內部程式碼。然後他又發現了一個由let關鍵字定義的timer,他也被暫時扔在一邊。

    第二步:timer是由建構函式Timer生成的一個例項,在生成的過程中,timer繼承了Timer的作用域,也就this,同時,Timer執行了其內部的程式碼,也就是setInterval定時器開始啟動了。

    第三步:setTimeout定時器也啟動了。

    那麼,javaScript作為一個單執行緒應用,是怎麼管理這些程式碼執行的呢?看下面這張圖

    作為一個單執行緒應用,javaScript有一個核心處理器,用於處理所有同步請求,其他非同步請求(如ajax,回撥函式),或者定時器,都會被放到同步請求一邊,等同步操作都執行完了,再來處理這些其他請求,而這些其他請求也是自己排隊,儘管setInterval * 3 === setTimeout,但是處理器可不會同時處理這兩個操作,計算機內部每個時鐘週期只能幹一件事,因此大部分情況下,setTimeout會排在setInterval*3後邊,因為setInterval在timer被例項化後就已經開始計時了,而setTimeout要晚一點被解析。但是,如果setInterval內部的執行時間過長,那麼他會被強制要求排在setTimeout後面,計算機會自動處理,無需你擔心,因此,設定一定的延遲有利於結果的正確輸出。