1. 程式人生 > >ES6學習筆記第一天

ES6學習筆記第一天

## 三、const和let

**3.1 const**

const用來定義常量,所謂的常量就是值一旦給定後就不變,一次定義終身不變的量
const a = 10; a = 20;
上面的a就是一個常量,若給a重新賦值,你會發現報錯了 注意:
const通常會定義兩種東西:
l 定義函式
l 定義一些特殊的字串和常數
常量名一般都是全大寫,如果由多個單片語成,用下劃線隔開,暗示這個是常量

**3.2 let**
let用來定義塊級作用域的變數,只要有“{}”包裹,就表示塊級作用域。
*注意:不是JSON,if語句體、函式體、while、for是塊,for迴圈的()也是塊

注意:我們通常會在for使用let,此時迴圈中自動加了閉包*:

var arr = [];
for(let i = 0; i < 10;i++){
arr.push(function(){
console.log(i);
});
}
arr[4](); //4

let和for是絕配,let平時沒啥用。
var宣告的變數,在for迴圈之外可以訪問,導致i變數到最終值的時候,arr[4]()雖然是閉包訪問,但是同一個i,所以i就是一個統一的值。
而let相當於每一次都有不同的i,都是新的i,但是i是可以訪問上一次的自增或自減的值。

**總結:
**l const用來定義常量,通常定義函式和常數
l let用來定義{}塊級的作用域的變數,通常用來定義for迴圈的變數
常量是塊級作用域,很像使用let,語句定義的變數,常量的值不能通過重新賦值來改變,並且不能重新宣告。****

## **四、變數的解構賦值**

**4.1陣列解構**
陣列可以解構,當等號右側是陣列的時候,等於左側可以將變數裝入[]中接收,一一對應接收。

var [a,b,c] = [1,2,3];
console.log(a); //1
console.log(b); //2
console.log(c); //3

上面程式碼表示,可以從陣列中提取值,按照對應位置,給變數賦值。

本質上,這種寫法屬於“模式匹配”,只要等號兩邊的模式相同,左邊的變數就會被賦予對應的值。

如果陣列較為複雜,此時左側結構的那些變數,也要有相同的結構:

var [a,b,[c,d]] = [1,2,[3,4]];
console.log(a); //1
console.log(b); //2
console.log(c); //3
console.log(d); //4

如果結構不同呢?

var [a,b,c] = [1,2,[3,4]];
console.log(a); //1
console.log(b); //2
console.log(c); //[3,4]

另外一種情況是不完全解構,即等號左邊的模式,只匹配一部分的等號右邊的陣列,這種情況解構依然可以成功。

var [a, [b], d] = [1, [2, 3], 4];
console.log(a); // 1
console.log(b); // 2
console.log(d); // 4
如果解構不成功,變數的值等於undefined

**4.2物件解構**
物件的結構和陣列有個不同點,陣列的元素是按順序排列的,陣列的取值由他的位置決定。
而物件的屬性(鍵名)沒有順序,但是變數必須與屬性同名,才能取到正確的值。

var {name,id,sex} = {"id":1001,"name":"張三","sex":"男"};
console.log(id); //1001
console.log(name); //張三
console.log(sex); //男

上面的例子,等號左邊的變數順序與等號右邊3個同名屬性的順序不一致,但是對取值完全沒影響
如果變數沒有對應的同名屬性,導致取不到值,所以是undefined。
如果變數名和屬性名不一致,必須寫成下面這樣:

var {foo: baz} = {foo : 'aaa', bar : 'bbb'}
console.log(baz); //aaa


var {first :f ,last :l} = {first :'hello', last :'world'}
console.log(f); //hello
console.log(l) //world

這實際上說明,物件的解構賦值是上面形式的簡寫
上面程式碼中,foo是匹配模式,baz才是變數,真正被賦值的是變數baz,而不是模式foo。
也就說,物件的解構的內部機制,是先找到同名屬性,然後再賦值給對應的變數,真正被賦值的是後者,而不是前者。

**4.3預設值**
結構賦值允許指定預設值

var [a = 1] = []
var [b = 1] = [88]
console.log(a);//1
console.log(b);//88
var [c = 1] = [undefined]
var [d = 1] = [null]
console.log(c);//1
console.log(d);//null

注意,ES6內部使用嚴格相等運算子(===),判斷一個位置是否有值,所以,只有當一個數組成員嚴格等於undefined,預設值才會生效
如果一個數組值是null,預設值不會生效,因為null不嚴格等於undefined。

**4.4擴充套件運算子(spread operator)**
擴充套件運算子(spread)是三個點(...)。將一個數組轉為用逗號分隔的引數序列,還能強制展開一個物件,通常用於物件的賦值,使用靈活廣泛。

l 第一個作用:稱為“展開運算子”,作用和字母意思用於,就是把東西展開,可以用在陣列和物件上。

var obj1 = {
"a" :100,
"b" :200,
"c" :300,
}
var obj2 = {
...obj1,
"d" :888
}
console.log(obj1)
console.log(obj2)
console.log(obj1 === obj2);


陣列也可以強制展開,通常陣列的賦值,比如有兩個數組合成一個數組:

**4.5剩餘操作符(rest operator)**
l 第二、三個作用:叫“剩餘操作符”是解構的一種,意思是把剩餘的引數放到一個數組中賦值給它。一般針對陣列或物件。

var [a,b,...c] = [1,2,3,4,5,6];
console.log(a);//1
console.log(b);//2
console.log(c);//[3,4,5,6]

注意“...”只能出現最後一個引數,並且通過這個例子發現...能將零散的值收納為陣列。
邏輯上,“...”是一個運算子。“...”能將陣列打散為零散值。

l 補充個知識點,在ES6中當一個物件的key和value一致時,可以省略value。

**l 應用場景2:**
以後的函式大概率都是接收一個JSON當引數,並且用ES6解構語法寫形參變數。
呼叫函式的時候傳的引數,一般是k:v,省略v

var name = "小明";
var height = 170;
var weight = 100;

function mm({height,name,weight}){
console.log("姓名是:" + name)
console.log("身高是:" + height)
console.log("體重是:" + weight)
};

// mm({name:name,"height":height,"weight":weight})
mm({name,height,weight})

紅色部分的語句是在建立JSON,綠色的部分是在進行結構。
呼叫函式時引數順序打亂也不影響結構,因為解構,會自動匹配key。
()
**l 展開運算子和剩餘操作運算子的區別**
關於展開運算子與剩餘操作符的直之間的區別,簡單的說,在某種程度上,剩餘操作符和展開運算子相反,展開運算子會“展開”陣列變成多個元素,剩餘操作符會收集多個元素和“壓縮”成一個單一的元素。

**4.6物件解構的翻譯問題**
注意:babel會將“[]”和“{}”解構變為一個個的var。
但是babel不能翻譯“物件解構”,只能翻譯陣列解構。
原因:object-rest-spread 還處於stage階段(屬於實驗性屬性)。
解決方法:安裝babel外掛transform-rest-spread,放到.babelrc檔案配置上,即可使用。

{
"presets":["es2015","es2016"],
"plugins":["transform-object-rest-spread"]
}
.babelrc的presets是用來定義預設,plugins定義外掛。
安裝依賴:
cnpm install babel-plugin-transform-object-rest-spread

**

## 五、陣列方法

**
ES6中對陣列新增了四大“金剛”函式:forEach()、map()、filter()、reduce(),都是一些語法糖。forEach()是es5語法
**5.1 forEach()遍歷陣列**
forEach()方法用來迴圈遍歷陣列,方法中的function回撥函式接收3個引數
第1個是遍歷的陣列內容(item);第2個是對應的陣列索引(index),第3個是陣列本身(array)。

var arr = ["白板","么雞","紅中","發財","三餅"];
arr.forEach(function(item,index,array){
console.log(item,index,array)
});
注意:forEach()沒有return返回值。

**5.2 map()對映**
map方法的作用不難理解,“對映”也就是原陣列被“對映”成對應的新陣列。

var arr = [10,20,30,40,50,99];
var newArr = arr.map(function(item,index,array){
return item * 2; //返回一個新的結果,給變數接收,原陣列不變
});

map函式的本質是依次遍歷原陣列的每一項,將每一項都執行一遍函式中的語句,返回一個新的陣列。
注意:
l 函式需要有return值,如果沒有,陣列所有項都被對映成undefined。
l map返回的陣列一定和原陣列的長度一樣。
l
在實際使用時,可以利用map()方便獲取物件陣列中的特定屬性值們
**5.3 filter()過濾**
filter為“過濾、篩選”之意,指原陣列中filter某些項後,返回過濾後的新陣列,用法和map相似。
比如想從原陣列中,挑選所有的偶數,返回新的陣列。

var arr = [312,55,77,11,13,15,18,26,30,40,50,99];
var newArr = arr.filter(function(item,index,array){
return item % 2 == 0;
});
console.log(arr)
console.log(newArr)

描述:arr中的每一項會依次的執行函式,filter的callback函式需要返回布林值true或false。true則將值放到新陣列中,false無情地將你拋棄…
l filter和map相同點:都會遍歷陣列的每一項
l filter和map不同點:map返回陣列不會少項,filter可能少項。

**5.4 reduce()迭代**

arr.reduce(callback[,initialValue])
第一個引數的callback回撥函式有四個引數,第二個為設定的初始值(可選)。
callback函式有四個引數:
previous :上一次疊加的結果值或初始值
current : 當前會參與疊加的項
index :當前值的下標
array :原陣列本身


求陣列的最大值【經典面試】:
var arr = [43,5,4,6,4567,78,8,69,568];
// var max = Math.max.apply(null,arr);
// console.log(max)

var max = arr.reduce(function(prev,cur){
console.log(prev) //43、43、43、43、4567、4567、4567...
return prev > cur ? prev : cur;
});
console.log(max); //4567

reduce的機理:從下標1的項開始遍歷,每次return的值將作為遍歷的下一項的prev的值,這一次的遍歷是cur,prev有種累加的感覺。
reduce可以設定初始引數(引數自定義),當reduce有第二個引數時,此時reduce遍歷將從第0項開始遍歷,而不是第1項開始。

**5.5陣列用途-寫純函式**
上面的四大“金剛”map、filter、reduce特別有用,做“函式式”程式設計。
什麼是純函式?
純函式是指不依賴於且不改變它作用域之外的變數狀態的函式。
l 這個函式內部不改變傳入的引數。
l 傳入這個函式一定有引數,一定會返回某一個確定的值。
l 函式中的語句,不能有隨機性,比如Math.random()、new Date(),傳入的引數相同,返回的值必定相同;
l 這個函式裡面不能有任何非同步語句,比如$.get()、fs.readFile()、setInterval()

**l【例子1】請寫一個純函式addItem(),接收arr、n當做引數,能夠將arr的尾部增加n。**

var arr = [99,77,66];
function addItem(arr,n){
return [...arr,n];
}
var arr2 = addItem(arr,88); //返回一個新陣列
console.log(arr); //原陣列不變
console.log(arr2);


**【例子4】請寫一個純函式changeItem,接受arr、n、a當做引數,能夠將arr第下標為n的那項改變值為a。**

var arr = ["白板","么雞","二條","三萬"];
function changeItem(arr,n,a){
return arr.map((item,index)=> index == n ? a : item )
}
var arr2 = changeItem(arr,2,"九條");
console.log(arr);
console.log(arr2);


**l 純函式的條件:**
l 一個函式的返回結果只依賴於它的引數
l 不依賴外部狀態
l 執行過程中沒有副作用

**什麼叫函式執行過程沒有副作用?**
一個函式執行過程中對外部產生了編號,那麼就說這個函式是有副作用的。

l 更改指定id的name屬性

const changeName = function(arr,id,name){
return arr.map(function(item){
if(item.id == id){
return {...item,name}
}
return item;
});
}

 

var jieguo = changeName(arr,2,"小蘭")
console.log(jieguo);

順口溜:刪filter、改map、增map或...

**總結
為什麼要煞費苦心地構建純函式?因為純函式非常“靠譜”,執行一個純函式你不用擔心它會幹什麼壞事,它不會產生不可預料的行為,也不會對外部產生影響。不管何時何地,你給它什麼它就會乖乖地吐出什麼。如果你的應用程式大多數函式都是由純函式組成,那麼你的程式測試、除錯起來會非常方便。
l 使用純函式的好處
最主要的好處是沒有副作用。純函式不會修改作用域之外的狀態,做到這一點,程式碼就變得足夠簡單和清晰:當你呼叫一個純函式,你只要關注它的返回值,而不用擔心因為別處的問題導致錯誤。

純函式是健壯的,改變執行次序不會對系統造成影響,因此純函式的操作可以並行執行。
純函式非常容易進行單元測試,因為不需要考慮上下文環境,只需要考慮輸入和輸出。

函式是接受一些輸入,併產生一些輸出的過程。這些輸入稱為引數,輸出稱為返回值。
純函式的返回值只由它呼叫時的引數決定,它的執行不依賴於系統的狀態(比如:何時、何處呼叫它)。**

&n